diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index e5eccc8..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "files.associations": { - "user_math.h": "c", - "bsp.h": "c", - "stdint.h": "c", - "array": "c", - "string": "c", - "string_view": "c", - "vector": "c", - "can.h": "c", - "device.h": "c", - "gpio.h": "c", - "uart.h": "c", - "motor_rm.h": "c", - "mm.h": "c", - "capacity.h": "c", - "error_detect.h": "c", - "bmi088.h": "c", - "time.h": "c", - "motor.h": "c" - } -} \ No newline at end of file diff --git a/app/code_page/bsp_interface.py b/app/code_page/bsp_interface.py index efbc26c..5cd1c03 100644 --- a/app/code_page/bsp_interface.py +++ b/app/code_page/bsp_interface.py @@ -318,6 +318,14 @@ def get_available_can(project_path): return analyzing_ioc.get_enabled_can_from_ioc(ioc_path) return [] +def get_available_fdcan(project_path): + """获取可用的FDCAN列表""" + ioc_files = [f for f in os.listdir(project_path) if f.endswith('.ioc')] + if ioc_files: + ioc_path = os.path.join(project_path, ioc_files[0]) + return analyzing_ioc.get_enabled_fdcan_from_ioc(ioc_path) + return [] + def get_available_spi(project_path): ioc_files = [f for f in os.listdir(project_path) if f.endswith('.ioc')] if ioc_files: @@ -618,6 +626,92 @@ class bsp_spi(BspPeripheralBase): ) +class bsp_fdcan(BspPeripheralBase): + def __init__(self, project_path): + super().__init__( + project_path, + "FDCAN", + {'header': 'fdcan.h', 'source': 'fdcan.c'}, + "BSP_FDCAN", + "hfdcan", + "fdcan", + get_available_fdcan + ) + + def _generate_header_file(self, configs, template_dir): + """生成FDCAN头文件,包含动态宏定义""" + template_path = os.path.join(template_dir, self.template_names['header']) + template_content = CodeGenerator.load_template(template_path) + if not template_content: + return False + + # 生成枚举 + enum_lines = [f" {self.enum_prefix}_{name}," for name, _ in configs] + content = CodeGenerator.replace_auto_generated( + template_content, f"AUTO GENERATED {self.enum_prefix}_NAME", "\n".join(enum_lines) + ) + + # 生成FDCAN实例使能宏定义 + macro_lines = [] + for name, instance in configs: + fdcan_num = ''.join(filter(str.isdigit, instance)) # 提取数字,如FDCAN1 -> 1 + macro_lines.append(f"#define {instance}_EN") + + # 替换宏定义区域 + content = CodeGenerator.replace_auto_generated( + content, "AUTO GENERATED FDCAN_EN", "\n".join(macro_lines) + ) + + # 生成FIFO配置宏定义 + fifo_lines = [] + fdcan_count = len(configs) + for idx, (name, instance) in enumerate(configs): + fdcan_num = ''.join(filter(str.isdigit, instance)) + # FDCAN1使用FIFO0,其他使用FIFO1 + if instance == 'FDCAN1': + fifo_lines.append(f"#define {instance}_RX_FIFO 0") + else: + fifo_lines.append(f"#define {instance}_RX_FIFO 1") + + content = CodeGenerator.replace_auto_generated( + content, "AUTO GENERATED FDCAN_RX_FIFO", "\n".join(fifo_lines) + ) + + output_path = os.path.join(self.project_path, f"User/bsp/{self.template_names['header']}") + CodeGenerator.save_with_preserve(output_path, content) + return True + + def _generate_source_file(self, configs, template_dir): + """生成FDCAN源文件""" + template_path = os.path.join(template_dir, self.template_names['source']) + template_content = CodeGenerator.load_template(template_path) + if not template_content: + return False + + # Get函数 + get_lines = [] + for idx, (name, instance) in enumerate(configs): + get_lines.append(f" case {idx}: return {self.enum_prefix}_{name};") + content = CodeGenerator.replace_auto_generated( + template_content, "AUTO GENERATED FDCAN_GET", "\n".join(get_lines) + ) + + # Handle函数 + handle_lines = [] + for name, instance in configs: + fdcan_num = ''.join(filter(str.isdigit, instance)) + handle_lines.append(f"#ifdef {instance}_EN") + handle_lines.append(f" case {self.enum_prefix}_{name}: return &{self.handle_prefix}{fdcan_num};") + handle_lines.append(f"#endif") + content = CodeGenerator.replace_auto_generated( + content, f"AUTO GENERATED {self.enum_prefix}_GET_HANDLE", "\n".join(handle_lines) + ) + + output_path = os.path.join(self.project_path, f"User/bsp/{self.template_names['source']}") + CodeGenerator.save_with_preserve(output_path, content) + return True + + def patch_uart_interrupts(project_path, uart_instances): """自动修改 stm32f4xx_it.c,插入 UART BSP 相关代码""" it_path = os.path.join(project_path, "Core/Src/stm32f4xx_it.c") @@ -1166,6 +1260,7 @@ def get_bsp_page(peripheral_name, project_path): special_classes = { "i2c": bsp_i2c, "can": bsp_can, + "fdcan": bsp_fdcan, "spi": bsp_spi, "uart": bsp_uart, "gpio": bsp_gpio, diff --git a/app/tools/analyzing_ioc.py b/app/tools/analyzing_ioc.py index 6a85c3d..542cbb4 100644 --- a/app/tools/analyzing_ioc.py +++ b/app/tools/analyzing_ioc.py @@ -71,7 +71,7 @@ class analyzing_ioc: @staticmethod def get_enabled_can_from_ioc(ioc_path): """ - 获取已启用的CAN列表 + 获取已启用的CAN列表(不包括FDCAN) 返回格式: ['CAN1', 'CAN2'] 等 """ enabled_can = [] @@ -84,12 +84,35 @@ class analyzing_ioc: key, value = line.split('=', 1) key = key.strip() value = value.strip() - if key.startswith('Mcu.IP') and value.startswith('CAN'): + # 只匹配CAN,不包括FDCAN + if key.startswith('Mcu.IP') and value.startswith('CAN') and not value.startswith('FDCAN'): can_name = value.split('.')[0] if '.' in value else value if can_name not in enabled_can: enabled_can.append(can_name) return sorted(enabled_can) + @staticmethod + def get_enabled_fdcan_from_ioc(ioc_path): + """ + 获取已启用的FDCAN列表 + 返回格式: ['FDCAN1', 'FDCAN2', 'FDCAN3'] 等 + """ + enabled_fdcan = [] + with open(ioc_path, encoding='utf-8', errors='ignore') as f: + for line in f: + line = line.strip() + if not line or line.startswith('#'): + continue + if '=' in line: + key, value = line.split('=', 1) + key = key.strip() + value = value.strip() + if key.startswith('Mcu.IP') and value.startswith('FDCAN'): + fdcan_name = value.split('.')[0] if '.' in value else value + if fdcan_name not in enabled_fdcan: + enabled_fdcan.append(fdcan_name) + return sorted(enabled_fdcan) + @staticmethod def get_enabled_uart_from_ioc(ioc_path): """ diff --git a/assets/User_code/.DS_Store b/assets/User_code/.DS_Store index e391af5..0f8f41b 100644 Binary files a/assets/User_code/.DS_Store and b/assets/User_code/.DS_Store differ diff --git a/assets/User_code/bsp/describe.csv b/assets/User_code/bsp/describe.csv index 5206a52..2788635 100644 --- a/assets/User_code/bsp/describe.csv +++ b/assets/User_code/bsp/describe.csv @@ -1,5 +1,6 @@ uart,请开启uart的dma和中断 can,请开启can中断,使用函数前请确保can已经初始化。一定要开启can发送中断!!! +fdcan,请开启fdcan中断,支持经典CAN和FDCAN模式。会自动根据IOC配置生成对应的宏定义。 gpio,会自动读取cubemx中配置为gpio的引脚,并自动区分输入输出和中断。 spi,请开启spi的dma和中断 i2c,要求开始spi中断 diff --git a/assets/User_code/bsp/fdcan.c b/assets/User_code/bsp/fdcan.c new file mode 100644 index 0000000..6c6221f --- /dev/null +++ b/assets/User_code/bsp/fdcan.c @@ -0,0 +1,576 @@ +/* Includes ----------------------------------------------------------------- */ +#include "fdcan.h" +#include "bsp/fdcan.h" +#include "bsp/bsp.h" +#include +#include +#include + +/* Private define ----------------------------------------------------------- */ +#define FDCAN_QUEUE_MUTEX_TIMEOUT 100 + +/* Private macro ------------------------------------------------------------ */ + +/* ===== FDCAN_FilterTypeDef 配置表 ===== + * 定义每个FDCAN实例的过滤器参数表。 + * 过滤器表参数说明: + * idx idtype ftype id1 id2 rxidx + * 过滤器编号 标识符类型 过滤器类型 过滤器ID1 过滤器ID2 接收缓冲区索引 + */ +#ifdef FDCAN1_EN + #define FDCAN1_FILTER_CONFIG_TABLE(X) \ + X(0, FDCAN_STANDARD_ID, FDCAN_FILTER_MASK, 0x000 , 0x000 , 0) \ + X(1, FDCAN_EXTENDED_ID, FDCAN_FILTER_MASK, 0x00000000, 0x00000000, 0) + #define FDCAN1_GLOBAL_FILTER FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE/* 全局过滤器参数(用于 HAL_FDCAN_ConfigGlobalFilter) */ +#endif +#ifdef FDCAN2_EN + #define FDCAN2_FILTER_CONFIG_TABLE(X) \ + X(0, FDCAN_STANDARD_ID, FDCAN_FILTER_MASK, 0x000 , 0x000 , 0) \ + X(1, FDCAN_EXTENDED_ID, FDCAN_FILTER_MASK, 0x00000000, 0x00000000, 0) + #define FDCAN2_GLOBAL_FILTER FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE/* 全局过滤器参数(用于 HAL_FDCAN_ConfigGlobalFilter) */ +#endif +#ifdef FDCAN3_EN + #define FDCAN3_FILTER_CONFIG_TABLE(X) \ + X(0, FDCAN_STANDARD_ID, FDCAN_FILTER_MASK, 0x000 , 0x000 , 0) \ + X(1, FDCAN_EXTENDED_ID, FDCAN_FILTER_MASK, 0x00000000, 0x00000000, 0) + #define FDCAN3_GLOBAL_FILTER FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE/* 全局过滤器参数(用于 HAL_FDCAN_ConfigGlobalFilter) */ +#endif + +/* ====宏展开实现==== */ +#define FDCAN_FILTER_TO_RXFIFO_ENUM_INNER(FIFOIndex) FDCAN_FILTER_TO_RXFIFO##FIFOIndex +#define FDCAN_FILTER_TO_RXFIFO_ENUM(FIFOIndex) FDCAN_FILTER_TO_RXFIFO_ENUM_INNER(FIFOIndex) +#define FDCAN_CONFIG_FILTER(idx, idtype, ftype, id1, id2, rxidx) \ + sFilterConfig.FilterIndex = (idx); \ + sFilterConfig.IdType = (idtype); \ + sFilterConfig.FilterType = (ftype); \ + sFilterConfig.FilterConfig = (FDCAN_FILTER_TO_RXFIFO_ENUM(FDCANX_RX_FIFO)); \ + sFilterConfig.FilterID1 = (id1); \ + sFilterConfig.FilterID2 = (id2); \ + sFilterConfig.RxBufferIndex = (rxidx); \ + HAL_FDCAN_ConfigFilter(&hfdcan, &sFilterConfig); + +#define FDCAN_NOTIFY_FLAG_RXFIFO_INNER(FIFO_IDX) FDCAN_IT_RX_FIFO##FIFO_IDX##_NEW_MESSAGE +#define FDCAN_NOTIFY_FLAG_RXFIFO(FIFO_IDX) FDCAN_NOTIFY_FLAG_RXFIFO_INNER(FIFO_IDX) +#define FDCANx_NOTIFY_FLAGS(FIFO_MACRO) (FDCAN_NOTIFY_FLAG_RXFIFO(FIFO_MACRO) | FDCAN_IT_TX_EVT_FIFO_NEW_DATA | FDCAN_IT_RAM_ACCESS_FAILURE) + +#define FDCANX_MSG_PENDING_CB_INNER(FIFO_IDX) HAL_FDCAN_RX_FIFO##FIFO_IDX##_MSG_PENDING_CB +#define FDCANX_MSG_PENDING_CB(FIFO_IDX) FDCANX_MSG_PENDING_CB_INNER(FIFO_IDX) +/* Private typedef ---------------------------------------------------------- */ +typedef struct BSP_FDCAN_QueueNode { + BSP_FDCAN_t fdcan; + uint32_t can_id; + osMessageQueueId_t queue; + uint8_t queue_size; + struct BSP_FDCAN_QueueNode *next; +} BSP_FDCAN_QueueNode_t; + +/* Private variables -------------------------------------------------------- */ +static BSP_FDCAN_QueueNode_t *queue_list = NULL; +static osMutexId_t queue_mutex = NULL; +static void (*FDCAN_Callback[BSP_FDCAN_NUM][HAL_FDCAN_CB_NUM])(void); +static bool inited = false; +static BSP_FDCAN_IdParser_t id_parser = NULL; +static BSP_FDCAN_TxQueue_t tx_queues[BSP_FDCAN_NUM]; +static const uint8_t fdcan_dlc2len[16] = {0,1,2,3,4,5,6,7,8,12,16,20,24,32,48,64}; + +/* Private function prototypes ---------------------------------------------- */ +static BSP_FDCAN_t FDCAN_Get(FDCAN_HandleTypeDef *hfdcan); +static osMessageQueueId_t BSP_FDCAN_FindQueue(BSP_FDCAN_t fdcan, uint32_t can_id); +static int8_t BSP_FDCAN_CreateIdQueue(BSP_FDCAN_t fdcan, uint32_t can_id, uint8_t queue_size); +static void BSP_FDCAN_RxFifo0Callback(void); +static void BSP_FDCAN_RxFifo1Callback(void); +static void BSP_FDCAN_TxCompleteCallback(void); +static BSP_FDCAN_FrameType_t BSP_FDCAN_GetFrameType(FDCAN_RxHeaderTypeDef *header); +static uint32_t BSP_FDCAN_DefaultIdParser(uint32_t original_id, BSP_FDCAN_FrameType_t frame_type); +static void BSP_FDCAN_TxQueueInit(BSP_FDCAN_t fdcan); +static bool BSP_FDCAN_TxQueuePush(BSP_FDCAN_t fdcan, BSP_FDCAN_TxMessage_t *msg); +static bool BSP_FDCAN_TxQueuePop(BSP_FDCAN_t fdcan, BSP_FDCAN_TxMessage_t *msg); +static bool BSP_FDCAN_TxQueueIsEmpty(BSP_FDCAN_t fdcan); + +/* Private functions -------------------------------------------------------- */ +static BSP_FDCAN_t FDCAN_Get(FDCAN_HandleTypeDef *hfdcan) { + if (hfdcan == NULL) return BSP_FDCAN_ERR; + if (hfdcan->Instance == FDCAN1) return BSP_FDCAN_1; + else if (hfdcan->Instance == FDCAN2) return BSP_FDCAN_2; + else if (hfdcan->Instance == FDCAN3) return BSP_FDCAN_3; + else return BSP_FDCAN_ERR; +} + +static osMessageQueueId_t BSP_FDCAN_FindQueue(BSP_FDCAN_t fdcan, uint32_t can_id) { + BSP_FDCAN_QueueNode_t *node = queue_list; + while (node != NULL) { + if (node->fdcan == fdcan && node->can_id == can_id) return node->queue; + node = node->next; + } + return NULL; +} + +static int8_t BSP_FDCAN_CreateIdQueue(BSP_FDCAN_t fdcan, uint32_t can_id, uint8_t queue_size) { + if (queue_size == 0) queue_size = BSP_FDCAN_DEFAULT_QUEUE_SIZE; + if (osMutexAcquire(queue_mutex, FDCAN_QUEUE_MUTEX_TIMEOUT) != osOK) return BSP_ERR_TIMEOUT; + BSP_FDCAN_QueueNode_t *node = queue_list; + while (node != NULL) { + if (node->fdcan == fdcan && node->can_id == can_id) { + osMutexRelease(queue_mutex); + return BSP_ERR; + } + node = node->next; + } + + BSP_FDCAN_QueueNode_t *new_node = (BSP_FDCAN_QueueNode_t *)BSP_Malloc(sizeof(BSP_FDCAN_QueueNode_t)); + if (new_node == NULL) { osMutexRelease(queue_mutex); return BSP_ERR_NULL; } + new_node->queue = osMessageQueueNew(queue_size, sizeof(BSP_FDCAN_Message_t), NULL); + if (new_node->queue == NULL) { BSP_Free(new_node); osMutexRelease(queue_mutex); return BSP_ERR; } + new_node->fdcan = fdcan; + new_node->can_id = can_id; + new_node->queue_size = queue_size; + new_node->next = queue_list; + queue_list = new_node; + osMutexRelease(queue_mutex); + return BSP_OK; +} + +static BSP_FDCAN_FrameType_t BSP_FDCAN_GetFrameType(FDCAN_RxHeaderTypeDef *header) { + if (header->RxFrameType == FDCAN_REMOTE_FRAME) { + return (header->IdType == FDCAN_EXTENDED_ID) ? BSP_FDCAN_FRAME_EXT_REMOTE : BSP_FDCAN_FRAME_STD_REMOTE; + } else { + return (header->IdType == FDCAN_EXTENDED_ID) ? BSP_FDCAN_FRAME_EXT_DATA : BSP_FDCAN_FRAME_STD_DATA; + } +} + +static uint32_t BSP_FDCAN_DefaultIdParser(uint32_t original_id, BSP_FDCAN_FrameType_t frame_type) { + (void)frame_type; + return original_id; +} + +static uint32_t BSP_FDCAN_EncodeDLC(uint8_t dlc) { + if (dlc <= 8) return dlc; + if (dlc <= 12) return FDCAN_DLC_BYTES_12; + if (dlc <= 16) return FDCAN_DLC_BYTES_16; + if (dlc <= 20) return FDCAN_DLC_BYTES_20; + if (dlc <= 24) return FDCAN_DLC_BYTES_24; + if (dlc <= 32) return FDCAN_DLC_BYTES_32; + if (dlc <= 48) return FDCAN_DLC_BYTES_48; + return FDCAN_DLC_BYTES_64; +} + +static void BSP_FDCAN_TxQueueInit(BSP_FDCAN_t fdcan) { + if (fdcan >= BSP_FDCAN_NUM) return; + tx_queues[fdcan].head = 0; + tx_queues[fdcan].tail = 0; +} + +static bool BSP_FDCAN_TxQueuePush(BSP_FDCAN_t fdcan, BSP_FDCAN_TxMessage_t *msg) { + if (fdcan >= BSP_FDCAN_NUM || msg == NULL) return false; + BSP_FDCAN_TxQueue_t *queue = &tx_queues[fdcan]; + uint32_t next_head = (queue->head + 1) % BSP_FDCAN_TX_QUEUE_SIZE; + if (next_head == queue->tail) return false; + queue->buffer[queue->head] = *msg; + queue->head = next_head; + return true; +} + +static bool BSP_FDCAN_TxQueuePop(BSP_FDCAN_t fdcan, BSP_FDCAN_TxMessage_t *msg) { + if (fdcan >= BSP_FDCAN_NUM || msg == NULL) return false; + BSP_FDCAN_TxQueue_t *queue = &tx_queues[fdcan]; + if (queue->head == queue->tail) return false; + *msg = queue->buffer[queue->tail]; + queue->tail = (queue->tail + 1) % BSP_FDCAN_TX_QUEUE_SIZE; + return true; +} + +static bool BSP_FDCAN_TxQueueIsEmpty(BSP_FDCAN_t fdcan) { + if (fdcan >= BSP_FDCAN_NUM) return true; + return tx_queues[fdcan].head == tx_queues[fdcan].tail; +} + +static void BSP_FDCAN_TxCompleteCallback(void) { + for (int i = 0; i < BSP_FDCAN_NUM; i++) { + BSP_FDCAN_t fdcan = (BSP_FDCAN_t)i; + FDCAN_HandleTypeDef *hfdcan = BSP_FDCAN_GetHandle(fdcan); + if (hfdcan == NULL) continue; + // 消费所有 TX EVENT FIFO 事件,防止堵塞 + FDCAN_TxEventFifoTypeDef tx_event; + while (HAL_FDCAN_GetTxEvent(hfdcan, &tx_event) == HAL_OK) { + // 可在此统计 MessageMarker、ID、时间戳等 + } + // 续写软件队列到硬件 FIFO + BSP_FDCAN_TxMessage_t msg; + while (!BSP_FDCAN_TxQueueIsEmpty(fdcan)) { + if (HAL_FDCAN_GetTxFifoFreeLevel(hfdcan) == 0) break; + if (!BSP_FDCAN_TxQueuePop(fdcan, &msg)) break; + HAL_StatusTypeDef res = HAL_FDCAN_AddMessageToTxFifoQ(hfdcan, &msg.header, msg.data); + if (res != HAL_OK) { + break; + } + } + } +} + +static void BSP_FDCAN_RxFifo0Callback(void) { + FDCAN_RxHeaderTypeDef rx_header; + uint8_t rx_data[BSP_FDCAN_MAX_DLC]; + for (int fdcan_idx = 0; fdcan_idx < BSP_FDCAN_NUM; fdcan_idx++) { + FDCAN_HandleTypeDef *hfdcan = BSP_FDCAN_GetHandle((BSP_FDCAN_t)fdcan_idx); + if (hfdcan == NULL) continue; + while (HAL_FDCAN_GetRxFifoFillLevel(hfdcan, FDCAN_RX_FIFO0) > 0) { + if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &rx_header, rx_data) == HAL_OK) { + uint32_t original_id = (rx_header.IdType == FDCAN_STANDARD_ID) ? rx_header.Identifier&0x7ff : rx_header.Identifier&0x1fffffff; + BSP_FDCAN_FrameType_t frame_type = BSP_FDCAN_GetFrameType(&rx_header); + uint32_t parsed_id = BSP_FDCAN_ParseId(original_id, frame_type); + osMessageQueueId_t queue = BSP_FDCAN_FindQueue((BSP_FDCAN_t)fdcan_idx, parsed_id); + if (queue != NULL) { + BSP_FDCAN_Message_t msg; + msg.frame_type = frame_type; + msg.original_id = original_id; + msg.parsed_id = parsed_id; + uint8_t real_len = fdcan_dlc2len[rx_header.DataLength & 0xF]; + msg.dlc = real_len; + if (msg.dlc > BSP_FDCAN_MAX_DLC) msg.dlc = BSP_FDCAN_MAX_DLC; + memset(msg.data, 0, BSP_FDCAN_MAX_DLC);//现在是最大缓冲区写法所以全清零 + memcpy(msg.data, rx_data, msg.dlc); + osMessageQueuePut(queue, &msg, 0, 0); + } + } else { + break; + } + } + } +} + +static void BSP_FDCAN_RxFifo1Callback(void) { + FDCAN_RxHeaderTypeDef rx_header; + uint8_t rx_data[BSP_FDCAN_MAX_DLC]; + for (int fdcan_idx = 0; fdcan_idx < BSP_FDCAN_NUM; fdcan_idx++) { + FDCAN_HandleTypeDef *hfdcan = BSP_FDCAN_GetHandle((BSP_FDCAN_t)fdcan_idx); + if (hfdcan == NULL) continue; + while (HAL_FDCAN_GetRxFifoFillLevel(hfdcan, FDCAN_RX_FIFO1) > 0) { + if (HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO1, &rx_header, rx_data) == HAL_OK) { + uint32_t original_id = (rx_header.IdType == FDCAN_STANDARD_ID) ? rx_header.Identifier&0x7ff : rx_header.Identifier&0x1fffffff; + BSP_FDCAN_FrameType_t frame_type = BSP_FDCAN_GetFrameType(&rx_header); + uint32_t parsed_id = BSP_FDCAN_ParseId(original_id, frame_type); + osMessageQueueId_t queue = BSP_FDCAN_FindQueue((BSP_FDCAN_t)fdcan_idx, parsed_id); + if (queue != NULL) { + BSP_FDCAN_Message_t msg; + msg.frame_type = frame_type; + msg.original_id = original_id; + msg.parsed_id = parsed_id; + uint8_t real_len = fdcan_dlc2len[rx_header.DataLength & 0xF]; + msg.dlc = real_len; + if (msg.dlc > BSP_FDCAN_MAX_DLC) msg.dlc = BSP_FDCAN_MAX_DLC; + memset(msg.data, 0, BSP_FDCAN_MAX_DLC);//现在是最大缓冲区写法所以全清零 + memcpy(msg.data, rx_data, msg.dlc); + osMessageQueuePut(queue, &msg, 0, 0); + } + } else { + break; + } + } + } +} + +/* HAL Callback Stubs (map HAL FDCAN callbacks to user callbacks) */ +void HAL_FDCAN_TxEventFifoCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t TxEventFifoITs) { + BSP_FDCAN_t bsp_fdcan = FDCAN_Get(hfdcan); + if (bsp_fdcan != BSP_FDCAN_ERR) { + if (FDCAN_Callback[bsp_fdcan][HAL_FDCAN_TX_EVENT_FIFO_CB]) + FDCAN_Callback[bsp_fdcan][HAL_FDCAN_TX_EVENT_FIFO_CB](); + } +} + +void HAL_FDCAN_TxBufferCompleteCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t BufferIndex) { + BSP_FDCAN_t bsp_fdcan = FDCAN_Get(hfdcan); + if (bsp_fdcan != BSP_FDCAN_ERR) { + if (FDCAN_Callback[bsp_fdcan][HAL_FDCAN_TX_BUFFER_COMPLETE_CB]) + FDCAN_Callback[bsp_fdcan][HAL_FDCAN_TX_BUFFER_COMPLETE_CB](); + } +} + +void HAL_FDCAN_TxBufferAbortCallback(FDCAN_HandleTypeDef *hfdcan, uint32_t BufferIndex) { + BSP_FDCAN_t bsp_fdcan = FDCAN_Get(hfdcan); + if (bsp_fdcan != BSP_FDCAN_ERR) { + if (FDCAN_Callback[bsp_fdcan][HAL_FDCAN_TX_BUFFER_ABORT_CB]) + FDCAN_Callback[bsp_fdcan][HAL_FDCAN_TX_BUFFER_ABORT_CB](); + } +} + +void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) { + BSP_FDCAN_t bsp_fdcan = FDCAN_Get(hfdcan); + if (bsp_fdcan != BSP_FDCAN_ERR) { + if (FDCAN_Callback[bsp_fdcan][HAL_FDCAN_RX_FIFO0_MSG_PENDING_CB]) + FDCAN_Callback[bsp_fdcan][HAL_FDCAN_RX_FIFO0_MSG_PENDING_CB](); + } +} + +void HAL_FDCAN_RxFifo1Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo1ITs) { + BSP_FDCAN_t bsp_fdcan = FDCAN_Get(hfdcan); + if (bsp_fdcan != BSP_FDCAN_ERR) { + if (FDCAN_Callback[bsp_fdcan][HAL_FDCAN_RX_FIFO1_MSG_PENDING_CB]) + FDCAN_Callback[bsp_fdcan][HAL_FDCAN_RX_FIFO1_MSG_PENDING_CB](); + } +} + +void HAL_FDCAN_ErrorCallback(FDCAN_HandleTypeDef *hfdcan) { + BSP_FDCAN_t bsp_fdcan = FDCAN_Get(hfdcan); + if (bsp_fdcan != BSP_FDCAN_ERR) { + if (FDCAN_Callback[bsp_fdcan][HAL_FDCAN_ERROR_CB]) + FDCAN_Callback[bsp_fdcan][HAL_FDCAN_ERROR_CB](); + } +} + +/* Exported functions ------------------------------------------------------- */ +int8_t BSP_FDCAN_Init(void) { + if (inited) return BSP_ERR_INITED; + + memset(FDCAN_Callback, 0, sizeof(FDCAN_Callback)); + for (int i = 0; i < BSP_FDCAN_NUM; i++) BSP_FDCAN_TxQueueInit((BSP_FDCAN_t)i); + id_parser = BSP_FDCAN_DefaultIdParser; + queue_mutex = osMutexNew(NULL); + if (queue_mutex == NULL) return BSP_ERR; + + inited = true; + + /* 配置并启动 FDCAN 实例,绑定中断/回调 */ + + //========== 过滤器配置说明:========================== + // 过滤器编号:相对于每个(相当于经典can过滤器的bank) + // sFilterConfig.FilterIndex = 0 to 127(标准ID) or 0 to 63(扩展ID); + // 关于过滤器索引的说明: + // 由stm32h7xx_hal_fdcan.c的第1874行代码可知滤波器地址计算方式如下: + // StandardFilterSA(字节) = SRAMCAN_BASE + (MessageRAMOffset * 4U) + // 标准滤波器物理地址(字节) = StandardFilterSA + (FilterIndex * 4U)(每个标准滤波器占 4 字节 = 1 word,扩展的则是8个字节) + // + // + // 标识符类型: + // sFilterConfig.IdType = FDCAN_STANDARD_ID or FDCAN_EXTENDED_ID; + // 过滤器类型: (仅介绍掩码模式) + // sFilterConfig.FilterType = FDCAN_FILTER_MASK;(掩码模式) + // 过滤器配置: + // sFilterConfig.FilterConfig = FDCAN_FILTER_DISABLE; (禁用该过滤器条目) + // FDCAN_FILTER_TO_RXFIFO0; (将匹配的消息放入 FIFO 0(普通优先级)) + // FDCAN_FILTER_TO_RXFIFO1; (将匹配的消息放入 FIFO 1(高优先级)) + // FDCAN_FILTER_TO_RXBUFFER; (将匹配的消息放入 指定的接收缓冲区) + // FDCAN_FILTER_REJECT; (拒绝接收该标识符对应的报文) + // FDCAN_FILTER_ACCEPT; (接受所有消息) + // FDCAN_FILTER_HP (过滤器匹配时,将报文标记为高优先级) + // FDCAN_FILTER_TO_RXFIFO0_HP (过滤器匹配时,将报文标记为高优先级并存储至接收FIFO 0) + // FDCAN_FILTER_TO_RXFIFO1_HP (过滤器匹配时,将报文标记为高优先级并存储至接收FIFO 1) + // FDCAN_FILTER_TO_RXBUFFER (将报文存储至接收缓冲区,过滤器类型(FilterType)配置项失效 ) + // 过滤器ID与掩码(FilterType掩码模式下) + // 比较值(要匹配的 ID 的参考位) + // sFilterConfig.FilterID1 = 0 to 0x7FF; 标准ID + // 0 to 0x1FFFFFFF 扩展ID + // 掩码(1=比较该位,0=忽略该位) + // sFilterConfig.FilterID2 = 0 to 0x7FF; 标准ID + // 0 to 0x1FFFFFFF 扩展ID + // 接收缓冲区索引 + // FilterConfig == FDCAN_FILTER_TO_RXBUFFER 时有效;必须小于RxBuffersNbr配置的实际Rx buffer数量 + // sFilterConfig.RxBufferIndex = 0 to (RxBuffersNbr - 1); + // 标记校准信息(用于 FDCAN 校准/时钟相关单元作特殊处理或统计) + // 仅在FilterConfig 设为 FDCAN_FILTER_TO_RXBUFFER 时才有意义,通常设置为0 + // IsCalibrationMsg = 0 or 1; + // fdcan_filter_table.h + //================================================================================= + /* 依据上述说明,配置过滤器并启动FDCAN */ + FDCAN_FilterTypeDef sFilterConfig; + +#ifdef FDCAN1_EN + #define hfdcan hfdcan1 + #define FDCANX_RX_FIFO FDCAN1_RX_FIFO + FDCAN1_FILTER_CONFIG_TABLE(FDCAN_CONFIG_FILTER) + #undef hfdcan + #undef FDCANX_RX_FIFO + HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN1_GLOBAL_FILTER); + HAL_FDCAN_ActivateNotification(&hfdcan1, FDCANx_NOTIFY_FLAGS(FDCAN1_RX_FIFO), 0); + BSP_FDCAN_RegisterCallback(BSP_FDCAN_1, FDCANX_MSG_PENDING_CB(FDCAN1_RX_FIFO), BSP_FDCAN_RxFifo0Callback); + BSP_FDCAN_RegisterCallback(BSP_FDCAN_1, HAL_FDCAN_TX_EVENT_FIFO_CB, BSP_FDCAN_TxCompleteCallback); + HAL_FDCAN_Start(&hfdcan1); +#endif + +#ifdef FDCAN2_EN + #define hfdcan hfdcan2 + #define FDCANX_RX_FIFO FDCAN2_RX_FIFO + FDCAN2_FILTER_CONFIG_TABLE(FDCAN_CONFIG_FILTER) + #undef hfdcan + #undef FDCANX_RX_FIFO + HAL_FDCAN_ConfigGlobalFilter(&hfdcan2, FDCAN2_GLOBAL_FILTER); + HAL_FDCAN_ActivateNotification(&hfdcan2, FDCANx_NOTIFY_FLAGS(FDCAN2_RX_FIFO), 0); + BSP_FDCAN_RegisterCallback(BSP_FDCAN_2, FDCANX_MSG_PENDING_CB(FDCAN2_RX_FIFO), BSP_FDCAN_RxFifo1Callback); + BSP_FDCAN_RegisterCallback(BSP_FDCAN_2, HAL_FDCAN_TX_EVENT_FIFO_CB, BSP_FDCAN_TxCompleteCallback); + HAL_FDCAN_Start(&hfdcan2); +#endif + +#ifdef FDCAN3_EN + #define hfdcan hfdcan3 + #define FDCANX_RX_FIFO FDCAN3_RX_FIFO + FDCAN3_FILTER_CONFIG_TABLE(FDCAN_CONFIG_FILTER) + #undef hfdcan + #undef FDCANX_RX_FIFO + HAL_FDCAN_ConfigGlobalFilter(&hfdcan3, FDCAN3_GLOBAL_FILTER); + HAL_FDCAN_ActivateNotification(&hfdcan3, FDCANx_NOTIFY_FLAGS(FDCAN3_RX_FIFO), 0); + BSP_FDCAN_RegisterCallback(BSP_FDCAN_3, FDCANX_MSG_PENDING_CB(FDCAN3_RX_FIFO), BSP_FDCAN_RxFifo1Callback); + BSP_FDCAN_RegisterCallback(BSP_FDCAN_3, HAL_FDCAN_TX_EVENT_FIFO_CB, BSP_FDCAN_TxCompleteCallback); + HAL_FDCAN_Start(&hfdcan3); +#endif + +#undef FDCAN_FILTER_TO_RXFIFO_ENUM_INNER +#undef FDCAN_FILTER_TO_RXFIFO_ENUM +#undef FDCAN_CONFIG_FILTER +#undef FDCAN_NOTIFY_FLAG_RXFIFO_INNER +#undef FDCAN_NOTIFY_FLAG_RXFIFO +#undef FDCANx_NOTIFY_FLAGS +#undef FDCANX_MSG_PENDING_CB_INNER +#undef FDCANX_MSG_PENDING_CB + + return BSP_OK; +} + +FDCAN_HandleTypeDef *BSP_FDCAN_GetHandle(BSP_FDCAN_t fdcan) { + if (fdcan >= BSP_FDCAN_NUM) return NULL; + switch (fdcan) { + /* AUTO GENERATED BSP_FDCAN_GET_HANDLE BEGIN */ + case BSP_FDCAN_1: return &hfdcan1; + case BSP_FDCAN_2: return &hfdcan2; + case BSP_FDCAN_3: return &hfdcan3; + /* AUTO GENERATED BSP_FDCAN_GET_HANDLE END */ + default: return NULL; + } +} + +int8_t BSP_FDCAN_RegisterCallback(BSP_FDCAN_t fdcan, BSP_FDCAN_Callback_t type, void (*callback)(void)) { + if (!inited) return BSP_ERR_INITED; + if (callback == NULL) return BSP_ERR_NULL; + if (fdcan >= BSP_FDCAN_NUM) return BSP_ERR; + if (type >= HAL_FDCAN_CB_NUM) return BSP_ERR; + FDCAN_Callback[fdcan][type] = callback; + return BSP_OK; +} + +int8_t BSP_FDCAN_Transmit(BSP_FDCAN_t fdcan, BSP_FDCAN_Format_t format, uint32_t id, uint8_t *data, uint8_t dlc) { + if (!inited) return BSP_ERR_INITED; + if (fdcan >= BSP_FDCAN_NUM) return BSP_ERR; + if (data == NULL && format != BSP_FDCAN_FORMAT_STD_REMOTE && format != BSP_FDCAN_FORMAT_EXT_REMOTE) return BSP_ERR_NULL; + if (dlc > BSP_FDCAN_MAX_DLC) return BSP_ERR; + FDCAN_HandleTypeDef *hfdcan = BSP_FDCAN_GetHandle(fdcan); + if (hfdcan == NULL) return BSP_ERR_NULL; + + BSP_FDCAN_TxMessage_t tx_msg = {0}; + switch (format) { + case BSP_FDCAN_FORMAT_STD_DATA: + tx_msg.header.Identifier = id; + tx_msg.header.IdType = FDCAN_STANDARD_ID; + tx_msg.header.TxFrameType = FDCAN_DATA_FRAME; + break; + case BSP_FDCAN_FORMAT_EXT_DATA: + tx_msg.header.Identifier = id; + tx_msg.header.IdType = FDCAN_EXTENDED_ID; + tx_msg.header.TxFrameType = FDCAN_DATA_FRAME; + break; + case BSP_FDCAN_FORMAT_STD_REMOTE: + tx_msg.header.Identifier = id; + tx_msg.header.IdType = FDCAN_STANDARD_ID; + tx_msg.header.TxFrameType = FDCAN_REMOTE_FRAME; + break; + case BSP_FDCAN_FORMAT_EXT_REMOTE: + tx_msg.header.Identifier = id; + tx_msg.header.IdType = FDCAN_EXTENDED_ID; + tx_msg.header.TxFrameType = FDCAN_REMOTE_FRAME; + break; + default: + return BSP_ERR; + } + switch (hfdcan->Init.FrameFormat) { + case FDCAN_FRAME_FD_BRS: + tx_msg.header.BitRateSwitch = FDCAN_BRS_ON; + tx_msg.header.FDFormat = FDCAN_FD_CAN; + break; + case FDCAN_FRAME_FD_NO_BRS: + tx_msg.header.BitRateSwitch = FDCAN_BRS_OFF; + tx_msg.header.FDFormat = FDCAN_FD_CAN; + break; + case FDCAN_FRAME_CLASSIC: + default: + tx_msg.header.BitRateSwitch = FDCAN_BRS_OFF; + tx_msg.header.FDFormat = FDCAN_CLASSIC_CAN; + break; + } + tx_msg.header.ErrorStateIndicator = FDCAN_ESI_ACTIVE; + tx_msg.header.TxEventFifoControl = FDCAN_STORE_TX_EVENTS; + tx_msg.header.MessageMarker = 0x01; + tx_msg.header.DataLength = BSP_FDCAN_EncodeDLC(dlc); + + memset(tx_msg.data, 0, dlc); + if (data != NULL && dlc > 0) {memcpy(tx_msg.data, data, dlc);} + + if (HAL_FDCAN_GetTxFifoFreeLevel(hfdcan) > 0) { + if (HAL_FDCAN_AddMessageToTxFifoQ(hfdcan, &tx_msg.header, tx_msg.data) == HAL_OK) return BSP_OK; + } + if (BSP_FDCAN_TxQueuePush(fdcan, &tx_msg)) return BSP_OK; + return BSP_ERR; +} + +int8_t BSP_FDCAN_TransmitStdDataFrame(BSP_FDCAN_t fdcan, BSP_FDCAN_StdDataFrame_t *frame) { + if (frame == NULL) return BSP_ERR_NULL; + return BSP_FDCAN_Transmit(fdcan, BSP_FDCAN_FORMAT_STD_DATA, frame->id, frame->data, frame->dlc); +} + +int8_t BSP_FDCAN_TransmitExtDataFrame(BSP_FDCAN_t fdcan, BSP_FDCAN_ExtDataFrame_t *frame) { + if (frame == NULL) return BSP_ERR_NULL; + return BSP_FDCAN_Transmit(fdcan, BSP_FDCAN_FORMAT_EXT_DATA, frame->id, frame->data, frame->dlc); +} + +int8_t BSP_FDCAN_TransmitRemoteFrame(BSP_FDCAN_t fdcan, BSP_FDCAN_RemoteFrame_t *frame) { + if (frame == NULL) return BSP_ERR_NULL; + BSP_FDCAN_Format_t format = frame->is_extended ? BSP_FDCAN_FORMAT_EXT_REMOTE : BSP_FDCAN_FORMAT_STD_REMOTE; + return BSP_FDCAN_Transmit(fdcan, format, frame->id, NULL, frame->dlc); +} + +int8_t BSP_FDCAN_RegisterId(BSP_FDCAN_t fdcan, uint32_t can_id, uint8_t queue_size) { + if (!inited) return BSP_ERR_INITED; + return BSP_FDCAN_CreateIdQueue(fdcan, can_id, queue_size); +} + +int8_t BSP_FDCAN_GetMessage(BSP_FDCAN_t fdcan, uint32_t can_id, BSP_FDCAN_Message_t *msg, uint32_t timeout) { + if (!inited) return BSP_ERR_INITED; + if (msg == NULL) return BSP_ERR_NULL; + if (osMutexAcquire(queue_mutex, FDCAN_QUEUE_MUTEX_TIMEOUT) != osOK) return BSP_ERR_TIMEOUT; + osMessageQueueId_t queue = BSP_FDCAN_FindQueue(fdcan, can_id); + osMutexRelease(queue_mutex); + if (queue == NULL) return BSP_ERR_NO_DEV; + osStatus_t res = osMessageQueueGet(queue, msg, NULL, timeout); + return (res == osOK) ? BSP_OK : BSP_ERR; +} + +int32_t BSP_FDCAN_GetQueueCount(BSP_FDCAN_t fdcan, uint32_t can_id) { + if (!inited) return -1; + if (osMutexAcquire(queue_mutex, FDCAN_QUEUE_MUTEX_TIMEOUT) != osOK) return -1; + osMessageQueueId_t queue = BSP_FDCAN_FindQueue(fdcan, can_id); + osMutexRelease(queue_mutex); + if (queue == NULL) return -1; + return (int32_t)osMessageQueueGetCount(queue); +} + +int8_t BSP_FDCAN_FlushQueue(BSP_FDCAN_t fdcan, uint32_t can_id) { + if (!inited) return BSP_ERR_INITED; + if (osMutexAcquire(queue_mutex, FDCAN_QUEUE_MUTEX_TIMEOUT) != osOK) return BSP_ERR_TIMEOUT; + osMessageQueueId_t queue = BSP_FDCAN_FindQueue(fdcan, can_id); + osMutexRelease(queue_mutex); + if (queue == NULL) return BSP_ERR_NO_DEV; + BSP_FDCAN_Message_t tmp; + while (osMessageQueueGet(queue, &tmp, NULL, BSP_FDCAN_TIMEOUT_IMMEDIATE) == osOK) { } + return BSP_OK; +} + +int8_t BSP_FDCAN_RegisterIdParser(BSP_FDCAN_IdParser_t parser) { + if (!inited) return BSP_ERR_INITED; + if (parser == NULL) return BSP_ERR_NULL; + id_parser = parser; + return BSP_OK; +} + +uint32_t BSP_FDCAN_ParseId(uint32_t original_id, BSP_FDCAN_FrameType_t frame_type) { + if (id_parser != NULL) return id_parser(original_id, frame_type); + return BSP_FDCAN_DefaultIdParser(original_id, frame_type); +} +/* */ + diff --git a/assets/User_code/bsp/fdcan.h b/assets/User_code/bsp/fdcan.h new file mode 100644 index 0000000..99ecd80 --- /dev/null +++ b/assets/User_code/bsp/fdcan.h @@ -0,0 +1,137 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ----------------------------------------------------------------- */ +#include +#include +#include "bsp/bsp.h" +#include "bsp/mm.h" +#include + +/* USER INCLUDE BEGIN */ +#include +/* USER INCLUDE END */ + +/* Exported constants ------------------------------------------------------- */ +#define BSP_FDCAN_MAX_DLC 64 +#define BSP_FDCAN_DEFAULT_QUEUE_SIZE 10 +#define BSP_FDCAN_TIMEOUT_IMMEDIATE 0 +#define BSP_FDCAN_TIMEOUT_FOREVER osWaitForever +#define BSP_FDCAN_TX_QUEUE_SIZE 32 +/* Exported macro ----------------------------------------------------------- */ +//FDCANX实例使能 +/* AUTO GENERATED FDCAN_EN BEGIN */ +#define FDCAN1_EN +#define FDCAN2_EN +#define FDCAN3_EN +/* AUTO GENERATED FDCAN_EN END */ + +// FDCANX接收FIFO选择(0=FIFO0, 1=FIFO1) +/* AUTO GENERATED FDCAN_RX_FIFO BEGIN */ +#ifdef FDCAN1_EN + #define FDCAN1_RX_FIFO 0 +#endif +#ifdef FDCAN2_EN + #define FDCAN2_RX_FIFO 1 +#endif +#ifdef FDCAN3_EN + #define FDCAN3_RX_FIFO 1 +#endif +/* AUTO GENERATED FDCAN_RX_FIFO END */ +/* Exported types ----------------------------------------------------------- */ +typedef enum { + /* AUTO GENERATED BSP_FDCAN_NAME BEGIN */ + BSP_FDCAN_1, + BSP_FDCAN_2, + BSP_FDCAN_3, + /* AUTO GENERATED BSP_FDCAN_NAME END */ + BSP_FDCAN_NUM, + BSP_FDCAN_ERR, +} BSP_FDCAN_t; + +typedef enum { + HAL_FDCAN_TX_EVENT_FIFO_CB, + HAL_FDCAN_TX_BUFFER_COMPLETE_CB, + HAL_FDCAN_TX_BUFFER_ABORT_CB, + HAL_FDCAN_RX_FIFO0_MSG_PENDING_CB, + HAL_FDCAN_RX_FIFO0_FULL_CB, + HAL_FDCAN_RX_FIFO1_MSG_PENDING_CB, + HAL_FDCAN_RX_FIFO1_FULL_CB, + HAL_FDCAN_ERROR_CB, + HAL_FDCAN_CB_NUM, +} BSP_FDCAN_Callback_t; + +typedef enum { + BSP_FDCAN_FORMAT_STD_DATA, + BSP_FDCAN_FORMAT_EXT_DATA, + BSP_FDCAN_FORMAT_STD_REMOTE, + BSP_FDCAN_FORMAT_EXT_REMOTE, +} BSP_FDCAN_Format_t; + +typedef enum { + BSP_FDCAN_FRAME_STD_DATA, + BSP_FDCAN_FRAME_EXT_DATA, + BSP_FDCAN_FRAME_STD_REMOTE, + BSP_FDCAN_FRAME_EXT_REMOTE, +} BSP_FDCAN_FrameType_t; + +typedef struct { + BSP_FDCAN_FrameType_t frame_type; + uint32_t original_id; + uint32_t parsed_id; + uint8_t dlc; + uint8_t data[BSP_FDCAN_MAX_DLC]; + uint32_t timestamp; +} BSP_FDCAN_Message_t; + +typedef struct { + uint32_t id; + uint8_t dlc; + uint8_t data[BSP_FDCAN_MAX_DLC]; +} BSP_FDCAN_StdDataFrame_t; + +typedef struct { + uint32_t id; + uint8_t dlc; + uint8_t data[BSP_FDCAN_MAX_DLC]; +} BSP_FDCAN_ExtDataFrame_t; + +typedef struct { + uint32_t id; + uint8_t dlc; + bool is_extended; +} BSP_FDCAN_RemoteFrame_t; + +typedef uint32_t (*BSP_FDCAN_IdParser_t)(uint32_t original_id, BSP_FDCAN_FrameType_t frame_type); + +typedef struct { + FDCAN_TxHeaderTypeDef header; /* HAL FDCAN header type */ + uint8_t data[BSP_FDCAN_MAX_DLC]; +} BSP_FDCAN_TxMessage_t; + +typedef struct { + BSP_FDCAN_TxMessage_t buffer[BSP_FDCAN_TX_QUEUE_SIZE]; + volatile uint32_t head; + volatile uint32_t tail; +} BSP_FDCAN_TxQueue_t; + +/* Exported functions prototypes -------------------------------------------- */ +int8_t BSP_FDCAN_Init(void); +FDCAN_HandleTypeDef *BSP_FDCAN_GetHandle(BSP_FDCAN_t can); +int8_t BSP_FDCAN_RegisterCallback(BSP_FDCAN_t can, BSP_FDCAN_Callback_t type, void (*callback)(void)); +int8_t BSP_FDCAN_Transmit(BSP_FDCAN_t can, BSP_FDCAN_Format_t format, uint32_t id, uint8_t *data, uint8_t dlc); +int8_t BSP_FDCAN_TransmitStdDataFrame(BSP_FDCAN_t can, BSP_FDCAN_StdDataFrame_t *frame); +int8_t BSP_FDCAN_TransmitExtDataFrame(BSP_FDCAN_t can, BSP_FDCAN_ExtDataFrame_t *frame); +int8_t BSP_FDCAN_TransmitRemoteFrame(BSP_FDCAN_t can, BSP_FDCAN_RemoteFrame_t *frame); +int8_t BSP_FDCAN_RegisterId(BSP_FDCAN_t can, uint32_t can_id, uint8_t queue_size); +int8_t BSP_FDCAN_GetMessage(BSP_FDCAN_t can, uint32_t can_id, BSP_FDCAN_Message_t *msg, uint32_t timeout); +int32_t BSP_FDCAN_GetQueueCount(BSP_FDCAN_t can, uint32_t can_id); +int8_t BSP_FDCAN_FlushQueue(BSP_FDCAN_t can, uint32_t can_id); +int8_t BSP_FDCAN_RegisterIdParser(BSP_FDCAN_IdParser_t parser); +uint32_t BSP_FDCAN_ParseId(uint32_t original_id, BSP_FDCAN_FrameType_t frame_type); +#ifdef __cplusplus +} +#endif diff --git a/assets/User_code/config.csv b/assets/User_code/config.csv index 32290e1..878ede2 100644 --- a/assets/User_code/config.csv +++ b/assets/User_code/config.csv @@ -1,4 +1,4 @@ -bsp,can,dwt,gpio,i2c,mm,spi,uart,pwm,time +bsp,can,fdcan,dwt,gpio,i2c,mm,spi,uart,pwm,time component,ahrs,capacity,cmd,crc8,crc16,error_detect,filter,FreeRTOS_CLI,limiter,mixer,pid,ui,user_math device,dr16,bmi088,ist8310,motor,motor_rm,motor_dm,motor_vesc,motor_lk,motor_lz,motor_odrive,dm_imu,rc_can,servo,buzzer,led,ws2812,vofa,ops9 module,config, \ No newline at end of file