Skip to content

[Bug] CAN总线发送(_can_int_tx)在链路波动时会阻塞 #10341

Open
@unnamed2

Description

@unnamed2
Contributor

RT-Thread Version

5.1.0

Hardware Type/Architectures

STM32F407VET6

Develop Toolchain

RT-Thread Studio

Describe the bug

在CAN总线上设备掉电时发送CAN报文,STM32F407会产生SCE中断(错误码并非RT_CAN_BUS_ACK_ERR),drv_can中没有调用rt_hw_can_isr来执行

rt_completion_done(&(tx_fifo->buffer[no].completion));

这会导致 _can_int_tx 中

rt_completion_wait(&(tx_tosnd->completion), RT_WAITING_FOREVER)

永远不会返回。我尝试将他改成

if(RT_EOK != rt_completion_wait(&(tx_tosnd->completion), 100))
        {
            /* send timeout. */
            
            level = rt_hw_interrupt_disable();
            rt_list_insert_before(&tx_fifo->freelist, &tx_tosnd->list);
            rt_hw_interrupt_enable(level);
            rt_sem_release(&(tx_fifo->sem));

            // rt_kprintf("CAN send timeout, no %d\n", no);
            goto err_ret;
        }

来解决,不知道是否正确

Other additional context

No response

Activity

wdfk-prog

wdfk-prog commented on May 31, 2025

@wdfk-prog
Contributor

static void _can_sce_isr(struct rt_can_device *can)

  • sce中断有定义且有做处理
  • 请排查一下是否进入该中断,进入后的具体中断标志是什么触发的.中断处理程序有没有执行错误处理
unnamed2

unnamed2 commented on May 31, 2025

@unnamed2
ContributorAuthor

rt-thread/bsp/stm32/libraries/HAL_Drivers/drivers/drv_can.c

     Line 707
  in
  [fe13089](/RT-Thread/rt-thread/commit/fe1308976ee6268d50890b4df7adecb182e309e5)





    
      
       static void _can_sce_isr(struct rt_can_device *can)

``
* sce中断有定义且有做处理

* 请排查一下是否进入该中断,进入后的具体中断标志是什么触发的.中断处理程序有没有执行错误处理

感谢回复。

在我使用的版本中, _can_sce_isr的代码是直接写在CAN1_SCE_IRQHandler中的,经过对比,他们的实现上的差距并不算很大。

经过排查,在设备掉电瞬间发送报文会产生SCE中断,此时ESR寄存器的值为0x1800013(在被读取之后变更为0x0800003), 对应着RT_CAN_BUS_BIT_PAD_ERR,新版_can_sce_isr中和我使用的旧版本中对此错误的处理是一致的,仅仅对计数+1以记录错误,随后并未调用rt_hw_can_isr来进行处理,这也是导致rt_completion_done(&(tx_fifo->buffer[no].completion));无法返回的原因。

在我的案例中,设备掉电之后,我尝试发送CAN报文会正常产生RT_CAN_BUS_ACK_ERR错误,这时能正确唤醒被挂起的发送线程。

wdfk-prog

wdfk-prog commented on May 31, 2025

@wdfk-prog
Contributor

rt-thread/bsp/stm32/libraries/HAL_Drivers/drivers/drv_can.c

     Line 707
  in
  [fe13089](/RT-Thread/rt-thread/commit/fe1308976ee6268d50890b4df7adecb182e309e5)





    
      
       static void _can_sce_isr(struct rt_can_device *can)

``

  • sce中断有定义且有做处理
* 请排查一下是否进入该中断,进入后的具体中断标志是什么触发的.中断处理程序有没有执行错误处理

感谢回复。

在我使用的版本中, _can_sce_isr的代码是直接写在CAN1_SCE_IRQHandler中的,经过对比,他们的实现上的差距并不算很大。

经过排查,在设备掉电瞬间发送报文会产生SCE中断,此时ESR寄存器的值为0x1800013(在被读取之后变更为0x0800003), 对应着RT_CAN_BUS_BIT_PAD_ERR,新版_can_sce_isr中和我使用的旧版本中对此错误的处理是一致的,仅仅对计数+1以记录错误,随后并未调用rt_hw_can_isr来进行处理,这也是导致rt_completion_done(&(tx_fifo->buffer[no].completion));无法返回的原因。

在我的案例中,设备掉电之后,我尝试发送CAN报文会正常产生RT_CAN_BUS_ACK_ERR错误,这时能正确唤醒被挂起的发送线程。

  • 那你能参考这里关于错误处理的代码提个pr吗?

if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_RQCP0))
{
if (!__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK0))
{
rt_hw_can_isr(can, RT_CAN_EVENT_TX_FAIL | 0 << 8);
}
SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP0);
}

  • 应该加入这样的代码就可以了,可以用去验证一下效果.我把RT_CAN_BUS_ACK_ERR错误处理的逻辑直接copy到RT_CAN_BUS_BIT_PAD_ERR错误处理上了.
        case RT_CAN_BUS_BIT_PAD_ERR:
            if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_RQCP0))
            {
                if (!__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK0))
                {
                    rt_hw_can_isr(can, RT_CAN_EVENT_TX_FAIL | 0 << 8);
                }
                SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP0);
            }
            else if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_RQCP1))
            {
                if (!__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK1))
                {
                    rt_hw_can_isr(can, RT_CAN_EVENT_TX_FAIL | 1 << 8);
                }
                SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP1);
            }
            else if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_RQCP2))
            {
                if (!__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK2))
                {
                    rt_hw_can_isr(can, RT_CAN_EVENT_TX_FAIL | 2 << 8);
                }
                SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP2);
            }
            else
            {
                if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TERR0))/*IF AutoRetransmission = ENABLE,ACK ERR handler*/
                {
                    SET_BIT(hcan->Instance->TSR, CAN_TSR_ABRQ0);/*Abort the send request, trigger the TX interrupt,release completion quantity*/
                }
                else if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TERR1))
                {
                    SET_BIT(hcan->Instance->TSR, CAN_TSR_ABRQ1);
                }
                else if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TERR2))
                {
                    SET_BIT(hcan->Instance->TSR, CAN_TSR_ABRQ2);
                }
            }
            break;
  • 你采用的方案,仅仅是增加的超时的错误返回而已.并不是真正的错误处理
  • 或许应该对SCE的所有错误都进行一下上述逻辑的处理.都进行一下,在没有开启AutoRetransmission 时,对于TX发送导致进入的SCE中断执行进入rt_hw_can_isr函数执行错误处理.
  • 其他错误因为很少遇到,并不清楚会不会对tx发送产生影响
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @unnamed2@wdfk-prog

        Issue actions

          [Bug] CAN总线发送(_can_int_tx)在链路波动时会阻塞 · Issue #10341 · RT-Thread/rt-thread