RT-Thread / rt-thread

RT-Thread is an open source IoT Real-Time Operating System (RTOS).
https://www.rt-thread.io
Apache License 2.0
10.47k stars 5.01k forks source link

can组件驱动中_can_int_tx 调用底层发送msg时 如果有暂时无法恢复的总线错误会卡死 #4848

Open Yohozzy opened 3 years ago

Yohozzy commented 3 years ago

can组件驱动中_can_int_tx 调用底层发送msg时 如果有暂时无法恢复的总线错误会卡死

rt_inline int _can_int_tx(struct rt_can_device can, const struct rt_can_msg data, int msgs) { int size; struct rt_can_tx_fifo *tx_fifo;

RT_ASSERT(can != RT_NULL);

size = msgs;
tx_fifo = (struct rt_can_tx_fifo *) can->can_tx;
RT_ASSERT(tx_fifo != RT_NULL);

while (msgs)
{
    rt_base_t level;
    rt_uint32_t no;
    rt_uint32_t result;
    struct rt_can_sndbxinx_list *tx_tosnd = RT_NULL;

    rt_sem_take(&(tx_fifo->sem), RT_WAITING_FOREVER);
    level = rt_hw_interrupt_disable();
    tx_tosnd = rt_list_entry(tx_fifo->freelist.next, struct rt_can_sndbxinx_list, list);
    RT_ASSERT(tx_tosnd != RT_NULL);
    rt_list_remove(&tx_tosnd->list);
    rt_hw_interrupt_enable(level);

    no = ((rt_uint32_t)tx_tosnd - (rt_uint32_t)tx_fifo->buffer) / sizeof(struct rt_can_sndbxinx_list);
    tx_tosnd->result = RT_CAN_SND_RESULT_WAIT;
    **if (can->ops->sendmsg(can, data, no) != RT_EOK)**
    {
        /* send failed. */
        level = rt_hw_interrupt_disable();
        rt_list_insert_after(&tx_fifo->freelist, &tx_tosnd->list);
        rt_hw_interrupt_enable(level);
        rt_sem_release(&(tx_fifo->sem));
        **continue;**
    }

    can->status.sndchange = 1;
    rt_completion_wait(&(tx_tosnd->completion), RT_WAITING_FOREVER);

    level = rt_hw_interrupt_disable();
    result = tx_tosnd->result;
    if (!rt_list_isempty(&tx_tosnd->list))
    {
        rt_list_remove(&tx_tosnd->list);
    }
    rt_list_insert_before(&tx_fifo->freelist, &tx_tosnd->list);
    rt_hw_interrupt_enable(level);
    rt_sem_release(&(tx_fifo->sem));

    if (result == RT_CAN_SND_RESULT_OK)
    {
        level = rt_hw_interrupt_disable();
        can->status.sndpkg++;
        rt_hw_interrupt_enable(level);

        data ++;
        msgs -= sizeof(struct rt_can_msg);
        if (!msgs) break;
    }
    else
    {
        level = rt_hw_interrupt_disable();
        can->status.dropedsndpkg++;
        rt_hw_interrupt_enable(level);
        break;
    }
}

return (size - msgs);

}

当总线存在临时物理断开时 调用底层can->ops->sendmsg(can, data, no) 会一直失败 然后再下面分支的continue一直循环

gbcwbz commented 2 years ago

遇到了相同的问题

logeexpluoqi commented 1 year ago

这个问题还没有解决吗?

gbcwbz commented 1 year ago

4.1.0之后好像解决了

logeexpluoqi commented 1 year ago

我现在使用任然会卡住,使用的是STM32F407VET6板子,LOOPBACK模式才不会卡住,而且该模式下CAN调试器能收到发的数据,NORMAL模式怎么都发不出去,而且会卡住,程序配置是按照官网例程来的,也接收不到,使用的版本是4.1.1。

gbcwbz commented 1 year ago

我看了下代码,这个 issue 里面提到的发送失败 continue 的问题已经改掉了,你遇到的也许是其他地方导致的, 比如驱动

logeexpluoqi commented 1 year ago

我看了下代码,这个 issue 里面提到的发送失败 continue 的问题已经改掉了,你遇到的也许是其他地方导致的, 比如驱动 多谢!我再找找

logeexpluoqi commented 1 year ago

image

canstat 查看的消息是这样的

logeexpluoqi commented 1 year ago

找到了,我用的CAN收发器不行。500k能用,1m的时候拿示波器看,明显信号波形 不对

wdfk-prog commented 1 year ago

找到了,我用的CAN收发器不行。500k能用,1m的时候拿示波器看,明显信号波形 不对