From 1eaa85c581a4bf5d0378084fc418105685273a0e Mon Sep 17 00:00:00 2001 From: wdfk-prog <1425075683@qq.com> Date: Mon, 2 Feb 2026 15:31:45 +0800 Subject: [PATCH] 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 --- .../libraries/HAL_Drivers/drivers/drv_can.c | 41 ++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_can.c b/bsp/stm32/libraries/HAL_Drivers/drivers/drv_can.c index 72d89316b2..97c06dadf6 100644 --- a/bsp/stm32/libraries/HAL_Drivers/drivers/drv_can.c +++ b/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. f4-series only. * 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" @@ -24,6 +25,14 @@ #define LOG_TAG "drv_can" #include +#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*/ #if defined (SOC_SERIES_STM32F1)/* APB1 36MHz(max) */ 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) { 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 */ 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; 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 */ if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FF1) && __HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_RX_FIFO1_FULL))