添加fdcan

This commit is contained in:
Robofish 2026-01-01 16:58:36 +08:00
parent 3e246f1de6
commit 3da379c832
8 changed files with 835 additions and 25 deletions

22
.vscode/settings.json vendored
View File

@ -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"
}
}

View File

@ -318,6 +318,14 @@ def get_available_can(project_path):
return analyzing_ioc.get_enabled_can_from_ioc(ioc_path) return analyzing_ioc.get_enabled_can_from_ioc(ioc_path)
return [] 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): def get_available_spi(project_path):
ioc_files = [f for f in os.listdir(project_path) if f.endswith('.ioc')] ioc_files = [f for f in os.listdir(project_path) if f.endswith('.ioc')]
if ioc_files: 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): def patch_uart_interrupts(project_path, uart_instances):
"""自动修改 stm32f4xx_it.c插入 UART BSP 相关代码""" """自动修改 stm32f4xx_it.c插入 UART BSP 相关代码"""
it_path = os.path.join(project_path, "Core/Src/stm32f4xx_it.c") 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 = { special_classes = {
"i2c": bsp_i2c, "i2c": bsp_i2c,
"can": bsp_can, "can": bsp_can,
"fdcan": bsp_fdcan,
"spi": bsp_spi, "spi": bsp_spi,
"uart": bsp_uart, "uart": bsp_uart,
"gpio": bsp_gpio, "gpio": bsp_gpio,

View File

@ -71,7 +71,7 @@ class analyzing_ioc:
@staticmethod @staticmethod
def get_enabled_can_from_ioc(ioc_path): def get_enabled_can_from_ioc(ioc_path):
""" """
获取已启用的CAN列表 获取已启用的CAN列表不包括FDCAN
返回格式: ['CAN1', 'CAN2'] 返回格式: ['CAN1', 'CAN2']
""" """
enabled_can = [] enabled_can = []
@ -84,12 +84,35 @@ class analyzing_ioc:
key, value = line.split('=', 1) key, value = line.split('=', 1)
key = key.strip() key = key.strip()
value = value.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 can_name = value.split('.')[0] if '.' in value else value
if can_name not in enabled_can: if can_name not in enabled_can:
enabled_can.append(can_name) enabled_can.append(can_name)
return sorted(enabled_can) 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 @staticmethod
def get_enabled_uart_from_ioc(ioc_path): def get_enabled_uart_from_ioc(ioc_path):
""" """

Binary file not shown.

View File

@ -1,5 +1,6 @@
uart,请开启uart的dma和中断 uart,请开启uart的dma和中断
can,请开启can中断使用函数前请确保can已经初始化。一定要开启can发送中断 can,请开启can中断使用函数前请确保can已经初始化。一定要开启can发送中断
fdcan,请开启fdcan中断支持经典CAN和FDCAN模式。会自动根据IOC配置生成对应的宏定义。
gpio,会自动读取cubemx中配置为gpio的引脚并自动区分输入输出和中断。 gpio,会自动读取cubemx中配置为gpio的引脚并自动区分输入输出和中断。
spi,请开启spi的dma和中断 spi,请开启spi的dma和中断
i2c,要求开始spi中断 i2c,要求开始spi中断

1 uart 请开启uart的dma和中断
2 can 请开启can中断,使用函数前请确保can已经初始化。一定要开启can发送中断!!!
3 fdcan 请开启fdcan中断,支持经典CAN和FDCAN模式。会自动根据IOC配置生成对应的宏定义。
4 gpio 会自动读取cubemx中配置为gpio的引脚,并自动区分输入输出和中断。
5 spi 请开启spi的dma和中断
6 i2c 要求开始spi中断

View File

@ -0,0 +1,576 @@
/* Includes ----------------------------------------------------------------- */
#include "fdcan.h"
#include "bsp/fdcan.h"
#include "bsp/bsp.h"
#include <fdcan.h>
#include <cmsis_os2.h>
#include <string.h>
/* 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);
}
/* */

View File

@ -0,0 +1,137 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ----------------------------------------------------------------- */
#include <stdint.h>
#include <stdbool.h>
#include "bsp/bsp.h"
#include "bsp/mm.h"
#include <cmsis_os.h>
/* USER INCLUDE BEGIN */
#include <fdcan.h>
/* 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

View File

@ -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 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 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, module,config,
1 bsp,can,dwt,gpio,i2c,mm,spi,uart,pwm,time bsp,can,fdcan,dwt,gpio,i2c,mm,spi,uart,pwm,time
2 component,ahrs,capacity,cmd,crc8,crc16,error_detect,filter,FreeRTOS_CLI,limiter,mixer,pid,ui,user_math component,ahrs,capacity,cmd,crc8,crc16,error_detect,filter,FreeRTOS_CLI,limiter,mixer,pid,ui,user_math
3 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 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
4 module,config, module,config,