Jelajahi Sumber

feat[STM32][CAN]: drain RX FIFO frames in ISR with a bounded limit to reduce overruns

- Add CAN_ISR_DRAIN_LIMIT (default 3) to cap ISR work
- Drain multiple frames per RX0/RX1 interrupt to reduce FIFO FULL/OVERRUN
wdfk-prog 2 hari lalu
induk
melakukan
1eaa85c581
1 mengubah file dengan 35 tambahan dan 6 penghapusan
  1. 35 6
      bsp/stm32/libraries/HAL_Drivers/drivers/drv_can.c

+ 35 - 6
bsp/stm32/libraries/HAL_Drivers/drivers/drv_can.c

@@ -15,6 +15,7 @@
  * 2021-8-25      SVCHAO       The baud rate is configured according to the different APB1 frequencies.
  * 2021-8-25      SVCHAO       The baud rate is configured according to the different APB1 frequencies.
                                f4-series only.
                                f4-series only.
  * 2025-09-20     wdfk_prog    Implemented sendmsg_nonblocking op to support framework's async TX.
  * 2025-09-20     wdfk_prog    Implemented sendmsg_nonblocking op to support framework's async TX.
+ * 2026-02-02     wdfk_prog    Drain multiple RX frames per ISR with a bounded limit.
  */
  */
 
 
 #include "drv_can.h"
 #include "drv_can.h"
@@ -24,6 +25,14 @@
 #define LOG_TAG    "drv_can"
 #define LOG_TAG    "drv_can"
 #include <drv_log.h>
 #include <drv_log.h>
 
 
+#ifndef CAN_ISR_DRAIN_LIMIT
+/*
+ * bxCAN FIFO depth is 3 (FMP[1:0]=0..3). Draining up to 3 frames can clear the FIFO in one ISR,
+ * reducing FULL/OVERRUN without letting ISR time grow unbounded.
+ */
+#define CAN_ISR_DRAIN_LIMIT 3
+#endif
+
 /* attention !!! baud calculation example: Tclk / ((ss + bs1 + bs2) * brp) = 36 / ((1 + 8 + 3) * 3) = 1MHz*/
 /* attention !!! baud calculation example: Tclk / ((ss + bs1 + bs2) * brp) = 36 / ((1 + 8 + 3) * 3) = 1MHz*/
 #if defined (SOC_SERIES_STM32F1)/* APB1 36MHz(max) */
 #if defined (SOC_SERIES_STM32F1)/* APB1 36MHz(max) */
 static const struct stm32_baud_rate_tab can_baud_rate_tab[] =
 static const struct stm32_baud_rate_tab can_baud_rate_tab[] =
@@ -745,10 +754,20 @@ static void _can_rx_isr(struct rt_can_device *can, rt_uint32_t fifo)
     switch (fifo)
     switch (fifo)
     {
     {
     case CAN_RX_FIFO0:
     case CAN_RX_FIFO0:
-        /* save to user list */
-        if (HAL_CAN_GetRxFifoFillLevel(hcan, CAN_RX_FIFO0) && __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO0_MSG_PENDING))
+        /* save to user list: drain multiple frames per ISR to reduce FULL/OVERRUN */
+        if (__HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO0_MSG_PENDING))
         {
         {
-            rt_hw_can_isr(can, RT_CAN_EVENT_RX_IND | fifo << 8);
+            for (rt_uint32_t i = 0; i < CAN_ISR_DRAIN_LIMIT; i++)
+            {
+                if (HAL_CAN_GetRxFifoFillLevel(hcan, CAN_RX_FIFO0) == 0)
+                {
+                    break;
+                }
+                else
+                {
+                    rt_hw_can_isr(can, RT_CAN_EVENT_RX_IND | fifo << 8);
+                }
+            }
         }
         }
         /* Check FULL flag for FIFO0 */
         /* Check FULL flag for FIFO0 */
         if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FF0) && __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO0_FULL))
         if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FF0) && __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO0_FULL))
@@ -766,10 +785,20 @@ static void _can_rx_isr(struct rt_can_device *can, rt_uint32_t fifo)
         }
         }
         break;
         break;
     case CAN_RX_FIFO1:
     case CAN_RX_FIFO1:
-        /* save to user list */
-        if (HAL_CAN_GetRxFifoFillLevel(hcan, CAN_RX_FIFO1) && __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO1_MSG_PENDING))
+        /* save to user list: drain multiple frames per ISR to reduce FULL/OVERRUN */
+        if (__HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO1_MSG_PENDING))
         {
         {
-            rt_hw_can_isr(can, RT_CAN_EVENT_RX_IND | fifo << 8);
+            for (rt_uint32_t i = 0; i < CAN_ISR_DRAIN_LIMIT; i++)
+            {
+                if (HAL_CAN_GetRxFifoFillLevel(hcan, CAN_RX_FIFO1) == 0)
+                {
+                    break;
+                }
+                else
+                {
+                    rt_hw_can_isr(can, RT_CAN_EVENT_RX_IND | fifo << 8);
+                }
+            }
         }
         }
         /* Check FULL flag for FIFO1 */
         /* Check FULL flag for FIFO1 */
         if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FF1) && __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO1_FULL))
         if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FF1) && __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO1_FULL))