Browse Source

[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>
liuyucai 1 month ago
parent
commit
a1c642aa3a

+ 20 - 1
components/drivers/can/Kconfig

@@ -6,7 +6,26 @@ if RT_USING_CAN
     config RT_CAN_USING_HDR
     config RT_CAN_USING_HDR
         bool "Enable CAN hardware filter"
         bool "Enable CAN hardware filter"
         default n
         default n
+        
     config RT_CAN_USING_CANFD
     config RT_CAN_USING_CANFD
         bool "Enable CANFD support"
         bool "Enable CANFD support"
         default n
         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

+ 28 - 13
components/drivers/can/dev_can.c

@@ -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
  * 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;
             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();
         level = rt_hw_interrupt_disable();
         result = tx_tosnd->result;
         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;
             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;
         result = tx_fifo->buffer[no].result;
         if (result == RT_CAN_SND_RESULT_OK)
         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;
         no = event >> 8;
         tx_fifo = (struct rt_can_tx_fifo *) can->can_tx;
         tx_fifo = (struct rt_can_tx_fifo *) can->can_tx;
         RT_ASSERT(tx_fifo != RT_NULL);
         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;
-        }
-        else
-        {
-            tx_fifo->buffer[no].result = RT_CAN_SND_RESULT_ERR;
+            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));
         }
         }
-        rt_completion_done(&(tx_fifo->buffer[no].completion));
         break;
         break;
     }
     }
     }
     }
@@ -972,3 +986,4 @@ int cmd_canstat(int argc, void **argv)
 }
 }
 MSH_CMD_EXPORT_ALIAS(cmd_canstat, canstat, stat can device status);
 MSH_CMD_EXPORT_ALIAS(cmd_canstat, canstat, stat can device status);
 #endif
 #endif
+

+ 5 - 1
components/drivers/include/drivers/dev_can.h

@@ -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
  * SPDX-License-Identifier: Apache-2.0
  *
  *
@@ -21,6 +21,9 @@
 #ifndef RT_CANSND_BOX_NUM
 #ifndef RT_CANSND_BOX_NUM
 #define RT_CANSND_BOX_NUM   1
 #define RT_CANSND_BOX_NUM   1
 #endif
 #endif
+#ifndef RT_CANSND_MSG_TIMEOUT
+#define RT_CANSND_MSG_TIMEOUT 100
+#endif
 
 
 enum CAN_DLC
 enum CAN_DLC
 {
 {
@@ -541,3 +544,4 @@ void rt_hw_can_isr(struct rt_can_device *can, int event);
 /*! @}*/
 /*! @}*/
 
 
 #endif /*__DEV_CAN_H*/
 #endif /*__DEV_CAN_H*/
+