1515 * 2021-8-25 SVCHAO The baud rate is configured according to the different APB1 frequencies.
1616 f4-series only.
1717 * 2025-09-20 wdfk_prog Implemented sendmsg_nonblocking op to support framework's async TX.
18+ * 2026-02-02 wdfk_prog Drain multiple RX frames per ISR with a bounded limit.
1819 */
1920
2021#include "drv_can.h"
2425#define LOG_TAG "drv_can"
2526#include <drv_log.h>
2627
28+ #ifndef CAN_ISR_DRAIN_LIMIT
29+ /*
30+ * bxCAN FIFO depth is 3 (FMP[1:0]=0..3). Draining up to 3 frames can clear the FIFO in one ISR,
31+ * reducing FULL/OVERRUN without letting ISR time grow unbounded.
32+ */
33+ #define CAN_ISR_DRAIN_LIMIT 3
34+ #endif
35+
2736/* attention !!! baud calculation example: Tclk / ((ss + bs1 + bs2) * brp) = 36 / ((1 + 8 + 3) * 3) = 1MHz*/
2837#if defined (SOC_SERIES_STM32F1 )/* APB1 36MHz(max) */
2938static 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)
745754 switch (fifo )
746755 {
747756 case CAN_RX_FIFO0 :
748- /* save to user list */
749- if (HAL_CAN_GetRxFifoFillLevel ( hcan , CAN_RX_FIFO0 ) && __HAL_CAN_GET_IT_SOURCE (hcan , CAN_IT_RX_FIFO0_MSG_PENDING ))
757+ /* save to user list: drain multiple frames per ISR to reduce FULL/OVERRUN */
758+ if (__HAL_CAN_GET_IT_SOURCE (hcan , CAN_IT_RX_FIFO0_MSG_PENDING ))
750759 {
751- rt_hw_can_isr (can , RT_CAN_EVENT_RX_IND | fifo << 8 );
760+ for (rt_uint32_t i = 0 ; i < CAN_ISR_DRAIN_LIMIT ; i ++ )
761+ {
762+ if (HAL_CAN_GetRxFifoFillLevel (hcan , CAN_RX_FIFO0 ) == 0 )
763+ {
764+ break ;
765+ }
766+ else
767+ {
768+ rt_hw_can_isr (can , RT_CAN_EVENT_RX_IND | fifo << 8 );
769+ }
770+ }
752771 }
753772 /* Check FULL flag for FIFO0 */
754773 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)
766785 }
767786 break ;
768787 case CAN_RX_FIFO1 :
769- /* save to user list */
770- if (HAL_CAN_GetRxFifoFillLevel ( hcan , CAN_RX_FIFO1 ) && __HAL_CAN_GET_IT_SOURCE (hcan , CAN_IT_RX_FIFO1_MSG_PENDING ))
788+ /* save to user list: drain multiple frames per ISR to reduce FULL/OVERRUN */
789+ if (__HAL_CAN_GET_IT_SOURCE (hcan , CAN_IT_RX_FIFO1_MSG_PENDING ))
771790 {
772- rt_hw_can_isr (can , RT_CAN_EVENT_RX_IND | fifo << 8 );
791+ for (rt_uint32_t i = 0 ; i < CAN_ISR_DRAIN_LIMIT ; i ++ )
792+ {
793+ if (HAL_CAN_GetRxFifoFillLevel (hcan , CAN_RX_FIFO1 ) == 0 )
794+ {
795+ break ;
796+ }
797+ else
798+ {
799+ rt_hw_can_isr (can , RT_CAN_EVENT_RX_IND | fifo << 8 );
800+ }
801+ }
773802 }
774803 /* Check FULL flag for FIFO1 */
775804 if (__HAL_CAN_GET_FLAG (hcan , CAN_FLAG_FF1 ) && __HAL_CAN_GET_IT_SOURCE (hcan , CAN_IT_RX_FIFO1_FULL ))
0 commit comments