2140805_zh-CN

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

2140805_zh-CN

2140805_zh-CN

LIN:S32K312 MCU 作为主站,在等待 LinID 时出现 Lin 超时错误

大家好,

我在长时间操作过程中遇到了间歇性 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

Re: LIN:S32K312 MCU as a Master, Lin Timeout Error whiling waiting for LinID

你好@dongxun

谢谢你的详细分析。

根据观察到的行为,我不认为这是软件驱动程序错误或 UART 模块硬件故障造成的。相反,它符合典型的嵌入式系统在中断严重情况下的行为。

根本原因似乎是 ISR 抢占,即 LIN RX/TX 中断因优先级更高的中断而延迟,导致缓冲区超限(STAT 寄存器中的 OR 位被设置)。
通过提高 LPUARTLIN-RXTx_IRQ 的优先级,有效地解决了这一问题,从而防止了进一步的抢占,恢复了稳定的通信。

这种缓解措施很好地说明了中断优先级如何影响实时通信可靠性。


顺祝商祺!

丹尼尔


Re: LIN:S32K312 MCU as a Master, Lin Timeout Error whiling waiting for LinID

嗨,丹

感谢您提供有关 LPUART 中断优先级和调试方法的详细建议。 展望未来,我们将积极监测 后续RTD版本中的 修复概述 ,以配合正在进行的 优化。

   

Re: LIN:S32K312 MCU as a Master, Lin Timeout Error whiling waiting for LinID

你好@dongxun

您目前使用的是过时版本的 RTD。请参阅每个版本的发行说明,其中包括已知问题和变更的详细列表。

考虑以下内容:

  1. 确保 LPUART 中断未被优先级更高的 ISR 屏蔽或延迟。如果可能,为 LPUART 中断分配最高优先级,以确保及时处理。
  2. 围绕 LIN ISR 和状态转换实施调试日志。比较成功和失败的传输日志,以识别异常或时间不一致。
  3. 在故障条件下捕获关键 LPUART 寄存器(例如 STAT、CTRL、BAUD)的值,以检测卡住标志或配置错误。
  4. 使用缩减的 LIN 计划进行测试(如仅 PID 0x10),以隔离与定时相关的问题并简化调试。
  5. 堆栈完整性检查
    调查潜在的堆栈溢出问题:在运行时监测堆栈指针,启动时使用已知模式初始化 SRAM 以检测溢出,考虑增加堆栈大小。
  6. 读写后序列化
    应用读写后技术,确保寄存器写入的正确完成和同步,特别是在关键外设配置中。

danielmartynek_0-1753689768578.pngdanielmartynek_0-1753689768578.png


此致,

丹尼尔

Re: LIN:S32K312 MCU as a Master, Lin Timeout Error whiling waiting for LinID

亲爱的团队

我写这封信是为了报告在数据传输过程中发现的 LIN 通信故障反复出现的根本原因和解决方法。经过深入调查,发现问题出在LPUART 外围设备的状态寄存器 (STAT) 上。具体来说,在协议标识符 (PID) 传输失败的情况下,超限错误 (OR) 位一直被设置。该标志表示新接收的数据在中断服务例程 (ISR) 处理前一个数据之前到达,导致数据丢失和通信停止

为了解决这个问题:

  1. 立即解决:我清除了 STAT 寄存器中的 OR 位,立即恢复了正常的 LIN 通信。
  2. 根本原因分析:我怀疑 LIN 数据处理 ISR(LPUARTLIN-RXTx_IRQ)被进入关键部分的优先级更高的中断所中断。这造成 ISR 执行延迟,导致缓冲区超限。
  3. 纠正措施:提高了 LPUARTLIN-RXTx_IRQ 的优先级,以尽量减少抢占风险。随后进行的压力测试(连续 10 小时的主从通信>)证实了长时间运行的稳定性。

征求反馈意见

虽然目前的解决方案很有效,但我欢迎大家提出进一步优化的建议,例如:

  • 实施硬件流量控制(如果 LPUART 外设支持),以防止超限。
  • 在 ISR 中添加缓冲区占用检查,在溢出发生前主动清除数据。
  • 探索基于 DMA 的数据传输,以减少 CPU 干预和中断延迟
     
    .

请就如何改进这种方法谈谈您的看法。

谨致问候,
dongxun、

Re: LIN:S32K312 MCU as a Master, Lin Timeout Error whiling waiting for LinID

你好,如图所示,我想我也遇到了这个问题。请告诉我您是如何解决这个问题的?QQ截图20260513203500.pngQQ截图20260513203500.png

Re: LIN:S32K312 MCU as a Master, Lin Timeout Error whiling waiting for LinID

你好,我在使用 MCU 作为从属设备时遇到了一个 LIN 通信问题。现象如下:程序烧录后,LIN 通信正常。我使用 MCU 作为从属设备来响应来自主机的帧头。但在运行过程中,运行一段时间后,会出现无响应的情况。观察到的现象是,主机不断发送无响应的帧头。看到这个帖子后,我尝试修改 LIN 的中断优先级,但现象依然存在。我通过示波器观察到的现象是,当帧头无响应时,帧头中的同步间隔段、同步段和 PID 都存在,但响应数据部分却不存在。您能告诉我应该从哪里查找原因吗?期待您的回复。谢谢。

