[Fix] <components>:drivers/can/dev_can.c 修复CAN底层无法工作时导致调用 _can_int_tx 的线程一直挂起的问题

Solution: 使用 can->status.sndchange 的bit位来表示某个发送邮箱超时
如果超时 底层驱动再通知tx_done或者tx_fail事件时不予处理

Signed-off-by: Yucai Liu <1486344514@qq.com>
This commit is contained in:
liuyucai 2025-07-29 10:15:03 +08:00 committed by Rbb666
parent c209173061
commit a1c642aa3a
3 changed files with 53 additions and 15 deletions

View File

@ -6,7 +6,26 @@ if RT_USING_CAN
config RT_CAN_USING_HDR
bool "Enable CAN hardware filter"
default n
config RT_CAN_USING_CANFD
bool "Enable CANFD support"
default n
endif
config RT_CANMSG_BOX_SZ
int "CAN message box size"
default 16
help
Set the size of the CAN message box.
config RT_CANSND_BOX_NUM
int "Number of CAN send queues"
default 1
help
Set the number of CAN send queues.
config RT_CANSND_MSG_TIMEOUT
int "CAN send message timeout"
default 100
help
Set the timeout for CAN send messages.
endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2024 RT-Thread Development Team
* Copyright (c) 2006-2025, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
@ -165,8 +165,16 @@ rt_inline int _can_int_tx(struct rt_can_device *can, const struct rt_can_msg *da
goto err_ret;
}
can->status.sndchange = 1;
rt_completion_wait(&(tx_tosnd->completion), RT_WAITING_FOREVER);
can->status.sndchange |= 1<<no;
if (rt_completion_wait(&(tx_tosnd->completion), RT_CANSND_MSG_TIMEOUT) != RT_EOK)
{
level = rt_hw_interrupt_disable();
rt_list_insert_before(&tx_fifo->freelist, &tx_tosnd->list);
can->status.sndchange &= ~ (1<<no);
rt_hw_interrupt_enable(level);
rt_sem_release(&(tx_fifo->sem));
goto err_ret;
}
level = rt_hw_interrupt_disable();
result = tx_tosnd->result;
@ -237,8 +245,12 @@ rt_inline int _can_int_tx_priv(struct rt_can_device *can, const struct rt_can_ms
{
continue;
}
can->status.sndchange = 1;
rt_completion_wait(&(tx_fifo->buffer[no].completion), RT_WAITING_FOREVER);
can->status.sndchange |= 1<<no;
if (rt_completion_wait(&(tx_fifo->buffer[no].completion), RT_CANSND_MSG_TIMEOUT) != RT_EOK)
{
can->status.sndchange &= ~ (1<<no);
continue;
}
result = tx_fifo->buffer[no].result;
if (result == RT_CAN_SND_RESULT_OK)
@ -892,16 +904,18 @@ void rt_hw_can_isr(struct rt_can_device *can, int event)
no = event >> 8;
tx_fifo = (struct rt_can_tx_fifo *) can->can_tx;
RT_ASSERT(tx_fifo != RT_NULL);
if ((event & 0xff) == RT_CAN_EVENT_TX_DONE)
if (can->status.sndchange&(1<<no))
{
tx_fifo->buffer[no].result = RT_CAN_SND_RESULT_OK;
if ((event & 0xff) == RT_CAN_EVENT_TX_DONE)
{
tx_fifo->buffer[no].result = RT_CAN_SND_RESULT_OK;
}
else
{
tx_fifo->buffer[no].result = RT_CAN_SND_RESULT_ERR;
}
rt_completion_done(&(tx_fifo->buffer[no].completion));
}
else
{
tx_fifo->buffer[no].result = RT_CAN_SND_RESULT_ERR;
}
rt_completion_done(&(tx_fifo->buffer[no].completion));
break;
}
}
@ -972,3 +986,4 @@ int cmd_canstat(int argc, void **argv)
}
MSH_CMD_EXPORT_ALIAS(cmd_canstat, canstat, stat can device status);
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2024 RT-Thread Development Team
* Copyright (c) 2006-2025, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
@ -21,6 +21,9 @@
#ifndef RT_CANSND_BOX_NUM
#define RT_CANSND_BOX_NUM 1
#endif
#ifndef RT_CANSND_MSG_TIMEOUT
#define RT_CANSND_MSG_TIMEOUT 100
#endif
enum CAN_DLC
{
@ -541,3 +544,4 @@ void rt_hw_can_isr(struct rt_can_device *can, int event);
/*! @}*/
#endif /*__DEV_CAN_H*/