Просмотр исходного кода

feat[can]: Implement non-blocking send mechanism and enhance CAN driver functionality

- Added support for non-blocking mode CAN message sending, including software ring buffer management and dynamic memory allocation options.
- Improved related comments and error handling.
- Updated example code to demonstrate the usage of both blocking and non-blocking sending modes, and corrected some structure field naming and macro definitions.
wdfk-prog 3 месяцев назад
Родитель
Сommit
11156de0de

+ 85 - 5
bsp/stm32/libraries/HAL_Drivers/drivers/drv_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
  *
@@ -14,6 +14,7 @@
  * 2021-02-02     YuZhe XU     fix bug in filter config
  * 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.
  */
 
 #include "drv_can.h"
@@ -484,6 +485,21 @@ static rt_err_t _can_control(struct rt_can_device *can, int cmd, void *arg)
     return RT_EOK;
 }
 
+/**
+ * @internal
+ * @brief Low-level function to send a CAN message to a specific hardware mailbox.
+ *
+ * This function is part of the **blocking** send mechanism. It is called by
+ * `_can_int_tx` after a hardware mailbox has already been acquired. Its role is
+ * to format the message according to the STM32 hardware requirements and place
+ * it into the specified mailbox for transmission.
+ *
+ * @param[in] can     A pointer to the CAN device structure.
+ * @param[in] buf     A pointer to the `rt_can_msg` to be sent.
+ * @param[in] box_num The specific hardware mailbox index (0, 1, or 2) to use for this tran
+ *
+ * @return `RT_EOK` on success, or an error code on failure.
+ */
 static int _can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t box_num)
 {
     CAN_HandleTypeDef *hcan;
@@ -586,6 +602,53 @@ static int _can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t
     }
 }
 
+/**
+ * @internal
+ * @brief Low-level, hardware-specific non-blocking function to send a CAN message.
+ *
+ * This function interacts directly with the STM32 HAL library to add a message
+ * to a hardware TX mailbox. It returns immediately and does not wait for the
+ * transmission to complete.
+ *
+ * @param[in] can   A pointer to the CAN device structure.
+ * @param[in] buf   A pointer to the `rt_can_msg` to be sent.
+ *
+ * @return
+ * - `RT_EOK` if the message was successfully accepted by the hardware.
+ * - `-RT_EBUSY` if all hardware mailboxes are currently full.
+ * - `-RT_ERROR` on other HAL failures.
+ */
+static rt_ssize_t _can_sendmsg_nonblocking(struct rt_can_device *can, const void *buf)
+{
+    CAN_HandleTypeDef *hcan = &((struct stm32_can *) can->parent.user_data)->CanHandle;
+    struct rt_can_msg *pmsg = (struct rt_can_msg *) buf;
+    CAN_TxHeaderTypeDef txheader = {0};
+    uint32_t tx_mailbox;
+
+    if ((hcan->State != HAL_CAN_STATE_READY) && (hcan->State != HAL_CAN_STATE_LISTENING))
+        return -RT_ERROR;
+
+    if (HAL_CAN_GetTxMailboxesFreeLevel(hcan) == 0)
+        return -RT_EBUSY;
+
+    txheader.DLC = pmsg->len;
+    txheader.RTR = (pmsg->rtr == RT_CAN_RTR) ? CAN_RTR_REMOTE : CAN_RTR_DATA;
+    txheader.IDE = (pmsg->ide == RT_CAN_STDID) ? CAN_ID_STD : CAN_ID_EXT;
+    if (txheader.IDE == CAN_ID_STD)
+        txheader.StdId = pmsg->id;
+    else
+        txheader.ExtId = pmsg->id;
+
+    HAL_StatusTypeDef status = HAL_CAN_AddTxMessage(hcan, &txheader, pmsg->data, &tx_mailbox);
+    if (status != HAL_OK)
+    {
+        LOG_W("can sendmsg nonblocking send error %d", status);
+        return -RT_ERROR;
+    }
+
+    return RT_EOK;
+}
+
 static int _can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t fifo)
 {
     HAL_StatusTypeDef status;
@@ -645,10 +708,11 @@ static int _can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t fifo)
 
 static const struct rt_can_ops _can_ops =
 {
-    _can_config,
-    _can_control,
-    _can_sendmsg,
-    _can_recvmsg,
+    .configure  = _can_config,
+    .control    = _can_control,
+    .sendmsg    = _can_sendmsg,
+    .recvmsg    = _can_recvmsg,
+    .sendmsg_nonblocking = _can_sendmsg_nonblocking,
 };
 
 static void _can_rx_isr(struct rt_can_device *can, rt_uint32_t fifo)
@@ -788,6 +852,22 @@ static void _can_sce_isr(struct rt_can_device *can)
     hcan->Instance->MSR |= CAN_MSR_ERRI;
 }
 
+/**
+ * @internal
+ * @brief The low-level ISR for CAN TX events on STM32.
+ *
+ * This function's sole responsibility is to check the hardware status flags
+ * to determine which mailbox completed a transmission and whether it was
+ * successful or failed. It then reports the specific event to the upper
+ * framework layer via `rt_hw_can_isr()`.
+ *
+ * @note This ISR contains NO framework-level logic (e.g., buffer handling).
+ *       It is a pure hardware event reporter, ensuring a clean separation
+ *       of concerns between the driver and the framework.
+ *
+ * @param[in] can A pointer to the CAN device structure.
+ * @return void
+ */
 static void _can_tx_isr(struct rt_can_device *can)
 {
     CAN_HandleTypeDef *hcan;

+ 57 - 12
components/drivers/can/Kconfig

@@ -1,31 +1,76 @@
 config RT_USING_CAN
     bool "Using CAN device drivers"
     default n
+    help
+        Enable this option to include the CAN device driver framework.
 
 if RT_USING_CAN
+
     config RT_CAN_USING_HDR
-        bool "Enable CAN hardware filter"
+        bool "Enable CAN hardware filter support"
         default n
-        
+        help
+            If your CAN controller supports hardware filtering, and you want to
+            use the framework to configure these filters, enable this option.
+
     config RT_CAN_USING_CANFD
-        bool "Enable CANFD support"
+        bool "Enable CAN-FD support"
         default n
-        
+        help
+            Enable this to support CAN with Flexible Data-Rate. This will
+            increase the size of the rt_can_msg structure.
+
     config RT_CANMSG_BOX_SZ
-        int "CAN message box size"
+        int "Software RX message box size (in messages)"
         default 16
         help
-            Set the size of the CAN message box.
-            
+            This sets the capacity of the software buffer (FIFO) for incoming
+            CAN messages. It defines how many messages can be buffered by the
+            driver before the application must read them.
+
     config RT_CANSND_BOX_NUM
-        int "Number of CAN send queues"
+        int "Number of mailboxes for blocking send"
         default 1
         help
-            Set the number of CAN send queues.
-            
+            This sets the number of concurrent blocking send operations that
+            can be in flight. It is typically matched to the number of
+            hardware transmission mailboxes on the CAN controller.
+
     config RT_CANSND_MSG_TIMEOUT
-        int "CAN send message timeout"
+        int "Timeout for blocking send (in OS ticks)"
         default 100
         help
-            Set the timeout for CAN send messages.
+            This sets the default time a thread will wait for a hardware
+            mailbox to become available when sending in blocking mode.
+
+    config RT_CAN_NB_TX_FIFO_SIZE
+        int "Non-blocking send buffer size (in bytes)"
+        default 256
+        help
+            This defines the size of the software ring buffer used for
+            non-blocking and ISR-based transmissions. When the hardware
+            mailboxes are full, outgoing messages are temporarily stored
+            in this buffer.
+
+            To calculate a suitable size, use:
+            (number of messages to buffer) * sizeof(struct rt_can_msg).
+            For standard CAN, sizeof(struct rt_can_msg) is typically 16 bytes.
+            The default of 256 bytes can buffer 16 standard CAN messages.
+            If using CAN-FD, you will need to increase this size significantly.
+
+    config RT_CAN_MALLOC_NB_TX_BUFFER
+        bool "Dynamically allocate the non-blocking send buffer"
+        depends on RT_USING_HEAP
+        default n
+        help
+            If this option is enabled (y), the non-blocking send buffer will
+            be allocated from the system heap at runtime when the CAN device
+            is opened (using rt_malloc). This saves static RAM but requires
+            a heap to be available.
+
+            If this option is disabled (n), the buffer will be allocated
+            as a static array within the rt_can_device structure. This
+            consumes static RAM but guarantees the memory is always available
+            and avoids heap fragmentation.
+
 endif

+ 281 - 54
components/drivers/can/dev_can.c

@@ -7,6 +7,7 @@
  * Date           Author            Notes
  * 2015-05-14     aubrcool@qq.com   first version
  * 2015-07-06     Bernard           code cleanup and remove RT_CAN_USING_LED;
+ * 2025-09-20     wdfk_prog         Implemented non-blocking, ISR-safe send logic unified under rt_device_write.
  */
 
 #include <rthw.h>
@@ -40,8 +41,19 @@ static rt_err_t rt_can_init(struct rt_device *dev)
     return result;
 }
 
