s12p64 number of data received by LIN

cancel
Showing results for 
Search instead for 
Did you mean: 

s12p64 number of data received by LIN

231 Views
Contributor II

Hi,

I'm now working on the LIN communication with MC9S12P64 and my module can receive and send LIN message perfectly. But the only problem is that in the receiving part, I want to get exactly the number of data that I receive by LIN.

I'm new to NXP microcontroller and also to LIN communication. I didn't know by which function I can find the DLC number. So can anyone tell me which function or register I can get the number of data received?

Here is a part of my code of LIN recerving:

/////////////////////////////////////////////////////////////////////////////////////////
// LINGetChar
// --------------------------------------------------------------------------------------
// SCI data receive routine
/////////////////////////////////////////////////////////////////////////////////////////
Bool LINGetChar(unsigned char lin_num)
{
unsigned int somme=0;
unsigned char y;
unsigned volatile char *lin_pt, ch;
lin_pt = lin_periph[lin_num];

// State of the LIN receive channel
switch(rx[lin_num].state++)
{
case IDLE:
//Clear RDRF or OR SCI Flag
if(!(lin_pt[SCI0SR1]&(SCISR1_RDRF_MASK|SCISR1_FE_MASK)))
return(FALSE);
if(lin_pt[SCI0DRL] != 0x00)
return(FALSE);
break;
case _BREAK:
//Clear RDRF Flag
if(!(lin_pt[SCI0SR1]&SCISR1_RDRF_MASK))
return(FALSE);
if(lin_pt[SCI0DRL] != 0x55)
return(FALSE);
break;
case SYNCH:
//Clear RDRF Flag
if(!(lin_pt[SCI0SR1]&SCISR1_RDRF_MASK))
return(FALSE);
ch = lin_pt[SCI0DRL];
rx[lin_num].protected_id = ch;
break;

case PROTECTED_IDENTIFIER:
case DATA_0:
case DATA_1:
case DATA_2:
case DATA_3:
case DATA_4:
case DATA_5:
case DATA_6:
case DATA_7:
//Clear RDRF Flag
if(!(lin_pt[SCI0SR1]&SCISR1_RDRF_MASK))
return(FALSE);
ch = lin_pt[SCI0DRL];
if (ch==0){


if((rx[lin_num].data[0]== 0) && (rx[lin_num].data[1]== 0) && (rx[lin_num].data[2]== 0) && (rx[lin_num].data[3]== 0) && (rx[lin_num].data[4]== 0) && (rx[lin_num].data[5]== 0) && (rx[lin_num].data[6]== 0) && (rx[lin_num].data[7]== 0)){

testid2=7;

}

}

for(y = 0; y <(rx[lin_num].state-DATA_0); y++)
{
somme += rx[lin_num].data[y];
if(somme&0xFF00)
{
somme = (somme&0x00FF) + 1;
}
}
somme += rx[lin_num].protected_id;
if(somme&0xFF00)
{
somme = (somme&0x00FF) + 1;
}
somme ^= 0x00FF;

if (ch == somme)
{
nombre_octets_recuperes = (rx[lin_num].state-DATA_0);
rx[lin_num].check = ch;
rx[lin_num].state = CHECKSUM;
}

else
{
rx[lin_num].data[rx[lin_num].state-DATA_0] = ch;
}
break;

case CHECKSUM:

return(FALSE);
}
return(TRUE);

}

/////////////////////////////////////////////////////////////////////////////////////////
// LINGetMsg
// --------------------------------------------------------------------------------------
// LIN Message Receive Routine
/////////////////////////////////////////////////////////////////////////////////////////
Bool LINGetMsg(unsigned char nombre_octets_recu, unsigned char lin_num, Bool get_data, struct message *msg,unsigned char version_lin)
{

unsigned char i;

if(rx[lin_num].state < PROTECTED_IDENTIFIER)
return(FALSE);
msg->identifier = (rx[lin_num].protected_id&0x3f);
if(get_data)
{
if(rx[lin_num].state == CHECKSUM)
{
nombre_octets_recuperes = (rx[lin_num].state-DATA_0);

for(i = 0; i < sizeof(rx[lin_num].data); i++)
msg->data_field[i] = rx[lin_num].data[i];
for(i = sizeof(rx[lin_num].data); i < 8; i++)
msg->data_field[i] = 0;
rx[lin_num].state = IDLE;

}
} else{

for(i = 0; i < 8; i++)
msg->data_field[i] = 0;

}

return TRUE;
}

Tags (1)
5 Replies

17 Views
NXP Employee
NXP Employee

Hi Shiren,

The LIN data bytes field contains from one to eight bytes of payload data bytes.

The number of bytes is not exactly specified by LIN specification. This must be specified by user LIN bus specification (the same settings for LIN master and LIN slaves).

