diff --git a/app/code_page/bsp_interface.py b/app/code_page/bsp_interface.py index efbc26c..d48513c 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: @@ -605,6 +613,183 @@ class bsp_can(BspPeripheralBase): ]) filter_bank += 1 # 为下一个CAN分配不同的过滤器组 +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 使能和 FIFO 分配定义""" + 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 使能宏和 FIFO 分配 + enable_lines = [] + fdcan_count = len(configs) + + # 根据 FDCAN 数量分配 FIFO(与 _generate_source_file 中的逻辑一致) + if fdcan_count == 1: + fifo_map = {0: 0} + elif fdcan_count == 2: + fifo_map = {0: 0, 1: 1} + else: # >= 3 + fifo_map = {0: 0, 1: 0, 2: 1} + + for idx, (name, instance) in enumerate(configs): + num = ''.join(filter(str.isdigit, instance)) + fifo_idx = fifo_map.get(idx, 1) + enable_lines.append(f"#define FDCAN{num}_EN") + enable_lines.append(f"#define FDCAN{num}_RX_FIFO {fifo_idx}") + + content = CodeGenerator.replace_auto_generated( + content, "AUTO GENERATED FDCAN_ENABLE", "\n".join(enable_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): + template_path = os.path.join(template_dir, self.template_names['source']) + template_content = CodeGenerator.load_template(template_path) + if not template_content: + return False + + # FDCAN_Get函数 + get_lines = [] + for idx, (name, instance) in enumerate(configs): + if idx == 0: + get_lines.append(f" if (hfdcan->Instance == {instance})") + else: + get_lines.append(f" else if (hfdcan->Instance == {instance})") + get_lines.append(f" 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: + num = ''.join(filter(str.isdigit, instance)) # 提取数字 + handle_lines.append(f" case {self.enum_prefix}_{name}:") + handle_lines.append(f" return &hfdcan{num};") + content = CodeGenerator.replace_auto_generated( + content, f"AUTO GENERATED {self.enum_prefix}_GET_HANDLE", "\n".join(handle_lines) + ) + + # 生成FDCAN初始化代码(类似CAN的策略) + init_lines = [] + fdcan_instances = [instance for _, instance in configs] + fdcan_count = len(fdcan_instances) + + # 根据FDCAN数量分配FIFO + if fdcan_count == 1: + self._generate_single_fdcan_init(init_lines, configs, 0) + elif fdcan_count == 2: + self._generate_dual_fdcan_init(init_lines, configs) + elif fdcan_count >= 3: + self._generate_multi_fdcan_init(init_lines, configs) + + content = CodeGenerator.replace_auto_generated( + content, "AUTO GENERATED FDCAN_INIT", "\n".join(init_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 _generate_single_fdcan_init(self, init_lines, configs, fifo_idx): + """单个FDCAN:使用指定的FIFO""" + for name, instance in configs: + num = ''.join(filter(str.isdigit, instance)) + init_lines.append(f"#ifdef FDCAN{num}_EN") + init_lines.append(f" {{") + init_lines.append(f" FDCAN_HandleTypeDef hfdcan = hfdcan{num};") + init_lines.append(f" FDCAN_FilterTypeDef sFilterConfig = {{0}};") + init_lines.append(f" #define FDCANX_RX_FIFO {fifo_idx}") + init_lines.append(f" #ifdef FDCAN{num}_FILTER_CONFIG_TABLE") + init_lines.append(f" FDCAN{num}_FILTER_CONFIG_TABLE(FDCAN_CONFIG_FILTER)") + init_lines.append(f" #endif") + init_lines.append(f" #ifdef FDCAN{num}_GLOBAL_FILTER") + init_lines.append(f" HAL_FDCAN_ConfigGlobalFilter(&hfdcan{num}, FDCAN{num}_GLOBAL_FILTER);") + init_lines.append(f" #endif") + init_lines.append(f" HAL_FDCAN_ActivateNotification(&hfdcan{num}, FDCANx_NOTIFY_FLAGS(FDCANX_RX_FIFO), 0);") + init_lines.append(f" BSP_FDCAN_RegisterCallback({self.enum_prefix}_{name}, FDCANX_MSG_PENDING_CB(FDCANX_RX_FIFO), BSP_FDCAN_RxFifo{fifo_idx}Callback);") + init_lines.append(f" BSP_FDCAN_RegisterCallback({self.enum_prefix}_{name}, HAL_FDCAN_TX_BUFFER_COMPLETE_CB, BSP_FDCAN_TxCompleteCallback);") + init_lines.append(f" #undef FDCANX_RX_FIFO") + init_lines.append(f" HAL_FDCAN_Start(&hfdcan{num});") + init_lines.append(f" }}") + init_lines.append(f"#endif") + init_lines.append("") + + def _generate_dual_fdcan_init(self, init_lines, configs): + """双FDCAN:FDCAN1用FIFO0,FDCAN2用FIFO1""" + fifo_map = {0: 0, 1: 1} + for idx, (name, instance) in enumerate(configs): + num = ''.join(filter(str.isdigit, instance)) + fifo_idx = fifo_map[idx] + init_lines.append(f"#ifdef FDCAN{num}_EN") + init_lines.append(f" {{") + init_lines.append(f" FDCAN_HandleTypeDef hfdcan = hfdcan{num};") + init_lines.append(f" FDCAN_FilterTypeDef sFilterConfig = {{0}};") + init_lines.append(f" #define FDCANX_RX_FIFO {fifo_idx}") + init_lines.append(f" #ifdef FDCAN{num}_FILTER_CONFIG_TABLE") + init_lines.append(f" FDCAN{num}_FILTER_CONFIG_TABLE(FDCAN_CONFIG_FILTER)") + init_lines.append(f" #endif") + init_lines.append(f" #ifdef FDCAN{num}_GLOBAL_FILTER") + init_lines.append(f" HAL_FDCAN_ConfigGlobalFilter(&hfdcan{num}, FDCAN{num}_GLOBAL_FILTER);") + init_lines.append(f" #endif") + init_lines.append(f" HAL_FDCAN_ActivateNotification(&hfdcan{num}, FDCANx_NOTIFY_FLAGS(FDCANX_RX_FIFO), 0);") + init_lines.append(f" BSP_FDCAN_RegisterCallback({self.enum_prefix}_{name}, FDCANX_MSG_PENDING_CB(FDCANX_RX_FIFO), BSP_FDCAN_RxFifo{fifo_idx}Callback);") + init_lines.append(f" BSP_FDCAN_RegisterCallback({self.enum_prefix}_{name}, HAL_FDCAN_TX_BUFFER_COMPLETE_CB, BSP_FDCAN_TxCompleteCallback);") + init_lines.append(f" #undef FDCANX_RX_FIFO") + init_lines.append(f" HAL_FDCAN_Start(&hfdcan{num});") + init_lines.append(f" }}") + init_lines.append(f"#endif") + init_lines.append("") + + def _generate_multi_fdcan_init(self, init_lines, configs): + """多FDCAN:FDCAN1和FDCAN2用FIFO0,FDCAN3用FIFO1""" + fifo_map = {0: 0, 1: 0, 2: 1} + for idx, (name, instance) in enumerate(configs): + num = ''.join(filter(str.isdigit, instance)) + fifo_idx = fifo_map.get(idx, 1) + init_lines.append(f"#ifdef FDCAN{num}_EN") + init_lines.append(f" {{") + init_lines.append(f" FDCAN_HandleTypeDef hfdcan = hfdcan{num};") + init_lines.append(f" FDCAN_FilterTypeDef sFilterConfig = {{0}};") + init_lines.append(f" #define FDCANX_RX_FIFO {fifo_idx}") + init_lines.append(f" #ifdef FDCAN{num}_FILTER_CONFIG_TABLE") + init_lines.append(f" FDCAN{num}_FILTER_CONFIG_TABLE(FDCAN_CONFIG_FILTER)") + init_lines.append(f" #endif") + init_lines.append(f" #ifdef FDCAN{num}_GLOBAL_FILTER") + init_lines.append(f" HAL_FDCAN_ConfigGlobalFilter(&hfdcan{num}, FDCAN{num}_GLOBAL_FILTER);") + init_lines.append(f" #endif") + init_lines.append(f" HAL_FDCAN_ActivateNotification(&hfdcan{num}, FDCANx_NOTIFY_FLAGS(FDCANX_RX_FIFO), 0);") + init_lines.append(f" BSP_FDCAN_RegisterCallback({self.enum_prefix}_{name}, FDCANX_MSG_PENDING_CB(FDCANX_RX_FIFO), BSP_FDCAN_RxFifo{fifo_idx}Callback);") + init_lines.append(f" BSP_FDCAN_RegisterCallback({self.enum_prefix}_{name}, HAL_FDCAN_TX_BUFFER_COMPLETE_CB, BSP_FDCAN_TxCompleteCallback);") + init_lines.append(f" #undef FDCANX_RX_FIFO") + init_lines.append(f" HAL_FDCAN_Start(&hfdcan{num});") + init_lines.append(f" }}") + init_lines.append(f"#endif") + init_lines.append("") + + class bsp_spi(BspPeripheralBase): def __init__(self, project_path): super().__init__( @@ -1166,6 +1351,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..51a70c6 100644 --- a/app/tools/analyzing_ioc.py +++ b/app/tools/analyzing_ioc.py @@ -84,12 +84,34 @@ class analyzing_ioc: key, value = line.split('=', 1) key = key.strip() value = value.strip() - if key.startswith('Mcu.IP') and value.startswith('CAN'): + 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/bsp/fdcan.c b/assets/User_code/bsp/fdcan.c new file mode 100644 index 0000000..3ddb26d --- /dev/null +++ b/assets/User_code/bsp/fdcan.c @@ -0,0 +1,536 @@ +/* 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; +/* AUTO GENERATED FDCAN_GET */ + 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; + + /* 配置并启动 FDCAN 实例,绑定中断/回调 */ +/* AUTO GENERATED FDCAN_INIT */ + + inited = true; + + //========== 过滤器配置说明:========================== + // 过滤器编号:相对于每个(相当于经典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 实例,绑定中断/回调 */ +/* AUTO GENERATED FDCAN_INIT */ + + inited = true; + +#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 */ + 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..3a53319 --- /dev/null +++ b/assets/User_code/bsp/fdcan.h @@ -0,0 +1,118 @@ +#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 ----------------------------------------------------------- */ +/* AUTO GENERATED FDCAN_ENABLE */ + +/* Exported types ----------------------------------------------------------- */ +typedef enum { + BSP_FDCAN_1, + BSP_FDCAN_2, + BSP_FDCAN_3, + 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 d462c63..592952d 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,oid,lcd_driver module,config, \ No newline at end of file