-/*
- * can interrupt routines
+/**
+ * @internal
+ * @brief Handles reading messages from the software RX FIFO into a user buffer.
+ *
+ * This function is called by the public `rt_can_read()` API when the device
+ * is opened with interrupt-driven reception enabled. It safely transfers
+ * messages from the internal `uselist` to the user-provided buffer.
+ *
+ * @param[in]  can   A pointer to the CAN device.
+ * @param[out] data  A pointer to the destination buffer for the received messages.
+ * @param[in]  msgs  The total size in bytes of the destination buffer.
+ *
+ * @return The number of bytes actually read from the FIFO.
  */
 rt_inline rt_ssize_t _can_int_rx(struct rt_can_device *can, struct rt_can_msg *data, rt_ssize_t msgs)
 {
@@ -63,7 +75,7 @@ rt_inline rt_ssize_t _can_int_rx(struct rt_can_device *can, struct rt_can_msg *d
         struct rt_can_msg_list *listmsg = RT_NULL;
 
         /* disable interrupt */
-        level = rt_hw_interrupt_disable();
+        level = rt_hw_local_irq_disable();
 #ifdef RT_CAN_USING_HDR
         hdr = data->hdr_index;
 
@@ -97,22 +109,22 @@ rt_inline rt_ssize_t _can_int_rx(struct rt_can_device *can, struct rt_can_msg *d
             else
             {
                 /* no data, enable interrupt and break out */
-                rt_hw_interrupt_enable(level);
+                rt_hw_local_irq_enable(level);
                 break;
             }
         }
 
         /* enable interrupt */
-        rt_hw_interrupt_enable(level);
+        rt_hw_local_irq_enable(level);
         if (listmsg != RT_NULL)
         {
             rt_memcpy(data, &listmsg->data, sizeof(struct rt_can_msg));
 
-            level = rt_hw_interrupt_disable();
+            level = rt_hw_local_irq_disable();
             rt_list_insert_before(&rx_fifo->freelist, &listmsg->list);
             rx_fifo->freenumbers++;
             RT_ASSERT(rx_fifo->freenumbers <= can->config.msgboxsz);
-            rt_hw_interrupt_enable(level);
+            rt_hw_local_irq_enable(level);
 
             listmsg = RT_NULL;
         }
@@ -127,6 +139,25 @@ rt_inline rt_ssize_t _can_int_rx(struct rt_can_device *can, struct rt_can_msg *d
     return (size - msgs);
 }
 
+/**
+ * @internal
+ * @brief Handles the blocking (synchronous) transmission of CAN messages.
+ *
+ * This function is the core of the blocking send mechanism. It iterates through
+ * a buffer of messages to be sent. For each message, it:
+ * 1. Acquires a hardware mailbox resource using a semaphore.
+ * 2. Submits the message to the low-level driver for transmission.
+ * 3. Blocks the calling thread by waiting on a completion object.
+ * 4. Is woken up by the TX complete ISR (`rt_hw_can_isr`) when the transmission is finished.
+ *
+ * @note This function will block the calling thread and must not be called from an ISR.
+ *
+ * @param[in] can   A pointer to the CAN device.
+ * @param[in] data  A pointer to the source buffer of messages to be sent.
+ * @param[in] msgs  The total size in bytes of the source buffer.
+ *
+ * @return The number of bytes successfully sent.
+ */
 rt_inline int _can_int_tx(struct rt_can_device *can, const struct rt_can_msg *data, int msgs)
 {
     int size;
@@ -146,11 +177,11 @@ rt_inline int _can_int_tx(struct rt_can_device *can, const struct rt_can_msg *da
         struct rt_can_sndbxinx_list *tx_tosnd = RT_NULL;
 
         rt_sem_take(&(tx_fifo->sem), RT_WAITING_FOREVER);
-        level = rt_hw_interrupt_disable();
+        level = rt_hw_local_irq_disable();
         tx_tosnd = rt_list_entry(tx_fifo->freelist.next, struct rt_can_sndbxinx_list, list);
         RT_ASSERT(tx_tosnd != RT_NULL);
         rt_list_remove(&tx_tosnd->list);
-        rt_hw_interrupt_enable(level);
+        rt_hw_local_irq_enable(level);
 
         no = ((rt_ubase_t)tx_tosnd - (rt_ubase_t)tx_fifo->buffer) / sizeof(struct rt_can_sndbxinx_list);
         tx_tosnd->result = RT_CAN_SND_RESULT_WAIT;
@@ -158,9 +189,9 @@ rt_inline int _can_int_tx(struct rt_can_device *can, const struct rt_can_msg *da
         if (can->ops->sendmsg(can, data, no) != RT_EOK)
         {
             /* send failed. */
-            level = rt_hw_interrupt_disable();
+            level = rt_hw_local_irq_disable();
             rt_list_insert_before(&tx_fifo->freelist, &tx_tosnd->list);
-            rt_hw_interrupt_enable(level);
+            rt_hw_local_irq_enable(level);
             rt_sem_release(&(tx_fifo->sem));
             goto err_ret;
         }
@@ -168,29 +199,29 @@ rt_inline int _can_int_tx(struct rt_can_device *can, const struct rt_can_msg *da
         can->status.sndchange |= 1<<no;
         if (rt_completion_wait(&(tx_tosnd->completion), RT_CANSND_MSG_TIMEOUT) != RT_EOK)
         {
-            level = rt_hw_interrupt_disable();
+            level = rt_hw_local_irq_disable();
             rt_list_insert_before(&tx_fifo->freelist, &tx_tosnd->list);
             can->status.sndchange &= ~ (1<<no);
-            rt_hw_interrupt_enable(level);
+            rt_hw_local_irq_enable(level);
             rt_sem_release(&(tx_fifo->sem));
             goto err_ret;
         }
 
-        level = rt_hw_interrupt_disable();
+        level = rt_hw_local_irq_disable();
         result = tx_tosnd->result;
         if (!rt_list_isempty(&tx_tosnd->list))
         {
             rt_list_remove(&tx_tosnd->list);
         }
         rt_list_insert_before(&tx_fifo->freelist, &tx_tosnd->list);
-        rt_hw_interrupt_enable(level);
+        rt_hw_local_irq_enable(level);
         rt_sem_release(&(tx_fifo->sem));
 
         if (result == RT_CAN_SND_RESULT_OK)
         {
-            level = rt_hw_interrupt_disable();
+            level = rt_hw_local_irq_disable();
             can->status.sndpkg++;
-            rt_hw_interrupt_enable(level);
+            rt_hw_local_irq_enable(level);
 
             data ++;
             msgs -= sizeof(struct rt_can_msg);
@@ -199,9 +230,9 @@ rt_inline int _can_int_tx(struct rt_can_device *can, const struct rt_can_msg *da
         else
         {
 err_ret:
-            level = rt_hw_interrupt_disable();
+            level = rt_hw_local_irq_disable();
             can->status.dropedsndpkg++;
-            rt_hw_interrupt_enable(level);
+            rt_hw_local_irq_enable(level);
             break;
         }
     }
@@ -209,6 +240,20 @@ err_ret:
     return (size - msgs);
 }
 
+/**
+ * @internal
+ * @brief Handles blocking transmission in "private mode".
+ *
+ * This is a specialized version of `_can_int_tx` where the target hardware mailbox
+ * for each message is specified by the user in the `priv` field of the `rt_can_msg`
+ * structure, rather than being acquired dynamically from a pool.
+ *
+ * @param[in] can   A pointer to the CAN device.
+ * @param[in] data  A pointer to the source buffer of messages.
+ * @param[in] msgs  The total size in bytes of the source buffer.
+ *
+ * @return The number of bytes successfully sent.
+ */
 rt_inline int _can_int_tx_priv(struct rt_can_device *can, const struct rt_can_msg *data, int msgs)
 {
     int size;
@@ -230,16 +275,16 @@ rt_inline int _can_int_tx_priv(struct rt_can_device *can, const struct rt_can_ms
             break;
         }
 
-        level = rt_hw_interrupt_disable();
+        level = rt_hw_local_irq_disable();
         if ((tx_fifo->buffer[no].result != RT_CAN_SND_RESULT_OK))
         {
-            rt_hw_interrupt_enable(level);
+            rt_hw_local_irq_enable(level);
 
             rt_completion_wait(&(tx_fifo->buffer[no].completion), RT_WAITING_FOREVER);
             continue;
         }
         tx_fifo->buffer[no].result = RT_CAN_SND_RESULT_WAIT;
-        rt_hw_interrupt_enable(level);
+        rt_hw_local_irq_enable(level);
 
         if (can->ops->sendmsg(can, data, no) != RT_EOK)
         {
@@ -255,18 +300,18 @@ rt_inline int _can_int_tx_priv(struct rt_can_device *can, const struct rt_can_ms
         result = tx_fifo->buffer[no].result;
         if (result == RT_CAN_SND_RESULT_OK)
         {
-            level = rt_hw_interrupt_disable();
+            level = rt_hw_local_irq_disable();
             can->status.sndpkg++;
-            rt_hw_interrupt_enable(level);
+            rt_hw_local_irq_enable(level);
             data ++;
             msgs -= sizeof(struct rt_can_msg);
             if (!msgs) break;
         }
         else
         {
-            level = rt_hw_interrupt_disable();
+            level = rt_hw_local_irq_disable();
             can->status.dropedsndpkg++;
-            rt_hw_interrupt_enable(level);
+            rt_hw_local_irq_enable(level);
             break;
         }
     }
@@ -274,6 +319,76 @@ rt_inline int _can_int_tx_priv(struct rt_can_device *can, const struct rt_can_ms
     return (size - msgs);
 }
 
+/**
+ * @internal
+ * @brief Internal implementation of non-blocking CAN transmission.
+ *
+ * This function iterates through a buffer of CAN messages and attempts to send each one
+ * using a non-blocking strategy. It first tries to send directly via hardware (fast path).
+ * If the hardware is busy, it enqueues the message into a software ring buffer (slow path).
+ * This function is thread-safe and ISR-safe due to the use of critical sections for
+ * accessing the shared ring buffer.
+ *
+ * @param[in] can   A pointer to the CAN device.
+ * @param[in] pmsg  A pointer to the buffer of `rt_can_msg` structures.
+ * @param[in] size  The total size of the buffer in bytes.
+ *
+ * @return The number of bytes successfully sent or enqueued for later transmission.
+ */
+static rt_ssize_t _can_nonblocking_tx(struct rt_can_device *can, const struct rt_can_msg *pmsg, rt_size_t size)
+{
+    rt_ssize_t sent_size = 0;
+    rt_base_t level;
+
+    if (can->ops->sendmsg_nonblocking == RT_NULL)
+    {
+        return -RT_EINVAL;
+    }
+
+    while (sent_size < size)
+    {
+        if (can->ops->sendmsg_nonblocking(can, pmsg) == RT_EOK)
+        {
+            pmsg++;
+            sent_size += sizeof(struct rt_can_msg);
+            continue;
+        }
+
+        level = rt_hw_local_irq_disable();
+        if (rt_ringbuffer_space_len(&can->nb_tx_rb) >= sizeof(struct rt_can_msg))
+        {
+            rt_ringbuffer_put(&can->nb_tx_rb, (rt_uint8_t *)pmsg, sizeof(struct rt_can_msg));
+            rt_hw_local_irq_enable(level);
+
+            pmsg++;
+            sent_size += sizeof(struct rt_can_msg);
+        }
+        else
+        {
+            /* Buffer is full, cannot process this message or subsequent ones. */
+            can->status.dropedsndpkg += (size - sent_size) / sizeof(struct rt_can_msg);
+            rt_hw_local_irq_enable(level);
+            break;
+        }
+    }
+
+    return sent_size;
+}
+
+/**
+ * @internal
+ * @brief Opens the CAN device and initializes its resources.
+ *
+ * This function is called when `rt_device_open()` is invoked on a CAN device.
+ * It allocates and initializes software FIFOs for reception and transmission,
+ * sets up semaphores for the blocking send mechanism, configures the non-blocking
+ * send buffer, and starts the periodic status timer.
+ *
+ * @param[in] dev   A pointer to the device to be opened.
+ * @param[in] oflag The open flags, e.g., `RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX`.
+ *
+ * @return `RT_EOK` on successful opening, or an error code on failure.
+ */
 static rt_err_t rt_can_open(struct rt_device *dev, rt_uint16_t oflag)
 {
     struct rt_can_device *can;
@@ -369,6 +484,12 @@ static rt_err_t rt_can_open(struct rt_device *dev, rt_uint16_t oflag)
     }
 #endif
 
+#ifdef RT_CAN_MALLOC_NB_TX_BUFFER
+    can->nb_tx_rb_pool = (rt_uint8_t *)rt_malloc(RT_CAN_NB_TX_FIFO_SIZE);
+    RT_ASSERT(can->nb_tx_rb_pool != RT_NULL);
+#endif /* RT_CAN_MALLOC_NB_TX_BUFFER  */
+    rt_ringbuffer_init(&can->nb_tx_rb, can->nb_tx_rb_pool, RT_CAN_NB_TX_FIFO_SIZE);
+
     if (!can->timerinitflag)
     {
         can->timerinitflag = 1;
@@ -397,6 +518,14 @@ static rt_err_t rt_can_close(struct rt_device *dev)
         return RT_EOK;
     }
 
+#ifdef RT_CAN_MALLOC_NB_TX_BUFFER
+    if (can->nb_tx_rb_pool)
+    {
+        rt_free(can->nb_tx_rb_pool);
+        can->nb_tx_rb_pool = RT_NULL;
+    }
+#endif
+
     if (can->timerinitflag)
     {
         can->timerinitflag = 0;
@@ -461,7 +590,7 @@ static rt_ssize_t rt_can_read(struct rt_device *dev,
     struct rt_can_device *can;
 
     RT_ASSERT(dev != RT_NULL);
-    if (size == 0) return 0;
+    if (size == 0) return -RT_EINVAL;
 
     can = (struct rt_can_device *)dev;
 
@@ -470,22 +599,64 @@ static rt_ssize_t rt_can_read(struct rt_device *dev,
         return _can_int_rx(can, buffer, size);
     }
 
-    return 0;
+    return -RT_ENOSYS;
 }
 
+/**
+ * @brief Write data to the CAN device.
+ *
+ * This function serves as the unified entry point for sending CAN messages.
+ * It intelligently routes the request to either a blocking or non-blocking
+ * transmission function based on:
+ * 1. The calling context (thread or ISR).
+ * 2. A user-specified flag (`nonblocking`) in the message structure.
+ *
+ * @param[in] dev     A pointer to the device object.
+ * @param[in] pos     This parameter is ignored for CAN devices.
+ * @param[in] buffer  A pointer to the buffer containing one or more `rt_can_msg` structures.
+ * @param[in] size    The total size of the buffer in bytes. Must be a multiple of `sizeof(struct rt_can_msg)`.
+ *
+ * @return The number of bytes successfully written. For non-blocking sends, this means
+ *         the data was either sent directly or enqueued in the buffer.
+ */
 static rt_ssize_t rt_can_write(struct rt_device *dev,
                               rt_off_t          pos,
                               const void       *buffer,
                               rt_size_t         size)
 {
     struct rt_can_device *can;
+    const struct rt_can_msg *pmsg;
 
     RT_ASSERT(dev != RT_NULL);
-    if (size == 0) return 0;
+    RT_ASSERT(buffer != RT_NULL);
+
+    if (size == 0) return -RT_EINVAL;
+
+    /* Ensure size is a multiple of the message size for buffer operations */
+    if (size % sizeof(struct rt_can_msg) != 0)
+    {
+        return -RT_EINVAL;
+    }
 
     can = (struct rt_can_device *)dev;
+    pmsg = (const struct rt_can_msg *)buffer;
+
+    if(dev->ref_count == 0)
+    {
+        return -RT_ENOSYS;
+    }
 
-    if ((dev->open_flag & RT_DEVICE_FLAG_INT_TX) && (dev->ref_count > 0))
+    /*
+     * Routing to the non-blocking send scenario:
+     * 1. Called from within an interrupt context.
+     * 2. Called from a thread, but the user explicitly set the nonblocking flag on the first message.
+     */
+    if (rt_interrupt_get_nest() > 0 || pmsg->nonblocking)
+    {
+        return _can_nonblocking_tx(can, pmsg, size);
+    }
+
+    if (dev->open_flag & RT_DEVICE_FLAG_INT_TX)
     {
         if (can->config.privmode)
         {
@@ -496,7 +667,7 @@ static rt_ssize_t rt_can_write(struct rt_device *dev,
             return _can_int_tx(can, buffer, size);
         }
     }
-    return 0;
+    return -RT_ENOSYS;
 }
 
 static rt_err_t rt_can_control(struct rt_device *dev,
@@ -542,7 +713,7 @@ static rt_err_t rt_can_control(struct rt_device *dev,
             {
                 for (i = 0;  i < can->config.sndboxnumber; i++)
                 {
-                    level = rt_hw_interrupt_disable();
+                    level = rt_hw_local_irq_disable();
                     if(rt_list_isempty(&tx_fifo->buffer[i].list))
                     {
                         rt_sem_release(&(tx_fifo->sem));
@@ -551,7 +722,7 @@ static rt_err_t rt_can_control(struct rt_device *dev,
                     {
                         rt_list_remove(&tx_fifo->buffer[i].list);
                     }
-                    rt_hw_interrupt_enable(level);
+                    rt_hw_local_irq_enable(level);
                 }
 
             }
@@ -559,12 +730,12 @@ static rt_err_t rt_can_control(struct rt_device *dev,
             {
                 for (i = 0;  i < can->config.sndboxnumber; i++)
                 {
-                    level = rt_hw_interrupt_disable();
+                    level = rt_hw_local_irq_disable();
                     if (tx_fifo->buffer[i].result == RT_CAN_SND_RESULT_OK)
                     {
                         rt_list_insert_before(&tx_fifo->freelist, &tx_fifo->buffer[i].list);
                     }
-                    rt_hw_interrupt_enable(level);
+                    rt_hw_local_irq_enable(level);
                 }
             }
         }
@@ -603,18 +774,18 @@ static rt_err_t rt_can_control(struct rt_device *dev,
                     continue;
                 }
 
-                level = rt_hw_interrupt_disable();
+                level = rt_hw_local_irq_disable();
                 if (!can->hdr[pitem->hdr_bank].connected)
                 {
-                    rt_hw_interrupt_enable(level);
+                    rt_hw_local_irq_enable(level);
                     rt_memcpy(&can->hdr[pitem->hdr_bank].filter, pitem,
                               sizeof(struct rt_can_filter_item));
-                    level = rt_hw_interrupt_disable();
+                    level = rt_hw_local_irq_disable();
                     can->hdr[pitem->hdr_bank].connected = 1;
                     can->hdr[pitem->hdr_bank].msgs = 0;
                     rt_list_init(&can->hdr[pitem->hdr_bank].list);
                 }
-                rt_hw_interrupt_enable(level);
+                rt_hw_local_irq_enable(level);
 
                 count--;
                 pitem++;
@@ -630,7 +801,7 @@ static rt_err_t rt_can_control(struct rt_device *dev,
                     pitem++;
                     continue;
                 }
-                level = rt_hw_interrupt_disable();
+                level = rt_hw_local_irq_disable();
 
                 if (can->hdr[pitem->hdr_bank].connected)
                 {
@@ -640,13 +811,13 @@ static rt_err_t rt_can_control(struct rt_device *dev,
                     {
                         rt_list_remove(can->hdr[pitem->hdr_bank].list.next);
                     }
-                    rt_hw_interrupt_enable(level);
+                    rt_hw_local_irq_enable(level);
                     rt_memset(&can->hdr[pitem->hdr_bank].filter, 0,
                               sizeof(struct rt_can_filter_item));
                 }
                 else
                 {
-                    rt_hw_interrupt_enable(level);
+                    rt_hw_local_irq_enable(level);
                 }
                 count--;
                 pitem++;
@@ -675,8 +846,17 @@ static rt_err_t rt_can_control(struct rt_device *dev,
     return res;
 }
 
-/*
- * can timer
+/**
+ * @internal
+ * @brief Periodic timer callback for the CAN device.
+ *
+ * This function is executed periodically by a system timer. Its main purposes are:
+ * 1. To query the current status of the CAN controller (e.g., error counters, bus state).
+ * 2. To invoke a user-registered status indicator callback, if any.
+ * 3. To call a user-registered bus hook function for periodic tasks, if any.
+ *
+ * @param[in] arg The argument passed to the callback, which is a pointer to the `rt_can_device`.
+ * @return void
  */
 static void cantimeout(void *arg)
 {
@@ -740,6 +920,10 @@ rt_err_t rt_hw_can_register(struct rt_can_device    *can,
     can->bus_hook       = RT_NULL;
 #endif /*RT_CAN_USING_BUS_HOOK*/
 
+#ifdef RT_CAN_MALLOC_NB_TX_BUFFER
+    can->nb_tx_rb_pool = RT_NULL;
+#endif
+
 #ifdef RT_USING_DEVICE_OPS
     device->ops         = &can_device_ops;
 #else
@@ -770,6 +954,17 @@ rt_err_t rt_hw_can_register(struct rt_can_device    *can,
 }
 
 /* ISR for can interrupt */
+/**
+ * @brief The framework-level ISR handler for CAN devices.
+ *
+ * This function is called by the low-level BSP ISR and acts as the central
+ * dispatcher for all CAN-related interrupt events. It handles both receive
+ * events and transmission-complete events.
+ *
+ * @param[in] can    A pointer to the CAN device structure.
+ * @param[in] event  The interrupt event mask, indicating the cause of the interrupt.
+ * @return void
+ */
 void rt_hw_can_isr(struct rt_can_device *can, int event)
 {
     switch (event & 0xff)
@@ -777,9 +972,9 @@ void rt_hw_can_isr(struct rt_can_device *can, int event)
     case RT_CAN_EVENT_RXOF_IND:
     {
         rt_base_t level;
-        level = rt_hw_interrupt_disable();
+        level = rt_hw_local_irq_disable();
         can->status.dropedrcvpkg++;
-        rt_hw_interrupt_enable(level);
+        rt_hw_local_irq_enable(level);
     }
     case RT_CAN_EVENT_RX_IND:
     {
@@ -803,7 +998,7 @@ void rt_hw_can_isr(struct rt_can_device *can, int event)
         if (ch == -1) break;
 
         /* disable interrupt */
-        level = rt_hw_interrupt_disable();
+        level = rt_hw_local_irq_disable();
         can->status.rcvpkg++;
         can->status.rcvchange = 1;
         if (!rt_list_isempty(&rx_fifo->freelist))
@@ -836,12 +1031,12 @@ void rt_hw_can_isr(struct rt_can_device *can, int event)
 #endif
         }
         /* enable interrupt */
-        rt_hw_interrupt_enable(level);
+        rt_hw_local_irq_enable(level);
 
         if (listmsg != RT_NULL)
         {
             rt_memcpy(&listmsg->data, &tmpmsg, sizeof(struct rt_can_msg));
-            level = rt_hw_interrupt_disable();
+            level = rt_hw_local_irq_disable();
             rt_list_insert_before(&rx_fifo->uselist, &listmsg->list);
 #ifdef RT_CAN_USING_HDR
             hdr = tmpmsg.hdr_index;
@@ -857,7 +1052,7 @@ void rt_hw_can_isr(struct rt_can_device *can, int event)
 
             }
 #endif
-            rt_hw_interrupt_enable(level);
+            rt_hw_local_irq_enable(level);
         }
 
         /* invoke callback */
@@ -867,9 +1062,9 @@ void rt_hw_can_isr(struct rt_can_device *can, int event)
             rt_size_t rx_length;
             RT_ASSERT(hdr < can->config.maxhdr && hdr >= 0);
 
-            level = rt_hw_interrupt_disable();
+            level = rt_hw_local_irq_disable();
             rx_length = can->hdr[hdr].msgs * sizeof(struct rt_can_msg);
-            rt_hw_interrupt_enable(level);
+            rt_hw_local_irq_enable(level);
             if (rx_length)
             {
                 can->hdr[hdr].filter.ind(&can->parent, can->hdr[hdr].filter.args, hdr, rx_length);
@@ -882,10 +1077,10 @@ void rt_hw_can_isr(struct rt_can_device *can, int event)
             {
                 rt_size_t rx_length;
 
-                level = rt_hw_interrupt_disable();
+                level = rt_hw_local_irq_disable();
                 /* get rx length */
                 rx_length = rt_list_len(&rx_fifo->uselist)* sizeof(struct rt_can_msg);
-                rt_hw_interrupt_enable(level);
+                rt_hw_local_irq_enable(level);
 
                 if (rx_length)
                 {
@@ -904,6 +1099,7 @@ 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 (can->status.sndchange&(1<<no))
         {
             if ((event & 0xff) == RT_CAN_EVENT_TX_DONE)
@@ -916,6 +1112,37 @@ void rt_hw_can_isr(struct rt_can_device *can, int event)
             }
             rt_completion_done(&(tx_fifo->buffer[no].completion));
         }
+
+        if (can->ops->sendmsg_nonblocking != RT_NULL)
+        {
+            while (RT_TRUE)
+            {
+                struct rt_can_msg msg_to_send;
+                rt_base_t level;
+                rt_bool_t msg_was_present = RT_FALSE;
+
+                level = rt_hw_local_irq_disable();
+                if (rt_ringbuffer_data_len(&can->nb_tx_rb) >= sizeof(struct rt_can_msg))
+                {
+                    rt_ringbuffer_get(&can->nb_tx_rb, (rt_uint8_t *)&msg_to_send, sizeof(struct rt_can_msg));
+                    msg_was_present = RT_TRUE;
+                }
+                rt_hw_local_irq_enable(level);
+
+                if (!msg_was_present)
+                {
+                    break;
+                }
+
+                if (can->ops->sendmsg_nonblocking(can, &msg_to_send) != RT_EOK)
+                {
+                    level = rt_hw_local_irq_disable();
+                    rt_ringbuffer_put_force(&can->nb_tx_rb, (rt_uint8_t *)&msg_to_send, sizeof(struct rt_can_msg));
+                    rt_hw_local_irq_enable(level);
+                    break;
+                }
+            }
+        }
         break;
     }
     }

+ 355 - 192
components/drivers/include/drivers/dev_can.h

@@ -8,12 +8,14 @@
  * 2015-05-14     aubrcool@qq.com   first version
  * 2015-07-06     Bernard           remove RT_CAN_USING_LED.
  * 2022-05-08     hpmicro           add CANFD support, fixed typos
+ * 2025-09-20     wdfk_prog         Added non-blocking send mechanism APIs and data structures.
  */
 
 #ifndef __DEV_CAN_H_
 #define __DEV_CAN_H_
 
 #include <rtthread.h>
+#include <rtdevice.h>
 
 #ifndef RT_CANMSG_BOX_SZ
 #define RT_CANMSG_BOX_SZ    16
@@ -71,77 +73,88 @@ enum CANBAUD
  * @brief       CAN driver api
  * @ingroup     group_device_driver
  *
- * <b>Example</b>
+ * <b>Example: Demonstrating CAN RX, Filters, and Blocking/Non-Blocking TX</b>
  * @code {.c}
  * #include <rtthread.h>
- * #include "rtdevice.h"
+ * #include <rtdevice.h>
  *
- * #define CAN_DEV_NAME       "can1"      // CAN 设备名称
+ * #define CAN_DEV_NAME       "can1"      // The name of the CAN device
  *
- * static struct rt_semaphore rx_sem;     // 用于接收消息的信号量
- * static rt_device_t can_dev;            // CAN 设备句柄
+ * static rt_device_t can_dev;            // CAN device handle
+ * static struct rt_semaphore rx_sem;     // Semaphore for message reception
  *
- * // 接收数据回调函数
- * static rt_err_t can_rx_call(rt_device_t dev, rt_size_t size)
+ * // Callback function for CAN reception
+ * static rt_err_t can_rx_callback(rt_device_t dev, rt_size_t size)
  * {
- *     // CAN 接收到数据后产生中断,调用此回调函数,然后发送接收信号量
+ *     // The CAN interrupt calls this callback when data is received.
+ *     // Release the semaphore to notify the receiving thread.
  *     rt_sem_release(&rx_sem);
- *
  *     return RT_EOK;
  * }
  *
  * static void can_rx_thread(void *parameter)
  * {
- *     int i;
  *     rt_err_t res;
- *     struct rt_can_msg rxmsg = {0};
+ *     struct rt_can_msg rx_msg = {0};
  *
- *     // 设置接收回调函数
- *     rt_device_set_rx_indicate(can_dev, can_rx_call);
+ *     // Set the receive callback function
+ *     rt_device_set_rx_indicate(can_dev, can_rx_callback);
  *
  * #ifdef RT_CAN_USING_HDR
- *     struct rt_can_filter_item items[5] =
+ *     // Example of configuring multiple hardware filters
+ *     struct rt_can_filter_item items[] =
  *     {
- *         RT_CAN_FILTER_ITEM_INIT(0x100, 0, 0, 0, 0x700, RT_NULL, RT_NULL), // std,match ID:0x100~0x1ff,hdr 为 - 1,设置默认过滤表
- *         RT_CAN_FILTER_ITEM_INIT(0x300, 0, 0, 0, 0x700, RT_NULL, RT_NULL), // std,match ID:0x300~0x3ff,hdr 为 - 1
- *         RT_CAN_FILTER_ITEM_INIT(0x211, 0, 0, 0, 0x7ff, RT_NULL, RT_NULL), // std,match ID:0x211,hdr 为 - 1
- *         RT_CAN_FILTER_STD_INIT(0x486, RT_NULL, RT_NULL),                  // std,match ID:0x486,hdr 为 - 1
- *         {0x555, 0, 0, 0, 0x7ff, 7,}                                       // std,match ID:0x555,hdr 为 7,指定设置 7 号过滤表
+ *         // Filter 1: Match standard frames with IDs from 0x100 to 0x1FF. hdr_index will be -1.
+ *         RT_CAN_FILTER_ITEM_INIT(0x100, 0, 0, 0, 0x700, RT_NULL, RT_NULL),
+ *         // Filter 2: Match standard frames with IDs from 0x300 to 0x3FF. hdr_index will be -1.
+ *         RT_CAN_FILTER_ITEM_INIT(0x300, 0, 0, 0, 0x700, RT_NULL, RT_NULL),
+ *         // Filter 3: Exactly match standard frame with ID 0x211. hdr_index will be -1.
+ *         RT_CAN_FILTER_ITEM_INIT(0x211, 0, 0, 0, 0x7FF, RT_NULL, RT_NULL),
+ *         // Filter 4: Exactly match standard frame with ID 0x486 using a helper macro. hdr_index will be -1.
+ *         RT_CAN_FILTER_STD_INIT(0x486, RT_NULL, RT_NULL),
+ *         // Filter 5: Exactly match standard frame with ID 0x555 and explicitly assign it to filter bank #7.
+ *         // This uses direct struct initialization: {id, ide, rtr, mode, mask, hdr_bank}.
+ *         {0x555, 0, 0, 0, 0x7FF, 7}
  *     };
- *     struct rt_can_filter_config cfg = {5, 1, items}; // 一共有 5 个过滤表
- *     // 设置硬件过滤表
+ *     // Create the filter configuration structure with 5 active filters.
+ *     struct rt_can_filter_config cfg = {sizeof(items)/sizeof(items[0]), 1, items};
+ *     // Set the hardware filters for the CAN device.
  *     res = rt_device_control(can_dev, RT_CAN_CMD_SET_FILTER, &cfg);
  *     RT_ASSERT(res == RT_EOK);
  * #endif
- *     res = RT_TRUE;
- *     res = rt_device_control(can_dev, RT_CAN_CMD_START, &res);
+ *
+ *     // Some drivers might require an explicit start command.
+ *     // This is driver-specific.
+ *     rt_uint32_t cmd_arg = 1; // Argument to enable the controller
+ *     res = rt_device_control(can_dev, RT_CAN_CMD_START, &cmd_arg);
+ *     RT_ASSERT(res == RT_EOK);
+ *
  *     while (1)
  *     {
- *         // hdr 值为 - 1,表示直接从 uselist 链表读取数据
- *         rxmsg.hdr = -1;
- *         // 阻塞等待接收信号量
+ *         // Block and wait for the semaphore, which is released by the receive callback.
  *         rt_sem_take(&rx_sem, RT_WAITING_FOREVER);
- *         // 从 CAN 读取一帧数据
- *         rt_device_read(can_dev, 0, &rxmsg, sizeof(rxmsg));
- *         // 打印数据 ID 及内容
- *         rt_kprintf("ID:%x", rxmsg.id);
- *         for (i = 0; i < 8; i++)
+ *
+ *         // Read one frame of data from the CAN device's general message queue.
+ *         rx_msg.hdr_index = -1;
+ *         rt_device_read(can_dev, 0, &rx_msg, sizeof(rx_msg));
+ *
+ *         // Print the received message's ID and data.
+ *         rt_kprintf("Received a message. ID: 0x%x, Data: ", rx_msg.id);
+ *         for (int i = 0; i < rx_msg.len; i++)
  *         {
- *             rt_kprintf("%2x", rxmsg.data[i]);
+ *             rt_kprintf("%02x ", rx_msg.data[i]);
  *         }
- *
  *         rt_kprintf("\n");
  *     }
  * }
  *
  * int can_sample(int argc, char *argv[])
  * {
- *     struct rt_can_msg msg = {0};
  *     rt_err_t res;
- *     rt_size_t  size;
  *     rt_thread_t thread;
  *     char can_name[RT_NAME_MAX];
  *
+ *     // Allow specifying the CAN device name from the command line, e.g., "can_sample can2"
  *     if (argc == 2)
  *     {
  *         rt_strncpy(can_name, argv[1], RT_NAME_MAX);
@@ -150,21 +163,23 @@ enum CANBAUD
  *     {
  *         rt_strncpy(can_name, CAN_DEV_NAME, RT_NAME_MAX);
  *     }
- *     // 查找 CAN 设备
+ *
+ *     // Find the CAN device by name
  *     can_dev = rt_device_find(can_name);
  *     if (!can_dev)
  *     {
- *         rt_kprintf("find %s failed!\n", can_name);
+ *         rt_kprintf("find device %s failed!\n", can_name);
  *         return -RT_ERROR;
  *     }
  *
- *     // 初始化 CAN 接收信号量
+ *     // Initialize the receive semaphore
  *     rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
  *
- *     // 以中断接收及发送方式打开 CAN 设备
+ *     // Open the CAN device in interrupt-driven TX/RX mode
  *     res = rt_device_open(can_dev, RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX);
  *     RT_ASSERT(res == RT_EOK);
- *     // 创建数据接收线程
+ *
+ *     // Create and start the data receiving thread
  *     thread = rt_thread_create("can_rx", can_rx_thread, RT_NULL, 1024, 25, 10);
  *     if (thread != RT_NULL)
  *     {
@@ -173,36 +188,61 @@ enum CANBAUD
  *     else
  *     {
  *         rt_kprintf("create can_rx thread failed!\n");
+ *         return -RT_ERROR;
  *     }
  *
- *     msg.id = 0x78;              // ID 为 0x78
- *     msg.ide = RT_CAN_STDID;     // 标准格式
- *     msg.rtr = RT_CAN_DTR;       // 数据帧
- *     msg.len = 8;                // 数据长度为 8
- *     // 待发送的 8 字节数据
- *     msg.data[0] = 0x00;
- *     msg.data[1] = 0x11;
- *     msg.data[2] = 0x22;
- *     msg.data[3] = 0x33;
- *     msg.data[4] = 0x44;
- *     msg.data[5] = 0x55;
- *     msg.data[6] = 0x66;
- *     msg.data[7] = 0x77;
- *     // 发送一帧 CAN 数据
- *     size = rt_device_write(can_dev, 0, &msg, sizeof(msg));
- *     if (size == 0)
+ *     rt_kprintf("CAN device %s opened successfully.\n", can_name);
+ *
+ *     // --- Demonstrate Blocking Send ---
+ *     struct rt_can_msg blocking_msg = {0};
+ *     blocking_msg.id = 0x78;
+ *     blocking_msg.ide = RT_CAN_STDID;
+ *     blocking_msg.rtr = RT_CAN_DTR;
+ *     blocking_msg.len = 8;
+ *     // The `nonblocking` flag is 0 by default for blocking mode.
+ *     for(int i = 0; i < 8; i++) blocking_msg.data[i] = i;
+ *
+ *     rt_kprintf("Attempting to send a message in BLOCKING mode...\n");
+ *     if (rt_device_write(can_dev, 0, &blocking_msg, sizeof(blocking_msg)) == sizeof(blocking_msg))
+ *     {
+ *         rt_kprintf("Blocking message sent successfully.\n");
+ *     }
+ *     else
+ *     {
+ *         rt_kprintf("Blocking message send failed.\n");
+ *     }
+ *
+ *     rt_thread_mdelay(100); // Wait a moment for clarity in the log
+ *
+ *     // --- Demonstrate Non-Blocking Send ---
+ *     struct rt_can_msg nonblocking_msg = {0};
+ *     nonblocking_msg.id = 0x79;
+ *     nonblocking_msg.ide = RT_CAN_STDID;
+ *     nonblocking_msg.rtr = RT_CAN_DTR;
+ *     nonblocking_msg.len = 4;
+ *     nonblocking_msg.data[0] = 0xDE;
+ *     nonblocking_msg.data[1] = 0xAD;
+ *     nonblocking_msg.data[2] = 0xBE;
+ *     nonblocking_msg.data[3] = 0xEF;
+ *     nonblocking_msg.nonblocking = 1; // <-- Key: Set the non-blocking flag
+ *
+ *     rt_kprintf("Attempting to send a message in NON-BLOCKING mode...\n");
+ *     if (rt_device_write(can_dev, 0, &nonblocking_msg, sizeof(nonblocking_msg)) == sizeof(nonblocking_msg))
  *     {
- *         rt_kprintf("can dev write data failed!\n");
+ *         rt_kprintf("Non-blocking message was accepted (sent or enqueued).\n");
+ *     }
+ *     else
+ *     {
+ *         rt_kprintf("Non-blocking send failed (buffer was full).\n");
  *     }
  *
  *     return res;
  * }
- * // 导出到 msh 命令列表中
- * MSH_CMD_EXPORT(can_sample, can device sample);
+ * // Export the function to the MSH command line
+ * MSH_CMD_EXPORT(can_sample, can device usage example);
  * @endcode
  */
 
-
 /*!
  * @addtogroup group_drivers_can
  * @{
@@ -211,27 +251,46 @@ enum CANBAUD
 #define CAN_RX_FIFO1                (0x00000001U)  /*!< CAN receive FIFO 1 */
 
 /**
- * @brief CAN filter item
+ * @brief CAN filter item structure
  */
 struct rt_can_filter_item
 {
-    rt_uint32_t id  : 29;
-    rt_uint32_t ide : 1;
-    rt_uint32_t rtr : 1;
-    rt_uint32_t mode : 1;
-    rt_uint32_t mask;
-    rt_int32_t  hdr_bank;/*Should be defined as:rx.FilterBank,which should be changed to rt_int32_t hdr_bank*/
-    rt_uint32_t rxfifo;/*Add a configuration item that CAN_RX_FIFO0/CAN_RX_FIFO1*/
+    rt_uint32_t id  : 29;   /**< The CAN ID to be filtered. */
+    rt_uint32_t ide : 1;    /**< Identifier type. 0 for Standard ID, 1 for Extended ID. */
+    rt_uint32_t rtr : 1;    /**< Frame type. 0 for Data Frame, 1 for Remote Frame. */
+    rt_uint32_t mode : 1;   /**< Filter mode. 0 for Mask Mode, 1 for List Mode. */
+    rt_uint32_t mask;       /**< The filter mask. In Mask Mode, a '1' bit means the corresponding ID bit must match. */
+    rt_int32_t  hdr_bank;   /**< The specific hardware filter bank index to use. A value of -1 allows the driver to auto-assign. */
+    rt_uint32_t rxfifo;     /**< The target RX FIFO for matched messages (CAN_RX_FIFO0 or CAN_RX_FIFO1). */
 #ifdef RT_CAN_USING_HDR
+    /**
+     * @brief Callback function for a specific filter.
+     * @param[in] dev   The CAN device that triggered the callback.
+     * @param[in] args  User-provided arguments.
+     * @param[in] hdr   The hardware filter index that matched the message.
+     * @param[in] size  The size of the received data in bytes.
+     * @return The operation status.
+     */
     rt_err_t (*ind)(rt_device_t dev, void *args , rt_int32_t hdr, rt_size_t size);
-    void *args;
+    void *args;             /**< User arguments for the indication callback. */
 #endif /*RT_CAN_USING_HDR*/
 };
 
-
+/**
+ * @def RT_CAN_FILTER_ITEM_INIT
+ * @brief A helper macro to initialize a `rt_can_filter_item` structure for Mask Mode.
+ *
+ * @param[in] _id   The CAN ID for the filter.
+ * @param[in] _ide  Identifier type (0 for Standard, 1 for Extended).
+ * @param[in] _rtr  Frame type (0 for Data, 1 for Remote).
+ * @param[in] _mode Filter mode (0 for Mask, 1 for List).
+ * @param[in] _mask The mask to be applied.
+ * @param[in] _ind  Optional callback function (can be RT_NULL).
+ * @param[in] _args Optional arguments for the callback (can be RT_NULL).
+ */
 #ifdef RT_CAN_USING_HDR
 #define RT_CAN_FILTER_ITEM_INIT(id,ide,rtr,mode,mask,ind,args) \
-      {(id), (ide), (rtr), (mode),(mask), -1, CAN_RX_FIFO0,(ind), (args)}/*0:CAN_RX_FIFO0*/
+      {(id), (ide), (rtr), (mode),(mask), -1, CAN_RX_FIFO0,(ind), (args)}
 #define RT_CAN_FILTER_STD_INIT(id,ind,args) \
      RT_CAN_FILTER_ITEM_INIT(id,0,0,0,0xFFFFFFFF,ind,args)
 #define RT_CAN_FILTER_EXT_INIT(id,ind,args) \
@@ -245,9 +304,8 @@ struct rt_can_filter_item
 #define RT_CAN_EXT_RMT_DATA_FILTER_INIT(id,ind,args) \
      RT_CAN_FILTER_ITEM_INIT(id,1,0,1,0xFFFFFFFF,ind,args)
 #else
-
 #define RT_CAN_FILTER_ITEM_INIT(id,ide,rtr,mode,mask) \
-      {(id), (ide), (rtr), (mode), (mask), -1, CAN_RX_FIFO0 }/*0:CAN_RX_FIFO0*/
+      {(id), (ide), (rtr), (mode), (mask), -1, CAN_RX_FIFO0 }
 #define RT_CAN_FILTER_STD_INIT(id) \
      RT_CAN_FILTER_ITEM_INIT(id,0,0,0,0xFFFFFFFF)
 #define RT_CAN_FILTER_EXT_INIT(id) \
@@ -264,65 +322,65 @@ struct rt_can_filter_item
 
 
 /**
- * @brief CAN filter configuration
+ * @brief CAN hardware filter configuration structure.
+ * This structure is passed to the driver via `rt_device_control` with the `RT_CAN_CMD_SET_FILTER` command.
  */
 struct rt_can_filter_config
 {
-    rt_uint32_t count;
-    rt_uint32_t actived;
-    struct rt_can_filter_item *items;
+    rt_uint32_t count;                /**< The number of filter items in the `items` array. */
+    rt_uint32_t actived;              /**< A flag to activate (1) or deactivate (0) the filters. */
+    struct rt_can_filter_item *items; /**< A pointer to an array of filter items. */
 };
 
 /**
- * @brief CAN timing configuration
+ * @brief CAN bit-timing parameters structure.
  */
 struct rt_can_bit_timing
 {
-    rt_uint16_t prescaler;  /* Pre-scaler */
-    rt_uint16_t num_seg1;   /* Bit Timing Segment 1, in terms of Tq */
-    rt_uint16_t num_seg2;   /* Bit Timing Segment 2, in terms of Tq */
-    rt_uint8_t num_sjw;     /* Synchronization Jump Width, in terms of Tq */
-    rt_uint8_t num_sspoff;  /* Secondary Sample Point Offset, in terms of Tq */
+    rt_uint16_t prescaler;  /**< Baud rate prescaler. */
+    rt_uint16_t num_seg1;   /**< Bit Timing Segment 1, in terms of Time Quanta (Tq). */
+    rt_uint16_t num_seg2;   /**< Bit Timing Segment 2, in terms of Time Quanta (Tq). */
+    rt_uint8_t num_sjw;     /**< Synchronization Jump Width, in terms of Time Quanta (Tq). */
+    rt_uint8_t num_sspoff;  /**< Secondary Sample Point Offset, in terms of Time Quanta (Tq) for CAN-FD. */
 };
 
 /**
- * @brief CAN bit timing configuration list
- * @note
- *  items[0] always for CAN2.0/CANFD Arbitration Phase
- *  items[1] always for CANFD (if it exists)
+ * @brief CAN bit timing configuration list structure.
+ * @note items[0] is for CAN 2.0 / CAN-FD Arbitration Phase.
+ *       items[1] is for CAN-FD Data Phase (if applicable).
  */
 struct rt_can_bit_timing_config
 {
-    rt_uint32_t count;
-    struct rt_can_bit_timing *items;
+    rt_uint32_t count;                  /**< The number of bit-timing configurations (typically 1 for CAN, 2 for CAN-FD). */
+    struct rt_can_bit_timing *items;    /**< A pointer to an array of bit-timing structures. */
 };
 
 
 /**
- * @brief CAN configuration
+ * @brief CAN device configuration structure.
  */
 struct can_configure
 {
-    rt_uint32_t baud_rate;
-    rt_uint32_t msgboxsz;
-    rt_uint32_t sndboxnumber;
-    rt_uint32_t mode      : 8;
-    rt_uint32_t privmode  : 8;
-    rt_uint32_t reserved  : 16;
-    rt_uint32_t ticks;
+    rt_uint32_t baud_rate;      /**< The baud rate for the arbitration phase (e.g., CAN500kBaud). */
+    rt_uint32_t msgboxsz;       /**< The size of the software receive buffer (in number of messages). */
+    rt_uint32_t sndboxnumber;   /**< The number of hardware mailboxes used for blocking send operations. */
+    rt_uint32_t mode      : 8;  /**< The CAN operation mode (e.g., RT_CAN_MODE_NORMAL, RT_CAN_MODE_LOOPBACK). */
+    rt_uint32_t privmode  : 8;  /**< Private mode flag. If set, the `priv` field of `rt_can_msg` specifies the hardware mailbox. */
+    rt_uint32_t reserved  : 16; /**< Reserved for future use. */
+    rt_uint32_t ticks;          /**< The period in OS ticks for the status-checking timer. */
 #ifdef RT_CAN_USING_HDR
-    rt_uint32_t maxhdr;
+    rt_uint32_t maxhdr;         /**< The maximum number of hardware filters supported by the controller. */
 #endif
 
 #ifdef RT_CAN_USING_CANFD
-    rt_uint32_t baud_rate_fd;       /* CANFD data bit rate*/
-    rt_uint32_t use_bit_timing: 8;  /* Use the bit timing for CAN timing configuration */
-    rt_uint32_t enable_canfd : 8;   /* Enable CAN-FD mode */
-    rt_uint32_t reserved1 : 16;
+    rt_uint32_t baud_rate_fd;       /**< The baud rate for the CAN-FD data phase. */
+    rt_uint32_t use_bit_timing: 8;  /**< A flag to indicate that `can_timing` and `canfd_timing` should be used instead of `baud_rate`. */
+    rt_uint32_t enable_canfd : 8;   /**< A flag to enable CAN-FD functionality. */
+    rt_uint32_t reserved1 : 16;     /**< Reserved for future use. */
 
     /* The below fields take effect only if use_bit_timing is non-zero */
-    struct rt_can_bit_timing can_timing;    /* CAN bit-timing /CANFD bit-timing for arbitration phase */
-    struct rt_can_bit_timing canfd_timing;  /* CANFD bit-timing for datat phase */
+    struct rt_can_bit_timing can_timing;    /**< Custom bit-timing for the arbitration phase. */
+    struct rt_can_bit_timing canfd_timing;  /**< Custom bit-timing for the data phase. */
 #endif
 };
 
@@ -368,66 +426,130 @@ enum RT_CAN_BUS_ERR
 };
 
 /**
- * @brief CAN status
+ * @brief CAN device status and error statistics structure.
  */
 struct rt_can_status
 {
-    rt_uint32_t rcverrcnt;
-    rt_uint32_t snderrcnt;
-    rt_uint32_t errcode;
-    rt_uint32_t rcvpkg;
-    rt_uint32_t dropedrcvpkg;
-    rt_uint32_t sndpkg;
-    rt_uint32_t dropedsndpkg;
-    rt_uint32_t bitpaderrcnt;
-    rt_uint32_t formaterrcnt;
-    rt_uint32_t ackerrcnt;
-    rt_uint32_t biterrcnt;
-    rt_uint32_t crcerrcnt;
-    rt_uint32_t rcvchange;
-    rt_uint32_t sndchange;
-    rt_uint32_t lasterrtype;
+    rt_uint32_t rcverrcnt;      /**< Receive Error Counter (REC). */
+    rt_uint32_t snderrcnt;      /**< Transmit Error Counter (TEC). */
+    rt_uint32_t errcode;        /**< The current bus error code (see `enum RT_CAN_BUS_ERR`). */
+    rt_uint32_t rcvpkg;         /**< Total number of successfully received packages. */
+    rt_uint32_t dropedrcvpkg;   /**< Number of received packages dropped due to full buffers. */
+    rt_uint32_t sndpkg;         /**< Total number of successfully sent packages. */
+    rt_uint32_t dropedsndpkg;   /**< Number of sent packages dropped due to full buffers or errors. */
+    rt_uint32_t bitpaderrcnt;   /**< Bit stuffing error count. */
+    rt_uint32_t formaterrcnt;   /**< Format error count. */
+    rt_uint32_t ackerrcnt;      /**< Acknowledgment error count. */
+    rt_uint32_t biterrcnt;      /**< Bit error (recessive/dominant) count. */
+    rt_uint32_t crcerrcnt;      /**< CRC error count. */
+    rt_uint32_t rcvchange;      /**< A flag indicating that the RX buffer status has changed. */
+    rt_uint32_t sndchange;      /**< A bitmask indicating which TX mailboxes have changed status. */
+    rt_uint32_t lasterrtype;    /**< The type of the last error that occurred. */
 };
 
 #ifdef RT_CAN_USING_HDR
+/**
+ * @brief CAN hardware filter list entry.
+ * @internal
+ */
 struct rt_can_hdr
 {
-    rt_uint32_t connected;
-    rt_uint32_t msgs;
-    struct rt_can_filter_item filter;
-    struct rt_list_node list;
+    rt_uint32_t connected;            /**< Flag indicating if the filter is connected to a specific list. */
+    rt_uint32_t msgs;                 /**< The number of messages currently buffered for this filter. */
+    struct rt_can_filter_item filter; /**< A copy of the filter configuration item. */
+    struct rt_list_node list;         /**< The list head for messages matched by this filter. */
 };
 #endif
 struct rt_can_device;
-typedef rt_err_t (*rt_canstatus_ind)(struct rt_can_device *, void *);
+/**
+ * @brief Typedef for the CAN status indication callback function.
+ * @param[in] can  A pointer to the CAN device.
+ * @param[in] args User-provided arguments.
+ * @return The operation status.
+ */
+typedef rt_err_t (*rt_canstatus_ind)(struct rt_can_device *can, void *args);
 
+/**
+ * @brief Structure to hold the status indication callback and its arguments.
+ */
 typedef struct rt_can_status_ind_type
 {
-    rt_canstatus_ind ind;
-    void *args;
+    rt_canstatus_ind ind;   /**< Pointer to the status indication callback function. */
+    void *args;             /**< Pointer to user arguments for the callback. */
 } *rt_can_status_ind_type_t;
-typedef void (*rt_can_bus_hook)(struct rt_can_device *);
+
+/**
+ * @brief Typedef for the periodic bus hook function.
+ * @param[in] can A pointer to the CAN device.
+ * @return void
+ */
+typedef void (*rt_can_bus_hook)(struct rt_can_device *can);
+
+/**
+ * @brief The CAN message structure.
+ */
+struct rt_can_msg
+{
+    rt_uint32_t id  : 29;           /**< CAN ID (Standard or Extended). */
+    rt_uint32_t ide : 1;            /**< Identifier type: 0=Standard ID, 1=Extended ID. */
+    rt_uint32_t rtr : 1;            /**< Frame type: 0=Data Frame, 1=Remote Frame. */
+    rt_uint32_t rsv : 1;            /**< Reserved bit. */
+    rt_uint32_t len : 8;            /**< Data Length Code (DLC) from 0 to 8. */
+    rt_uint32_t priv : 8;           /**< Private data, used to specify the hardware mailbox in private mode. */
+    rt_int32_t hdr_index : 8;       /**< For received messages, the index of the hardware filter that matched the message. */
+#ifdef RT_CAN_USING_CANFD
+    rt_uint32_t fd_frame : 1;       /**< CAN-FD frame indicator. */
+    rt_uint32_t brs : 1;            /**< Bit-rate switching indicator for CAN-FD. */
+    rt_uint32_t rxfifo : 2;         /**< The RX FIFO where the message was received. */
+    rt_uint32_t reserved : 3;
+#else
+    rt_uint32_t rxfifo : 2;         /**< The RX FIFO where the message was received. */
+    rt_uint32_t reserved : 5;
+#endif
+    rt_uint32_t nonblocking : 1;    /**< Send mode: 0=Blocking (default), 1=Non-blocking. */
+#ifdef RT_CAN_USING_CANFD
+    rt_uint8_t data[64];            /**< CAN-FD message payload (up to 64 bytes). */
+#else
+    rt_uint8_t data[8];             /**< CAN message payload (up to 8 bytes). */
+#endif
+};
+typedef struct rt_can_msg *rt_can_msg_t;
+
+#ifndef RT_CAN_NB_TX_FIFO_SIZE
+#define RT_CAN_NB_TX_FIFO_SIZE   (RT_CANMSG_BOX_SZ * sizeof(struct rt_can_msg))
+#endif
+
+/**
+ * @brief The core CAN device structure.
+ */
 struct rt_can_device
 {
-    struct rt_device parent;
+    struct rt_device parent;            /**< Inherits from the base RT-Thread device structure. */
 
-    const struct rt_can_ops *ops;
-    struct can_configure config;
-    struct rt_can_status status;
+    const struct rt_can_ops *ops;       /**< A pointer to the low-level driver operations. */
+    struct can_configure config;        /**< The current configuration of the CAN device. */
+    struct rt_can_status status;        /**< The current status and error statistics of the CAN device. */
 
-    rt_uint32_t timerinitflag;
-    struct rt_timer timer;
+    rt_uint32_t timerinitflag;          /**< A flag to indicate if the status timer has been initialized. */
+    struct rt_timer timer;              /**< A timer for periodically checking the CAN bus status. */
 
-    struct rt_can_status_ind_type status_indicate;
+    struct rt_can_status_ind_type status_indicate; /**< The user-registered status indication callback. */
 #ifdef RT_CAN_USING_HDR
-    struct rt_can_hdr *hdr;
+    struct rt_can_hdr *hdr;             /**< A pointer to an array of hardware filter list entries. */
 #endif
 #ifdef RT_CAN_USING_BUS_HOOK
-    rt_can_bus_hook bus_hook;
+    rt_can_bus_hook bus_hook;           /**< The user-registered periodic bus hook function. */
 #endif /*RT_CAN_USING_BUS_HOOK*/
-    struct rt_mutex lock;
-    void *can_rx;
-    void *can_tx;
+    struct rt_mutex lock;               /**< A mutex for thread-safe access to the device. */
+    void *can_rx;                       /**< A pointer to the software receive FIFO structure (`rt_can_rx_fifo`). */
+    void *can_tx;                       /**< A pointer to the software transmit FIFO structure (`rt_can_tx_fifo`). */
+
+    struct rt_ringbuffer nb_tx_rb;      /**< The ring buffer for non-blocking transmissions. */
+#ifdef RT_CAN_MALLOC_NB_TX_BUFFER
+    rt_uint8_t *nb_tx_rb_pool;          /**< A pointer to the dynamically allocated pool for the non-blocking TX ring buffer. */
+#else
+    rt_uint8_t nb_tx_rb_pool[RT_CAN_NB_TX_FIFO_SIZE]; /**< The statically allocated pool for the non-blocking TX ring buffer. */
+#endif /* RT_CAN_MALLOC_NB_TX_BUFFER  */
 };
 typedef struct rt_can_device *rt_can_t;
 
@@ -438,49 +560,30 @@ typedef struct rt_can_device *rt_can_t;
 
 typedef struct rt_can_status *rt_can_status_t;
 
-struct rt_can_msg
-{
-    rt_uint32_t id  : 29;
-    rt_uint32_t ide : 1;
-    rt_uint32_t rtr : 1;
-    rt_uint32_t rsv : 1;
-    rt_uint32_t len : 8;
-    rt_uint32_t priv : 8;
-    rt_int32_t hdr_index : 8;/*Should be defined as:rx.FilterMatchIndex,which should be changed to rt_int32_t hdr_index : 8*/
-#ifdef RT_CAN_USING_CANFD
-    rt_uint32_t fd_frame : 1;
-    rt_uint32_t brs : 1;
-    rt_uint32_t rxfifo : 2;/*Redefined to return :CAN RX FIFO0/CAN RX FIFO1*/
-    rt_uint32_t reserved : 4;
-#else
-    rt_uint32_t rxfifo : 2;/*Redefined to return :CAN RX FIFO0/CAN RX FIFO1*/
-    rt_uint32_t reserved : 6;
-#endif
-#ifdef RT_CAN_USING_CANFD
-    rt_uint8_t data[64];
-#else
-    rt_uint8_t data[8];
-#endif
-};
-typedef struct rt_can_msg *rt_can_msg_t;
-
+/**
+ * @internal
+ * @brief List node for a single CAN message in a software FIFO.
+ */
 struct rt_can_msg_list
 {
-    struct rt_list_node list;
+    struct rt_list_node list;       /**< List node to link into a free/used list. */
 #ifdef RT_CAN_USING_HDR
-    struct rt_list_node hdrlist;
-    struct rt_can_hdr *owner;
+    struct rt_list_node hdrlist;    /**< List node to link into a specific hardware filter's list. */
+    struct rt_can_hdr *owner;       /**< Pointer to the hardware filter that owns this message. */
 #endif
-    struct rt_can_msg data;
+    struct rt_can_msg data;         /**< The actual CAN message data. */
 };
 
+/**
+ * @internal
+ * @brief Software receive FIFO structure.
+ */
 struct rt_can_rx_fifo
 {
-    /* software fifo */
-    struct rt_can_msg_list *buffer;
-    rt_uint32_t freenumbers;
-    struct rt_list_node freelist;
-    struct rt_list_node uselist;
+    struct rt_can_msg_list *buffer; /**< A pointer to the buffer pool of message list nodes. */
+    rt_uint32_t freenumbers;        /**< The number of free nodes in the buffer pool. */
+    struct rt_list_node freelist;   /**< The list of free message nodes. */
+    struct rt_list_node uselist;    /**< The list of used message nodes (containing received messages). */
 };
 
 #define RT_CAN_SND_RESULT_OK        0
@@ -493,40 +596,94 @@ struct rt_can_rx_fifo
 #define RT_CAN_EVENT_RX_TIMEOUT     0x05    /* Rx timeout    */
 #define RT_CAN_EVENT_RXOF_IND       0x06    /* Rx overflow */
 
+/**
+ * @internal
+ * @brief List node for a blocking send operation, corresponding to one hardware mailbox.
+ */
 struct rt_can_sndbxinx_list
 {
-    struct rt_list_node list;
-    struct rt_completion completion;
-    rt_uint32_t result;
+    struct rt_list_node list;       /**< List node to link into the free list. */
+    struct rt_completion completion;/**< A completion object to block the sending thread. */
+    rt_uint32_t result;             /**< The result of the transmission (OK, ERR, WAIT). */
 };
 
+/**
+ * @internal
+ * @brief Software transmit FIFO structure for blocking sends.
+ */
 struct rt_can_tx_fifo
 {
-    struct rt_can_sndbxinx_list *buffer;
-    struct rt_semaphore sem;
-    struct rt_list_node freelist;
+    struct rt_can_sndbxinx_list *buffer; /**< A pointer to the buffer of sendbox nodes. */
+    struct rt_semaphore sem;             /**< A counting semaphore representing available hardware mailboxes. */
+    struct rt_list_node freelist;        /**< The list of free sendbox nodes. */
 };
 
 /**
- * @brief CAN operators
+ * @brief The CAN device driver operations structure.
+ *
+ * This structure contains pointers to the low-level functions that implement the CAN functionality.
+ * It must be provided when registering a CAN device.
  */
 struct rt_can_ops
 {
+    /**
+     * @brief Configures the CAN controller with the specified settings.
+     * @param[in] can A pointer to the CAN device structure.
+     * @param[in] cfg A pointer to the configuration structure.
+     * @return `RT_EOK` on success, or a negative error code on failure.
+     */
     rt_err_t (*configure)(struct rt_can_device *can, struct can_configure *cfg);
+    /**
+     * @brief Sends control commands to the CAN device.
+     * @param[in] can A pointer to the CAN device structure.
+     * @param[in] cmd The control command (e.g., RT_CAN_CMD_SET_FILTER).
+     * @param[in] arg A pointer to the arguments for the command.
+     * @return `RT_EOK` on success, or a negative error code on failure.
+     */
     rt_err_t (*control)(struct rt_can_device *can, int cmd, void *arg);
+    /**
+     * @brief Low-level blocking function to send a CAN message.
+     * @param[in] can   A pointer to the CAN device structure.
+     * @param[in] buf   A pointer to the `rt_can_msg` to be sent.
+     * @param[in] boxno The hardware mailbox number to use for transmission.
+     * @return The number of bytes sent on success, or a negative error code on failure.
+     */
     rt_ssize_t (*sendmsg)(struct rt_can_device *can, const void *buf, rt_uint32_t boxno);
-    rt_ssize_t (*recvmsg)(struct rt_can_device *can, void *buf, rt_uint32_t boxno);
+    /**
+     * @brief Low-level function to receive a CAN message.
+     * @param[in,out] can A pointer to the CAN device structure.
+     * @param[out]    buf A pointer to the buffer to store the received `rt_can_msg`.
+     * @param[in]     fifo The hardware FIFO number to read from.
+     * @return The number of bytes received on success, or a negative error code on failure.
+     */
+    rt_ssize_t (*recvmsg)(struct rt_can_device *can, void *buf, rt_uint32_t fifo);
+    /**
+     * @brief Low-level, hardware-specific function to send a CAN message non-blockingly.
+     *
+     * This function attempts to place a message into a hardware transmission mailbox
+     * and returns immediately without waiting for the transmission to complete.
+     *
+     * @param[in] can A pointer to the CAN device structure.
+     * @param[in] buf A pointer to the `rt_can_msg` to be sent.
+     *
+     * @return
+     * - `RT_EOK` if the message was successfully accepted by the hardware.
+     * - `-RT_EBUSY` if all hardware mailboxes are currently full.
+     * - Other negative error codes for different failures.
+     */
+    rt_ssize_t (*sendmsg_nonblocking)(struct rt_can_device *can, const void *buf);
 };
 
 /**
- * @brief Register a CAN device to device list
+ * @brief This function registers a CAN device with the device framework.
  *
- * @param can   the CAN device object
- * @param name  the name of CAN device
- * @param ops   the CAN device operators
- * @param data  the private data of CAN device
+ * @param[in] can   A pointer to the CAN device object to be registered.
+ * @param[in] name  The name that the device will be registered with.
+ * @param[in] ops   A pointer to the structure containing the low-level CAN driver operations.
+ * @param[in] data  A pointer to a user-defined data structure, which can be accessed
+ *                  via `can->parent.user_data`.
  *
- * @return the error code, RT_EOK on successfully
+ * @return `RT_EOK` on successful registration, or a negative error code on failure.
  */
 rt_err_t rt_hw_can_register(struct rt_can_device    *can,
                             const char              *name,
@@ -534,10 +691,16 @@ rt_err_t rt_hw_can_register(struct rt_can_device    *can,
                             void                    *data);
 
 /**
- * @brief CAN interrupt service routine
+ * @brief The framework-level ISR handler for CAN devices.
+ *
+ * This function is called by the low-level BSP ISR and acts as the central
+ * dispatcher for all CAN-related interrupt events. It handles both receive
+ * events and transmission-complete events.
+ *
+ * @param[in] can    A pointer to the CAN device structure.
+ * @param[in] event  The interrupt event mask, indicating the cause of the interrupt.
  *
- * @param can    the CAN device
- * @param event  the event mask
+ * @return void
  */
 void rt_hw_can_isr(struct rt_can_device *can, int event);