S32K_LIN_Master&Slave_driver(寄存器配置no SDK)
S32K14X LIN BUS 主从驱动配置(纯C no SDK)
一、工作原理
1、LIN BUS通信原理简介
2、LPUART收发原理
3、基于LPUART硬件电路(TJA1021收发器)
二、代码编写
/*
* ===================================================
* Function : LPUART0 LIN init(Master & Salve)
* 1. Clock Src= 1 (SOSCDIV2_CLK),set baud rate = 9600
* 2. 8 bit format
* 3. 1 stop bit
* 4. LIN Break Detect Interrupt
* 5. Idle Line Interrupt
* 6. receives interrupt
* Coder : djf
* Date/Time : 2020/07/25
* ===================================================
*/
void LPUART0_LIN_init(void)
{
PCC->PCCn[PCC_LPUART0_INDEX] &= ~PCC_PCCn_CGC_MASK; /* Ensure clk disabled for config */
PCC->PCCn[PCC_LPUART0_INDEX] |= PCC_PCCn_PCS(1) /* Clock Src= 1 (SOSCDIV2_CLK) */
| PCC_PCCn_CGC_MASK; /* Enable clock for LPUART1 regs */
LPUART0->GLOBAL |= LPUART_GLOBAL_RST_MASK; /* RST=1: Module is reset */
LPUART0->GLOBAL &= ~LPUART_GLOBAL_RST_MASK; /* RST=0: Module is not reset */
LPUART0->BAUD &= ~LPUART_BAUD_SBNS_MASK; /* SBNS=0: One stop bit */
LPUART0->BAUD &= ~LPUART_BAUD_SBR_MASK; /* Clear SBR field */
LPUART0->BAUD = LPUART_BAUD_SBR(0x34)| /* Initialize for 9600 baud, 1 stop. SBR=52 (0x34): baud divisor = 8M/9600/16 = ~52 */
LPUART_BAUD_OSR(15) | /* OSR=15: Over sampling ratio = 15+1=16 */
LPUART_BAUD_LBKDIE_MASK; // LIN Break Detect Interrupt Enable, Hardware interrupt requested when STAT[LBKDIF] flag is 1.
/* SBNS=0: One stop bit */
/* BOTHEDGE=0: receiver samples only on rising edge */
/* M10=0: Rx and Tx use 7 to 9 bit data characters */
/* RESYNCDIS=0: Resync during rec'd data word supported */
/* LBKDIE, RXEDGIE=0: interrupts disable */
/* TDMAE, RDMAE, TDMAE=0: DMA requests disabled */
/* MAEN1, MAEN2, MATCFG=0: Match disabled */
LPUART0->STAT &= ~LPUART_STAT_MSBF_MASK; /* MSBF=0: LSB (bit0) is the first bit */
LPUART0->STAT |= LPUART_STAT_BRK13_MASK | /* BRK13=1: Break character is transmitted with length of 13 bit times */
LPUART_STAT_LBKDE_MASK; /* LBKDE=1: LIN break detect is enabled */
LPUART0->CTRL = LPUART_CTRL_ORIE_MASK | // Overrun Interrupt Enable
LPUART_CTRL_PEIE_MASK | // Framing Error Interrupt Enable
LPUART_CTRL_RIE_MASK | // Receiver Interrupt Enable
LPUART_CTRL_IDLECFG(7) | // 128 idle characters
LPUART_CTRL_ILT_MASK | /* ILT=1: Idle char bit count starts after start bit */
LPUART_CTRL_ILIE_MASK | // Idle Line Interrupt Enable
LPUART_CTRL_RE_MASK | /* RE=1: Receiver enabled */
LPUART_CTRL_TE_MASK; /* TE=1: Transmitter enabled, Enable transmitter & receiver, no parity, 8 bit char: */
// LPUART_CTRL_LOOPS_MASK;
// LPUART_CTRL_RSRC_MASK;
}
void LIN_SendHeader(uint8_t PID)
{
while((LPUART0->STAT & LPUART_STAT_TDRE_MASK) == 0); /* Wait until Transmit data buffer become empty */
LPUART0->CTRL |= LPUART_CTRL_SBK_MASK; /* SBK=1: Queue break character(s) to be sent */
LPUART0->CTRL &= ~LPUART_CTRL_SBK_MASK; /* SBK=0: Normal transmitter operation */
while((LPUART0->STAT & LPUART_STAT_TDRE_MASK) == 0); /* Wait until Transmit data buffer become empty */
LPUART0->DATA = 0x55; /* Transmit Sync Byte */
while((LPUART0->STAT & LPUART_STAT_TDRE_MASK) == 0); /* Wait until Transmit data buffer become empty */
LPUART0->DATA = PID; /* transmit PID */
while((LPUART0->STAT & LPUART_STAT_TC_MASK) == 0); /* transmission activity complete */
}
void LIN_SendResponse(uint8_t *SendArray)
{
uint8_t i = 0;
for(i=0; i<9; i++)
{
while((LPUART0->STAT & LPUART_STAT_TDRE_MASK) == 0);
LPUART0->DATA = SendArray[i];
}
while((LPUART0->STAT & LPUART_STAT_TC_MASK) == 0); /* transmission activity complete*/
}
/**********************************************************/
/* Name: void LIN_Slave_RxTxFrame(void) */
/* Function: Slave receives response and sends response, */
/* Slave receives Header */
/* Modify Date: 2020/07/25 */
/* Parameter: */
/* */
/* */
/* Result: */
/* Coder: djf */
/**********************************************************/
void LIN_RxTxFrame(void)
{
uint8_t i = 0;
uint8_t RecOkflag = 0;
uint8_t LinRecbuffer = 0;
static uint8_t BreakOkflag = 0;
static uint8_t recHeaderNu = 0;
static uint8_t recResponseNu = 0;
// static uint8_t sendResponseNu = 0;
static uint8_t recResponseFlag = 0; /* Receive response flag */
static uint8_t sendResponseFlag = 0;
static uint8_t RecResponseFinish = 0; /* Receive the response completion flag */
if((LPUART0->STAT & LPUART_STAT_LBKDIF_MASK) == LPUART_STAT_LBKDIF_MASK) /* LIN break character detected? */
{
LPUART0->STAT |= LPUART_STAT_LBKDIF_MASK; /* Write 1 to clear flag */
LPUART0->STAT &= ~LPUART_STAT_LBKDE_MASK; /* LBKDE=0: LIN break detect is disabled */
BreakOkflag = 1;
}
else
{
}
if((LPUART0->STAT & LPUART_STAT_IDLE_MASK) == LPUART_STAT_IDLE_MASK) //Idle line was detected
{
LPUART0->STAT |= LPUART_STAT_IDLE_MASK; //write logic 1 to the Idle flag
RecOkflag = 1;
}
else
{
}
if((LPUART0->STAT & LPUART_STAT_FE_MASK) == LPUART_STAT_FE_MASK) //Framing error
{
LPUART0->STAT |= LPUART_STAT_FE_MASK; //write logic 1 to the FE flag
RecOkflag = 1;
}
else
{
}
if((LPUART0->STAT & LPUART_STAT_OR_MASK) == LPUART_STAT_OR_MASK) //Receive overrun
{
LPUART0->STAT |= LPUART_STAT_OR_MASK; //write logic 1 to the OR flag
RecOkflag = 1;
}
else
{
}
if(((LPUART0->STAT & LPUART_STAT_RDRF_MASK) == LPUART_STAT_RDRF_MASK))
{
LinRecbuffer = (uint8_t)LPUART0->DATA;
if(!RecOkflag) // No overflow, no frame error start receiving
{
if(1==BreakOkflag)
{
LinRecHeader[recHeaderNu] = LinRecbuffer; /* receive 0x55、PID */
recHeaderNu++;
if(0x55!=LinRecHeader[0]) /* The clear count flag is not equal to 0x55 when receiving the synchronization segment */
{
recHeaderNu = 0;
BreakOkflag = 0;
}
else
{
if(2==recHeaderNu)
{
switch(LinRecHeader[1])
{
case PIDrxResp: // Receive the response header
recResponseFlag = 1;
sendResponseFlag = 0;
break;
case PIDtxResp: // Send the response header
recResponseFlag = 0;
sendResponseFlag = 1;
LPUART0->STAT |= LPUART_STAT_LBKDE_MASK;
break;
case HCMPID:
recResponseFlag = 1;
sendResponseFlag = 0;
break;
default:
LPUART0->STAT |= LPUART_STAT_LBKDE_MASK;
break;
}
recHeaderNu = 0;
BreakOkflag = 0; // Headers have been received. Clear the break flag and wait for the next Header to start
}
else
{
}
}
}
else
{
if(1==recResponseFlag)
{
LinRecResponseArray[recResponseNu] = LinRecbuffer; // Receive the response data segment
recResponseNu++;
if(8<recResponseNu)
{
recResponseNu = 0;
recResponseFlag = 0;
RecResponseFinish = 1;
LPUART0->STAT |= LPUART_STAT_LBKDE_MASK; // LIN break detect is enable
}
else
{
}
}
else
{
}
if(1==RecResponseFinish) /* Response receiving completion flag */
{
RecResponseFinish = 0;
CheckSum = LINCalcChecksum(LinRecResponseArray, LinRecHeader[1]) + LinRecResponseArray[8]; /* Calculate whether the sum of the validations equals 0xFF */
if(0xFF==CheckSum)
{
for(i=0; i<8; i++)
{
LinRec02Data[i] = LinRecResponseArray[i];
}
}
else
{
}
}
else
{
}
}
}
else
{
}
}
else
{
}
if(1==sendResponseFlag) //Send response
{
LinSendResponseArray[8] = 0xFF - LINCalcChecksum(LinSendResponseArray, PIDtxResp);
LIN_SendResponse(LinSendResponseArray);
sendResponseFlag = 0;
}
else
{
}
if(1==RecOkflag)
{
RecOkflag = 0;
recResponseFlag = 0;
recHeaderNu = 0;
recResponseNu = 0;
BreakOkflag = 0;
LPUART0->STAT |= LPUART_STAT_LBKDE_MASK;
}
else
{
}
}
/*******************************************************/
/* Name: void LinMasterSchedule(void) */
/* Function: LinMasterSchedule */
/* Modify Date: 2020/07/25 */
/* Parameter: */
/* */
/* */
/* Result: */
/* Coder: djf */
/*******************************************************/
void LinSchedule(void)
{
static uint8_t LinScheduleTimer = 0;
if(2>LinScheduleTimer)
{
LinScheduleTimer++;
}
else
{
LinScheduleTimer = 0;
LinSendResponseArray[1]++;
LinSendResponseArray[2] = 0xFF - LinSendResponseArray[1];
}
switch(LinScheduleTimer)
{
case (HCM):
{
if(200>LinSend16Data[1])
{
LinSend16Data[1]++;
}
else
{
LinSend16Data[1] = 0;
}
LinSend16Data[2] = 0xFF-LinSend16Data[1];
LPUART0->CTRL &= ~LPUART_CTRL_RE_MASK; //Block the receive and interrupt,Reduced interrupt scheduling time
LPUART0->CTRL &= ~LPUART_CTRL_RIE_MASK;
LinSend16Data[8] = 0xFF - LINCalcChecksum(LinSend16Data, HCMPID); //CheckSum
LIN_SendHeader(HCMPID);
LIN_SendResponse(LinSend16Data);
}
break;
case (FCP): //receiving response
{
LPUART0->CTRL |= LPUART_CTRL_RIE_MASK;
LPUART0->CTRL |= LPUART_CTRL_RE_MASK;
LIN_SendHeader(PIDrxResp);
}
break;
case (PM): //send response
{
LPUART0->CTRL |= LPUART_CTRL_RIE_MASK;
LPUART0->CTRL |= LPUART_CTRL_RE_MASK;
LIN_SendHeader(PIDtxResp);
}
break;
default:
break;
}
}
#define HCMPID 0xD6 //ID 0x16
#define PIDrxResp 0x42 //ID 0x02
#define PIDtxResp 0xA3 //ID 0x23
#define HCM 0
#define FCP 1 //0+3
#define PM 2 //0+3+2
void LPUART0_NVIC_init_IRQs(void)
{
S32_NVIC->ICPR[1] = (uint32_t)(1 << (LPUART0_RxTx_IRQn % 32));
S32_NVIC->ISER[(uint32_t)(LPUART0_RxTx_IRQn) >> 5U] = (uint32_t)(1UL << ((uint32_t)(LPUART0_RxTx_IRQn) & (uint32_t)0x1FU));
S32_NVIC->IP[LPUART0_RxTx_IRQn] = 0xC;
}
void LPUART0_RxTx_IRQHandler(void)
{
LIN_RxTxFrame();
}
三、总结
以上代码是基于LPUART编写的LIN 主节点、从节点驱动程序,从节点接收报头和响应是放在LPUART接收发送中断函数里面,主节点调度是放在主循环里面轮询,调度周期为100ms。上面例程包含了主节点和从节点收发驱动,初始化配置里面配置了break检测中断,Idle检测中断,error帧检测中断,overrun中断。LIN的初始化配置相比CAN初始化简单不少,重点在于从节点接收和发送驱动程序编写,大伙在调试时这方面重点看下。