mirror of
https://github.com/goldenfishs/MRobot.git
synced 2026-02-04 18:00:19 +08:00
更新fdcan
This commit is contained in:
parent
b2c24ef6bd
commit
ba291f2c28
@ -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:
|
||||||
@ -605,6 +613,183 @@ class bsp_can(BspPeripheralBase):
|
|||||||
])
|
])
|
||||||
filter_bank += 1 # 为下一个CAN分配不同的过滤器组
|
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):
|
class bsp_spi(BspPeripheralBase):
|
||||||
def __init__(self, project_path):
|
def __init__(self, project_path):
|
||||||
super().__init__(
|
super().__init__(
|
||||||
@ -1166,6 +1351,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,
|
||||||
|
|||||||
@ -84,12 +84,34 @@ 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'):
|
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):
|
||||||
"""
|
"""
|
||||||
|
|||||||
536
assets/User_code/bsp/fdcan.c
Normal file
536
assets/User_code/bsp/fdcan.c
Normal file
@ -0,0 +1,536 @@
|
|||||||
|
/* 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;
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
/* */
|
||||||
|
|
||||||
118
assets/User_code/bsp/fdcan.h
Normal file
118
assets/User_code/bsp/fdcan.h
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
#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 ----------------------------------------------------------- */
|
||||||
|
/* 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
|
||||||
@ -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,oid,lcd_driver
|
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,
|
module,config,
|
||||||
|
Loading…
Reference in New Issue
Block a user