The goal of this example is to demonstrate basic LIN communication between two devices where one active as Master another as Slave. In this case, the two devices used are LPC55S16 EVK's.
LIN master will send a specific publisher frame and a subscriber frame, the LIN slave will detect the master data and feedback the data accordingly.
This article will mainly focus on the software side, for hardware please refer https://community.nxp.com/t5/LPC-Microcontrollers-Knowledge/LPC54608-LIN-master-basic-usage-sharing/....
LIN master sends the LIN publisher data and the subscriber ID data, the software code is modified from the SDK_2.8.2_LPCXpresso55S16 usart_interrupt_rb_transfer project, the detailed code is as follows:
/* USART callback */
void FLEXCOMM3_IRQHandler()
{
if(DEMO_USART->STAT & USART_STAT_RXBRK_MASK) // detect LIN break
{
Lin_BKflag = 1;
cnt = 0;
state = RECV_DATA;
DisableLinBreak;
}
if((kUSART_RxFifoNotEmptyFlag | kUSART_RxError) & USART_GetStatusFlags(DEMO_USART))
{
USART_ClearStatusFlags(DEMO_USART,kUSART_TxError | kUSART_RxError);
rxbuff[cnt] = USART_ReadByte(DEMO_USART);;
switch(state)
{
case RECV_SYN:
if(0x55 == rxbuff[cnt])
{
state = RECV_PID;
}
else
{
state = IDLE;
DisableLinBreak;
}
break;
case RECV_PID:
if(0xAD == rxbuff[cnt])
{
state = SEND_DATA;
}
else if(0XEC == rxbuff[cnt])
{
state = RECV_DATA;
}
else
{
state = IDLE;
DisableLinBreak;
}
break;
case RECV_DATA:
Sub_rxbuff[recdatacnt++]= rxbuff[cnt];
if(recdatacnt >= 3) // 2 Bytes data + 1 Bytes checksum
{
recdatacnt=0;
state = RECV_SYN;
EnableLinBreak;
}
break;
case SEND_DATA:
recdatacnt++;
if(recdatacnt >= 4) // 2 Bytes data + 1 Bytes checksum
{
recdatacnt=0;
state = RECV_SYN;
EnableLinBreak;
}
break;
default:break;
}
cnt++;
}
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
exception return operation might vector to incorrect interrupt */
#if defined __CORTEX_M && (__CORTEX_M == 4U)
__DSB();
#endif
}
void Lin_Master_Publisher(void)
{
unsigned int i=0;
unsigned char ch =0xa0;//dummy byte
//===============================LIN master send=====================
DEMO_USART->CTL |= USART_CTL_TXBRKEN_MASK;//enable TX break;
while (kUSART_TxFifoNotFullFlag & USART_GetStatusFlags(DEMO_USART))
{
USART_WriteBlocking(DEMO_USART,&ch,1);//dummy data
break; //just send one byte, otherwise, will send 16 bytes
}
DEMO_USART->CTL &= ~(USART_CTL_TXBRKEN_MASK); //disable TX break
// Send the sync byte 0x55.
while (kUSART_TxFifoNotFullFlag & USART_GetStatusFlags(DEMO_USART))
{
USART_WriteByte(DEMO_USART, 0X55);
break; //just send one byte, otherwise, will send 16 bytes
}
//protected ID
while (kUSART_TxFifoNotFullFlag & USART_GetStatusFlags(DEMO_USART))
{
USART_WriteByte(DEMO_USART, 0Xad);
break; //just send one byte, otherwise, will send 16 bytes
}
//Data1
while (kUSART_TxFifoNotFullFlag & USART_GetStatusFlags(DEMO_USART))
{
USART_WriteByte(DEMO_USART, 0X01);
break; //just send one byte, otherwise, will send 16 bytes
}
//Data2
while (kUSART_TxFifoNotFullFlag & USART_GetStatusFlags(DEMO_USART))
{
USART_WriteByte(DEMO_USART, 0X02);
break; //just send one byte, otherwise, will send 16 bytes
}
//Data3
while (kUSART_TxFifoNotFullFlag & USART_GetStatusFlags(DEMO_USART))
{
USART_WriteByte(DEMO_USART, 0X03);
break; //just send one byte, otherwise, will send 16 bytes
}
// checksum byte
while (kUSART_TxFifoNotFullFlag & USART_GetStatusFlags(DEMO_USART))
{
USART_WriteByte(DEMO_USART, 0X4c);//0X4c
break; //just send one byte, otherwise, will send 16 bytes
}
}
void Lin_Master_Subscribe(void)
{
unsigned int i=0;
unsigned char ch=0xf0;//dummy byte
DEMO_USART->CTL |= USART_CTL_TXBRKEN_MASK;//enable TX break;
while (kUSART_TxFifoNotFullFlag & USART_GetStatusFlags(DEMO_USART))
{
USART_WriteBlocking(DEMO_USART,&ch,1);
break; //just send one byte, otherwise, will send 16 bytes
}
DEMO_USART->CTL &= ~(USART_CTL_TXBRKEN_MASK); //disable TX break
// Send the syncy byte 0x55.
while (kUSART_TxFifoNotFullFlag & USART_GetStatusFlags(DEMO_USART))
{
USART_WriteByte(DEMO_USART, 0X55);
break; //just send one byte, otherwise, will send 16 bytes
}
//protected ID
while (kUSART_TxFifoNotFullFlag & USART_GetStatusFlags(DEMO_USART))
{
USART_WriteByte(DEMO_USART, 0X3C);
break; //just send one byte, otherwise, will send 16 bytes
}
state = RECV_DATA;
}
The main task here was to generate and detect the LIN break field.
If one look closely, to generate the LIN break field in publisher and subscriber frame, we first set the Tx break and then send a dummy byte and then disable the Tx break. The function used to send the dummy byte is USART_WriteBlocking whereas USART_WriteByte is used to send data other than dummy byte. This is because if we use USART_WriteByte during dummy byte then it was not a continuous low as in the other case. I still need to find the reason for this, will update here once done.
LIN Slave receives the LIN publisher data and the subscriber ID data from Master and respond back id required, the software code is modified from the SDK_2.8.2_LPCXpresso55S16 usart_interrupt_rb_transfer project, the detailed code is as follows:
void FLEXCOMM3_IRQHandler()
{
if(DEMO_USART->STAT & USART_STAT_RXBRK_MASK) // detect LIN break
{
Lin_BKflag = 1;
cnt = 0;
state = RECV_SYN;
DisableLinBreak;
}
if((kUSART_RxFifoNotEmptyFlag | kUSART_RxError) & USART_GetStatusFlags(DEMO_USART))
{
USART_ClearStatusFlags(DEMO_USART,kUSART_TxError | kUSART_RxError);
rxbuff[cnt] = USART_ReadByte(DEMO_USART);;
switch(state)
{
case RECV_SYN:
if(0x55 == rxbuff[cnt])
{
state = RECV_PID;
}
else
{
state = IDLE;
DisableLinBreak;
}
break;
case RECV_PID:
if(0xAD == rxbuff[cnt])
{
state = RECV_DATA;
}
else if(0X3C == rxbuff[cnt])
{
state = SEND_DATA;
senddata();
}
else
{
state = IDLE;
DisableLinBreak;
}
break;
case RECV_DATA:
recdatacnt++;
if(recdatacnt >= 4) // 3 Bytes data + 1 Bytes checksum
{
recdatacnt=0;
state = RECV_SYN;
EnableLinBreak;
}
break;
default:break;
}
cnt++;
}
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
exception return operation might vector to incorrect interrupt */
#if defined __CORTEX_M && (__CORTEX_M == 4U)
__DSB();
#endif
}
void senddata(void)
{
{
while (kUSART_TxFifoNotFullFlag & USART_GetStatusFlags(DEMO_USART))
{
USART_WriteByte(DEMO_USART, 0X01);
break; //just send one byte, otherwise, will send 16 bytes
}
while (kUSART_TxFifoNotFullFlag & USART_GetStatusFlags(DEMO_USART))
{
USART_WriteByte(DEMO_USART, 0X02);
break; //just send one byte, otherwise, will send 16 bytes
}
while (kUSART_TxFifoNotFullFlag & USART_GetStatusFlags(DEMO_USART))
{
USART_WriteByte(DEMO_USART, 0X10);// 0X10 correct 0Xaa wrong
break; //just send one byte, otherwise, will send 16 bytes
}
recdatacnt=0;
state = RECV_SYN;
EnableLinBreak;
}
}
Attaching herewith the codes of the Master and Slave.
I hope it helps!!