|
|
@@ -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);
|
|
|
|