It seems that your application calculates CRC checksum and compare it with received data (if (ch == somme)). If values are equal, the lin state is configured as CHECKSUM – the last from the LIN states.

Since switch code contains “rx[lin_num].state++”, the state will be incremented after execution. So, the next message will be already received when rx.state is IDLE (start of new frame).

The number of received data bytes is here calculated as nombre_octets_recuperes = (rx[lin_num].state-DATA_0);

 

This solution is interesting however it does not expect situation:

  1. when any bits will be damaged on the bus – the wrong checksum.
  2. when some of the useful data byte has unintentionally the same value as checksum from already received data bytes.

 

The basic LIN example code, similar to your (based on SofTec example code), may be found at:
https://community.nxp.com/docs/DOC-93792

The official LIN stack with LIN 2.0/2.1/2.2A driver:

http://www.nxp.com/assets/downloads/data/en/device-drivers/FSL_LIN_2.X_STACK.zip

I hope it helps you.

Have a great day,
Radek

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

17 Views
Contributor II

Hi Radek,

Thank you for your quick response. The two problems that you mentioned of my solution are excactly what I'm worried about. So I wonder if it exists a way that I can know if the DLC of LIN frame received is ZERO or not. 

As the microcontroller performes as a slave node, it should response the master when it receives a frame DLC 0 from the master. Now I'm looking at the SCI registers and hoping to find a register that can detect the end of transmission or the IDLE. 

I read the datasheet and I think maybe the TC flag in SCISR1 can solve this problem. Here is the description of this register:

TC
Transmit Complete Flag — TC is set low when there is a transmission in progress or when a preamble or break character is loaded. TC is set high when the TDRE flag is set and no data, preamble, or break character is being transmitted.When TC is set, the TXD pin becomes idle (logic 1). Clear TC by reading SCI status register 1 (SCISR1) with TC set and then writing to SCI data register low (SCIDRL). TC is cleared automatically when data, preamble, or break is queued and ready to be sent. TC is cleared in the event of a simultaneous set and clear of the TC flag (transmission not complete). 0 Transmission in progress 1 No transmission in progress

I'm not sure this will be a good solution or not. Please tell me if it is possible if you know well how this register function.

0 Kudos

17 Views
NXP Employee
NXP Employee

Hi Shiren,

In fact, the SCI is very simple module without any FIFO or DLC.

It simply calls an interrupt when a byte is received.

The composing of complete received LIN message is fully managed by software – in your case by simple state machine with IDLE..CHECKSUM states.

 

The slave must know how many bytes refers to the received rx[lin_num].protected_id.

 

So, the rx[lin_num].protected_id value will tell you type of LIN message (whether Master send or request data, how many bytes Slave should receive/send).

 

Note: The most confusing point of this software is the state machine shift. The break character is received in the case IDLE, synchronization is tested in case _BREAK, protected_ID is received in case SYNCH…

The state is incremented directly after any of the cases execution, therefore it will fit from external point of view (when we receive protected_ID and LINGetChar() is executed, the rx[lin_num].state will be PROTECTED_IDENTIFIER).

 

 

The TC flag will probably not help you. It is just flag which signalize when byte transmit finish.

The TC flag is like the TDRE flag with small difference. The TDRE is set again when output buffer is ready for new data. TC is set again when complete byte is sent. In reality, there is just half SCI bit shift (TDRE first, TC later).

 

I hope it helps you.

Have a great day,
Radek

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

17 Views
Contributor II

Hi Radek,

As you said SCI simply calls an interrupt when a byte is received. But I think a timeout function for the interrupt  may solve this problem: Which means every time the slave receive a byte, it will turn on a timeout flag after the interrupt. If the timeout is reached but still receive nothing, we can suppose that the frame is end.

So by this way the slave don't have to know the data length before and it will calculate it by itself. But for me, I don't really know how to implement a timeout in the SCI. It should be done by a timer or there is a way supported by SCI that I can generate it? Please tell me the best way to generate a timeout in the SCI communication and is there any timeout example if you could?

Best regards,

Shiren

0 Kudos

17 Views
NXP Employee
NXP Employee

Hi Shiren,

Interesting idea. But, it may theoretically work only for really simply one direction communication without any errors on bus.

The slave should check PID information for check:

1. whether Master send data or request data

2. whether this LIN frame is even targeted to him or not

3. which data Master sends/request

 

I am afraid that building reliable LIN slave driver without knowledge of LIN bus configuration is simply not possible.

Your idea may be theoretically used for building LIN sniffer (just logging communication on LIN bus).

 

About timeout)

The simplest method is using any timer channel in output compare mode. Please look at G240-TIM_50us_interval-CW51 example code at:

https://community.nxp.com/docs/DOC-93792

Note: if you want disconnect timer channel from port T pin, please set appropriate OCPDx bit.

I hope it helps you.

Have a great day,
Radek

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------