Re: LIN:S32K312 MCU as a Master, Lin Timeout Error whiling waiting for LinID

嗨,Aoyng、

我注意到,只有在运行一段时间后才会出现无响应的情况。这表明,当 MCU 充当从机时,LIN 状态机最初运行正常。您观察到 MCU 停止响应时内部状态机卡住的具体位置了吗?

此外,您是否查阅了参考手册并检查了与从机相关的错误寄存器,以确定是否触发了特定错误?对于 S32K312 MCU,Lpuart_Lin_Ip_StatusFlagType 结构包含各种故障条件的描述。我个人曾遇到过这样一个问题(将 MCU 用作主设备时),LPUART_LIN_IP_RX_OVERRUN 标志被设置,导致 MCU 无法传输同步段和后续数据。通过检查这些寄存器和状态机状态,你应该能够确定从属设备的故障所在。我相信这应该是一个简单明了的故障排除步骤。

致以最崇高的敬意

dongxun

Re: LIN:S32K312 MCU as a Master, Lin Timeout Error whiling waiting for LinID

我目前计划将这一清零操作纳入中断服务函数中执行。这可行吗?或者,能否请您告诉我您指的是哪个时间表?如果能有一些代码供我们审查就更好了。如能提供,将不胜感激。QQ截图20260514101334.pngQQ截图20260514101334.png

Re: LIN:S32K312 MCU as a Master, Lin Timeout Error whiling waiting for LinID

此外,当我寻找清除超限的方法时,我发现有一个函数专门用于执行这种清除操作。当发生超限并在中断中检测到时,就会执行该功能。是什么原因导致我这边没有通过审核?期待您的回复。谢谢。QQ截图20260514090616.pngQQ截图20260514090616.pngQQ截图20260514090705.pngQQ截图20260514090705.png

Re: LIN:S32K312 MCU as a Master, Lin Timeout Error whiling waiting for LinID

嗨,Aoyng、

建议在其他调度程序中加入此清零操作,或者如果能确保在 RX_overrun 期间回调函数能够进入,也可以将其放在此处。



Re: LIN:S32K312 MCU as a Master, Lin Timeout Error whiling waiting for LinID

嗨,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); 
}
Re: LIN:S32K312 MCU as a Master, Lin Timeout Error whiling waiting for LinID

您好

我把它放在操作系统的一个定期调用函数中(手写代码),特别是调用 Lin_SendFrame 的函数中。每次发送 LIn 数据前都会调用它,您可以尝试测试一下,看看是否还有问题。

Re: LIN:S32K312 MCU as a Master, Lin Timeout Error whiling waiting for LinID

嗨,Aoyng、

据我所知,这是一个错误。我在"SW32K3_S32M27x_RDD_R21-11_5.0.0_D2410_Release 的勘误表手册中找到了以下描述备注pdf".由于我使用的是旧版本的 RTD,很明显我的 2.00 版本也存在这个错误。

dongxun_0-1778721726304.pngdongxun_0-1778721726304.png


Re: LIN:S32K312 MCU as a Master, Lin Timeout Error whiling waiting for LinID

好的,我看到在中断期间检测到了这种状态。我是否可以在自己的回调函数中执行上述清除操作,如下图所示?我的从属程序与主机的通信(发送和接收)都是在回调函数中触发的。QQ截图20260514085744.pngQQ截图20260514085744.png

Re: LIN:S32K312 MCU as a Master, Lin Timeout Error whiling waiting for LinID

对不起,dongxun,也许我昨天观察到的现象是不正确的。笔者在调试时,如果监控程序遇到问题,程序会进入中断状态,在接收到帧头后(当前 MCU 为从机),程序会再次进入中断,并进入该功能(如下图所示)。它没有在 LPUART_LIN_IP_RX_OVERRUN 状态下停止,但此时我应该做的是接收数据。然后,当再次进入中断时,它会停在 LPUART_LIN_IP_FRAME_ERR 处,然后清除错误。至于为什么在 OR 寄存器中显示 1,我就不清楚了。你有什么想法吗?QQ截图20260514135304.pngQQ截图20260514135304.png

Re: LIN:S32K312 MCU as a Master, Lin Timeout Error whiling waiting for LinID

QQ截图20260514110755.pngQQ截图20260514110755.pngQQ截图20260514110934.pngQQ截图20260514110934.png好的,谢谢你的建议。我使用的是 S32K314 芯片。根据官方文档,我发现该芯片的LPUART接收缓冲区的大小为4字节。我能否理解,当接收到的数据超过 4 字节时,将触发溢出中断,此时需要将其清除?我可以更改接收缓冲区的大小吗?我从上图中获得的信息是,接收缓冲区的默认大小目前为 1 字节,但最初被提及为 4 字节。我对此有些困惑。你能理解吗?

Tags (1)
No ratings
Version history
Last update:
‎05-15-2026 02:42 AM
Updated by: