大家好,
我在长时间操作过程中遇到了间歇性 LIN 通信问题,希望您能提供专业意见。该系统配置为恩智浦S32K3xx(EB Tresos 28.2,SW32K3_STD_4.4_2.0.2RD2211)作为 LIN 主机,每 10 毫秒向电机控制板从属设备发送 PID 0x11(从机响应)、0x14(从机响应)和 0x10(主机请求)。
初始通信在前 2 分钟内正常运行,但大约 10 分钟后,会出现间歇性超时错误(" LIN_ID/帧错误 "),并伴有帧传输不完整(仅在示波器上观察到中断场和同步字节,没有 PID/数据)。
调试显示,LPUART_LIN_IP_FrameirqHandler 中断在故障期间停止触发信号,导致全局状态结构 LPUART_LIN_IP_apxStateStructureArray 在 LIN_TX_BUSY 和 LINOPTIONAL 之间振荡,这表明潜在的 TX 状态机锁定。
值得注意的是,该问题只有在长时间运行后才会出现,这表明可能存在温度敏感性、资源冲突或外设配置漂移等问题。这可能是 IRQ 标志配置错误(如意外禁用 TX 完整 IRQ)、时钟不稳定或已知芯片错误造成的吗?有关 LPUART 状态寄存器 (LPUART_STAT)、IRQ 启用位或时钟完整性检查的诊断指导非常宝贵。请告知进一步的步骤或分析所需的数据。
Std_ReturnType LinMstr_DataChk(uint8 current_frame_index)
{
Std_ReturnType ret_val = E_NOT_OK;
static uint8 linSdu[8] = {0};
static uint8 *linSduPtr = linSdu;
Lin_PduType *current_frame = &Lin_Schedule_Frames[current_frame_index];
lin_data.rx_status = Lin_GetStatus(LIN_CHANNEL_0, &linSduPtr);
do
{
if (LIN_OPERATIONAL == lin_data.rx_status)
{
Lin_SendFrame(LIN_CHANNEL_0, current_frame);
lin_state = LIN_STATE_TX_READY;
break;
}
else
{
/* When send a wakeup signal to LIN BUS, the init state switch to LIN_OPERATIONAL */
}
if (current_frame->Drc == LIN_FRAMERESPONSE_TX)
{
/**
* State Machine Transitions:
* 1. On entering `LIN_STATE_TX_READY`, the Master initiates frame transmission.
* 2. If a Slave response is validated (`LIN_RX_OK`), transition to `LIN_STATE_RX_COMPLETED`.
* 3. Automatically advance to the next frame in the schedule table.
*/
switch (lin_state)
{
case LIN_STATE_TX_READY:
{
if (LIN_TX_OK == lin_data.rx_status)
{
MotMgr_SetMasterE2ECounter();
lin_state = LIN_STATE_TX_COMPLETED;
return E_OK;
}
else
{
lin_state = LIN_STATE_TIMEOUT_ERROR;
}
break;
}
case LIN_STATE_RX_COMPLETED:
{
/* After send the last frame sucessfully, the next frame shall be send immediately */
Lin_SendFrame(LIN_CHANNEL_0, current_frame);
lin_state = LIN_STATE_TX_READY;
break;
}
/* This status depends on the order of the schedule. Now, it won't enter this branch */
case LIN_STATE_TX_COMPLETED:
{
/* Only Using in the last frame DRC is TX */
Lin_SendFrame(LIN_CHANNEL_0, current_frame);
lin_state = LIN_STATE_TX_READY;
break;
}
case LIN_STATE_TIMEOUT_ERROR:
{
Lin_SendFrame(LIN_CHANNEL_0, current_frame);
break;
}
default:
{
/* If LIN_FRAME_ERROR, the lin_state is LIN_IDLE, enter this branch to send Frame again.*/
Lin_SendFrame(LIN_CHANNEL_0, current_frame);
lin_state = LIN_STATE_TX_READY;
break;
}
}
}
else if (current_frame->Drc == LIN_FRAMERESPONSE_RX)
{
switch (lin_state)
{
case LIN_STATE_TX_COMPLETED:
{
/**
* [Action] Send slave frame header and transition to waiting state(Waiting response from Slave).
* - Transmits the header of the RX frame to initiate Slave response.
* - State updated to LIN_STATE_RX_WAITING_RESP to monitor response.
*/
Lin_SendFrame(LIN_CHANNEL_0, current_frame);
lin_state = LIN_STATE_RX_WAITING_RESP;
break;
}
case LIN_STATE_RX_WAITING_RESP:
{
/**
* [Polling] Check Slave response status.
* - If LIN_RX_OK: Valid response received, transition to completed state.
* - Else: Handle timeout or errors (BUSY/NO_RESPONSE).
*/
if (LIN_RX_OK == lin_data.rx_status)
{
/* Reveive Data from Buffer */
if (current_frame->Pid == 0x14U)
{
linmstr_debounce.timeout_cnt_14 = LINMSTR_TIME_BASE;
if (linmstr_rte_out.tmout_flag_14 == TRUE)
{
linmstr_debounce.recovery_cnt_14 += LINMSTR_TIME_BASE;
if (linmstr_debounce.recovery_cnt_14 >= LINMSTR_RECOVERY_DURATION)
{
linmstr_rte_out.tmout_flag_14 = FALSE;
}
}
for (uint8 index = 0U; index < 8U; index++)
{
lin_data.response_buffer[LINMSTR_PID_14][index] = linSduPtr[index];
}
}
/* Put the signals of the same message into the same buffer */
else if (current_frame->Pid == 0x11U)
{
if (linmstr_rte_out.tmout_flag_11 == TRUE)
{
linmstr_debounce.recovery_cnt_11 += LINMSTR_TIME_BASE;
if (linmstr_debounce.recovery_cnt_11 >= LINMSTR_RECOVERY_DURATION)
{
linmstr_rte_out.tmout_flag_11 = FALSE;
}
}
linmstr_debounce.timeout_cnt_11 = LINMSTR_TIME_BASE;
MotMgr_SetSlaveE2ECounter();
for (uint8 index = 0U; index < 8U; index++)
{
lin_data.response_buffer[LINMSTR_PID_11][index] = linSduPtr[index];
}
}
else
{
/* fall-through */
}
/* Reveive Data from Buffer */
lin_state = LIN_STATE_RX_COMPLETED;
ret_val = E_OK;
}
else
{
/**
* [Error Handling] Possible states:
* - LIN_TX_BUSY: Ongoing transmission blocking new operations
* - LIN_RX_NO_RESPONSE: Slave did not respond within timeout
* - LIN_RX_BUSY: Receiving data in progress.
* - In this state, send a frame to polling the status of Slave.
*/
/* The Logic implement in LinIf.c */
Lin_SendFrame(LIN_CHANNEL_0, current_frame);
lin_state = LIN_STATE_TIMEOUT_ERROR;
}
/* If enter DIAG schedule table, the state may be stay the LIN_STATE_RX_WAITING_RESP, so we shall consider the condition that
the last state is Rx and Lin state is LIN_STATE_RX_WAITING_RESP, to avoid break continuous sending of schedule table */
break;
}
case LIN_STATE_RX_COMPLETED:
{
/**
* [Re-Initiate] Start next RX frame transaction.
* - Previous state validation: Requires LIN_RX_OK as precondition.
* - Sends header and transitions to LIN_STATE_RX_WAITING_RESP.
* - Timeout period defined by LIN specification or application config.
*/
Lin_SendFrame(LIN_CHANNEL_0, current_frame);
lin_state = LIN_STATE_RX_WAITING_RESP;
break;
}
case LIN_STATE_TIMEOUT_ERROR:
{
if (LIN_RX_OK == lin_data.rx_status)
{
lin_state = LIN_STATE_RX_COMPLETED;
}
else
{
/* Detect the Time out error */
if (0x11U == current_frame->Pid)
{
linmstr_debounce.recovery_cnt_11 = LINMSTR_TIME_BASE;
if (linmstr_rte_out.tmout_flag_11 == FALSE)
{
linmstr_debounce.timeout_cnt_11 += LINMSTR_TIME_BASE;
if (linmstr_debounce.timeout_cnt_11 >= LINMSTR_DURATION_11)
{
linmstr_rte_out.tmout_flag_11 = TRUE;
}
}
}
if (0x14U == current_frame->Pid)
{
linmstr_debounce.recovery_cnt_14 = LINMSTR_TIME_BASE;
if (linmstr_rte_out.tmout_flag_14 == FALSE)
{
linmstr_debounce.timeout_cnt_14 += LINMSTR_TIME_BASE;
if (linmstr_debounce.timeout_cnt_14 >= LINMSTR_DURATION_14)
{
linmstr_rte_out.tmout_flag_14 = TRUE;
}
}
}
Lin_SendFrame(LIN_CHANNEL_0, current_frame);
}
break;
}
default:
Lin_SendFrame(LIN_CHANNEL_0, current_frame);
lin_state = LIN_STATE_TIMEOUT_ERROR;
break;
}
}
} while (0U);
return ret_val;
}谨致问候,
Dongxun
你好@dongxun、
谢谢你的详细分析。
根据观察到的行为,我不认为这是软件驱动程序错误或 UART 模块硬件故障造成的。相反,它符合典型的嵌入式系统在中断严重情况下的行为。
根本原因似乎是 ISR 抢占,即 LIN RX/TX 中断因优先级更高的中断而延迟,导致缓冲区超限(STAT 寄存器中的 OR 位被设置)。
通过提高 LPUARTLIN-RXTx_IRQ 的优先级,有效地解决了这一问题,从而防止了进一步的抢占,恢复了稳定的通信。
这种缓解措施很好地说明了中断优先级如何影响实时通信可靠性。
顺祝商祺!
丹尼尔
嗨,丹
感谢您提供有关 LPUART 中断优先级和调试方法的详细建议。 展望未来,我们将积极监测 后续RTD版本中的 修复概述 ,以配合正在进行的 优化。
你好@dongxun、
您目前使用的是过时版本的 RTD。请参阅每个版本的发行说明,其中包括已知问题和变更的详细列表。
考虑以下内容:
danielmartynek_0-1753689768578.png
此致,
丹尼尔
亲爱的团队
我写这封信是为了报告在数据传输过程中发现的 LIN 通信故障反复出现的根本原因和解决方法。经过深入调查,发现问题出在LPUART 外围设备的状态寄存器 (STAT) 上。具体来说,在协议标识符 (PID) 传输失败的情况下,超限错误 (OR) 位一直被设置。该标志表示新接收的数据在中断服务例程 (ISR) 处理前一个数据之前到达,导致数据丢失和通信停止。
为了解决这个问题:
虽然目前的解决方案很有效,但我欢迎大家提出进一步优化的建议,例如:
请就如何改进这种方法谈谈您的看法。
谨致问候,
dongxun、
你好,如图所示,我想我也遇到了这个问题。请告诉我您是如何解决这个问题的?QQ截图20260513203500.png
你好,我在使用 MCU 作为从属设备时遇到了一个 LIN 通信问题。现象如下:程序烧录后,LIN 通信正常。我使用 MCU 作为从属设备来响应来自主机的帧头。但在运行过程中,运行一段时间后,会出现无响应的情况。观察到的现象是,主机不断发送无响应的帧头。看到这个帖子后,我尝试修改 LIN 的中断优先级,但现象依然存在。我通过示波器观察到的现象是,当帧头无响应时,帧头中的同步间隔段、同步段和 PID 都存在,但响应数据部分却不存在。您能告诉我应该从哪里查找原因吗?期待您的回复。谢谢。
嗨,Aoyng、
我注意到,只有在运行一段时间后才会出现无响应的情况。这表明,当 MCU 充当从机时,LIN 状态机最初运行正常。您观察到 MCU 停止响应时内部状态机卡住的具体位置了吗?
此外,您是否查阅了参考手册并检查了与从机相关的错误寄存器,以确定是否触发了特定错误?对于 S32K312 MCU,Lpuart_Lin_Ip_StatusFlagType 结构包含各种故障条件的描述。我个人曾遇到过这样一个问题(将 MCU 用作主设备时),LPUART_LIN_IP_RX_OVERRUN 标志被设置,导致 MCU 无法传输同步段和后续数据。通过检查这些寄存器和状态机状态,你应该能够确定从属设备的故障所在。我相信这应该是一个简单明了的故障排除步骤。
致以最崇高的敬意
dongxun
我目前计划将这一清零操作纳入中断服务函数中执行。这可行吗?或者,能否请您告诉我您指的是哪个时间表?如果能有一些代码供我们审查就更好了。如能提供,将不胜感激。QQ截图20260514101334.png
此外,当我寻找清除超限的方法时,我发现有一个函数专门用于执行这种清除操作。当发生超限并在中断中检测到时,就会执行该功能。是什么原因导致我这边没有通过审核?期待您的回复。谢谢。QQ截图20260514090616.png
QQ截图20260514090705.png
嗨,Aoyng、
建议在其他调度程序中加入此清零操作,或者如果能确保在 RX_overrun 期间回调函数能够进入,也可以将其放在此处。
嗨,Aoyng、
根据您的截图,在 MCU 数据接收过程中显然发生了超限错误,导致通信死锁。您可以使用以下方法手动清除错误标记并恢复通信。至于此错误的具体细节,请参阅数据表和其他参考资料。
if(TRUE == Lpuart_Lin_Ip_HwGetStatusFlag(Base, LPUART_LIN_IP_RX_OVERRUN)) { /* Clear RxOverrun status */ (void)Lpuart_Lin_Ip_HwClearStatusFlag(Base, LPUART_LIN_IP_RX_OVERRUN); }
您好
我把它放在操作系统的一个定期调用函数中(手写代码),特别是调用 Lin_SendFrame 的函数中。每次发送 LIn 数据前都会调用它,您可以尝试测试一下,看看是否还有问题。
嗨,Aoyng、
据我所知,这是一个错误。我在"SW32K3_S32M27x_RDD_R21-11_5.0.0_D2410_Release 的勘误表手册中找到了以下描述备注pdf".由于我使用的是旧版本的 RTD,很明显我的 2.00 版本也存在这个错误。
dongxun_0-1778721726304.png
好的,我看到在中断期间检测到了这种状态。我是否可以在自己的回调函数中执行上述清除操作,如下图所示?我的从属程序与主机的通信(发送和接收)都是在回调函数中触发的。QQ截图20260514085744.png
对不起,dongxun,也许我昨天观察到的现象是不正确的。笔者在调试时,如果监控程序遇到问题,程序会进入中断状态,在接收到帧头后(当前 MCU 为从机),程序会再次进入中断,并进入该功能(如下图所示)。它没有在 LPUART_LIN_IP_RX_OVERRUN 状态下停止,但此时我应该做的是接收数据。然后,当再次进入中断时,它会停在 LPUART_LIN_IP_FRAME_ERR 处,然后清除错误。至于为什么在 OR 寄存器中显示 1,我就不清楚了。你有什么想法吗?QQ截图20260514135304.png
QQ截图20260514110755.png
QQ截图20260514110934.png好的,谢谢你的建议。我使用的是 S32K314 芯片。根据官方文档,我发现该芯片的LPUART接收缓冲区的大小为4字节。我能否理解,当接收到的数据超过 4 字节时,将触发溢出中断,此时需要将其清除?我可以更改接收缓冲区的大小吗?我从上图中获得的信息是,接收缓冲区的默认大小目前为 1 字节,但最初被提及为 4 字节。我对此有些困惑。你能理解吗?