-
Notifications
You must be signed in to change notification settings - Fork 55
Open
Description
weifengdq: 详细解读hpm_mcan_soc.h
GitHub Copilot: 下面是对当前头文件的逐段解读与改进建议要点。
文件作用
- 为 HPMicro HPM53xx 平台上的 MCAN 外设提供 SoC 相关适配:消息 RAM(AHB_RAM)地址/大小约束、外部时间基选择(TSU/TBSEL)、待机脚控制,以及基于寄存器基地址推导实例号等。
- 提供一组内联函数,便于上层驱动快速访问和配置这些 SoC 相关特性。
关键类型与全局
- mcan_msg_buf_attr_t:描述每个 MCAN 实例使用的消息缓冲(AHB_RAM)区间,包含 ram_base 与 ram_size,单位字节。
- mcan_soc_msg_buf_attr[]:外部定义的全局数组,按实例号存放每个 MCAN 的消息 RAM 属性。
重要宏与常量
- HPM_MCAN_TBSEL_BASE/HPM_MCAN_TBSEL:TBSEL 外部时间基选择寄存器的物理地址映射(0xF02FF000)。通过该 32 位寄存器为最多 4 路 ext_tbsel 配置时间源。
- HPM_MCAN_TBSEL_BITWIDTH=6/HPM_MCAN_TBSEL_MASK/SHIFT:每路 TBSEL 选择域宽 6 bit,从 bit8 起,每路间隔 6 bit。
- 外部时间基编号:0~3(HPM_MCAN_EXT_TBSEL_NUM=4)。
- AHB_RAM 有效区间:
- 起始:MCAN_MSG_BUF_BASE_VALID_START=0xF0400000
- 最大:32KB
- 结束:MCAN_MSG_BUF_BASE_VALID_END=起始+最大
- 对齐:MCAN_MSG_BUF_ALIGNMENT_SIZE=4 字节
- MCAN_IP_SLOT_SIZE=0x4000:MCAN 寄存器块槽位大小,用于根据基地址推导实例序号。
- TSU 时间基选项宏:MCAN_TSU_TBSEL_PTPC0、MCAN_TSU_TBSEL_MCANx 等,表示把 TBSEL 对应的外部时间基接到 PTPC0 或某个 MCAN 的内部时间基输出。
内联函数解读
- mcan_get_instance_from_base(MCAN_Type*):
- 用基地址与 HPM_MCAN0_BASE 的差,除以槽位大小 0x4000 计算实例号。
- 假设各 MCAN 外设地址连续且等距。
- mcan_set_tsu_ext_timebase_src(MCAN_Type*, uint8_t src):
- 设置 TSU 的“外部时间输入选择”字段(GLB_CTL.TSU_TBIN_SEL)。src 范围 0..3。
- mcan_set_tsu_tbsel_option(MCAN_Type*, uint8_t ext_tbsel, uint8_t tbsel_option):
- 选择某一路外部 TBSEL 的时间来源(写 HPM_MCAN_TBSEL 指定域)。
- ext_tbsel 0..3,tbsel_option 6 bit 有效。写法为先算移位与掩码再合成。
- mcan_enable_standby_pin/mcan_disable_standby_pin:
- 置/清 GLB_CTL.M_CAN_STBY 控制待机脚。
- mcan_set_msg_buf_attr(MCAN_Type*, const mcan_msg_buf_attr_t*):
- 参数有效性检查:
- 指针非空
- ram_base 落在合法 AHB_RAM 区间内,且 ram_base+ram_size 不越界
- ram_size 不大于 AHB_RAM 最大容量
- ram_base 与 ram_size 均为 4 字节对齐
- 实例号在范围内
- 通过实例号把属性写入 mcan_soc_msg_buf_attr[]。
- 参数有效性检查:
- mcan_get_ram_base():
- 固定返回 AHB_RAM 基地址(不是实例专属基址)。真正实例偏移由 mcan_get_ram_offset 提供。
- mcan_get_ram_offset(MCAN_Type*):
- 返回该实例相对 AHB_RAM 起点的偏移(由先前 set_msg_buf_attr 设置的 ram_base 决定)。
- mcan_get_ram_size(MCAN_Type*):
- 返回该实例配置的消息 RAM 大小。
易错点与建议
- 字符串拼写错误:
- 头尾 C++ 兼容宏写成了 __cpluspus,正确应为 __cplusplus。
- 命名可能的笔误:
- 宏 MCAN_MSG_BUG_SIZE_MAX 似为 MCAN_MSG_BUF_SIZE_MAX 的笔误。建议保留别名兼容,统一使用 BUF。
- 边界/健壮性:
- mcan_get_ram_offset/mcan_get_ram_size 未再次校验实例号范围;若未先调用 mcan_set_msg_buf_attr 进行初始化,可能访问未初始化内容。建议在这两个 getter 中补充实例范围检查。
- mcan_set_msg_buf_attr 可考虑禁止 ram_size 为 0。
- 并发/原子性:
- 对 HPM_MCAN_TBSEL 的读改写在并发环境下可能被打断,建议在临界区或关中断上下文中执行,或以位带/掩码原子写支持为准。
- 可移植性:
- mcan_get_instance_from_base 中把指针强转为 uint32_t 依赖 32 位地址宽度;在该 MCU 平台上合理,但在不同编译环境可考虑使用 uintptr_t。
可选修改建议(补丁)
- 修复 __cplusplus 宏拼写错误。
- 引入 MCAN_MSG_BUF_SIZE_MAX 并保留旧名别名。
- 在 getter 中补充实例号校验;在 setter 中禁止 size=0。
- 在条件判断中统一使用新的 BUF 名称。
// ...existing code...
#ifdef __cpluspus
extern "C" {
#endif
// ...existing code...
#define MCAN_MSG_BUF_BASE_VALID_START (0xF0400000UL) /* This is the start address of AHB_RAM */
#define MCAN_MSG_BUF_SIZE_MAX (32UL * 1024UL) /* This is the total size of AHB_RAM */
/* Backward-compat alias (typo kept for existing code) */
#define MCAN_MSG_BUG_SIZE_MAX MCAN_MSG_BUF_SIZE_MAX
#define MCAN_MSG_BUF_BASE_VALID_END (MCAN_MSG_BUF_BASE_VALID_START + MCAN_MSG_BUF_SIZE_MAX)
// ...existing code...
static inline hpm_stat_t mcan_set_msg_buf_attr(MCAN_Type *ptr, const mcan_msg_buf_attr_t *attr)
{
if ((attr == NULL) || \
(attr->ram_base < MCAN_MSG_BUF_BASE_VALID_START) || \
(attr->ram_base >= MCAN_MSG_BUF_BASE_VALID_END) || \
(attr->ram_size == 0U) || \
(attr->ram_size > MCAN_MSG_BUF_SIZE_MAX) || \
(attr->ram_base + attr->ram_size > MCAN_MSG_BUF_BASE_VALID_END) || \
(attr->ram_base % MCAN_MSG_BUF_ALIGNMENT_SIZE != 0U) || \
(attr->ram_size % MCAN_MSG_BUF_ALIGNMENT_SIZE != 0U)) {
return status_invalid_argument;
}
uint32_t instance = mcan_get_instance_from_base(ptr);
if (instance >= MCAN_SOC_MAX_COUNT) {
return status_invalid_argument;
}
mcan_soc_msg_buf_attr[instance].ram_base = attr->ram_base;
mcan_soc_msg_buf_attr[instance].ram_size = attr->ram_size;
return status_success;
}
// ...existing code...
static inline uint32_t mcan_get_ram_offset(MCAN_Type *ptr)
{
uint32_t instance = mcan_get_instance_from_base(ptr);
if (instance >= MCAN_SOC_MAX_COUNT) {
return 0U;
}
return (mcan_soc_msg_buf_attr[instance].ram_base - MCAN_MSG_BUF_BASE_VALID_START);
}
// ...existing code...
static inline uint32_t mcan_get_ram_size(MCAN_Type *ptr)
{
uint32_t instance = mcan_get_instance_from_base(ptr);
if (instance >= MCAN_SOC_MAX_COUNT) {
return 0U;
}
return mcan_soc_msg_buf_attr[instance].ram_size;
}
// ...existing code...
#ifdef __cplusplus
}
#endif
// ...existing code...简要用法示例
- 为各实例分配 AHB_RAM 子区并设置属性:
#include "hpm_mcan_drv.h"
#include "hpm_mcan_soc.h"
void mcan_init_ram(void)
{
const uint32_t ahb_base = MCAN_MSG_BUF_BASE_VALID_START;
const uint32_t ahb_size = MCAN_MSG_BUF_SIZE_MAX; // 32KB
const uint32_t inst_cnt = MCAN_SOC_MAX_COUNT;
uint32_t chunk = (ahb_size / inst_cnt) & ~((uint32_t)MCAN_MSG_BUF_ALIGNMENT_SIZE - 1U);
for (uint32_t i = 0; i < inst_cnt; i++) {
MCAN_Type *base = (MCAN_Type *)(HPM_MCAN0_BASE + i * MCAN_IP_SLOT_SIZE);
mcan_msg_buf_attr_t attr = {
.ram_base = ahb_base + i * chunk,
.ram_size = chunk
};
(void)mcan_set_msg_buf_attr(base, &attr);
}
}- 配置 TSU 外部时间基 0 来自 PTPC0,选择 TSU 输入为 TBSEL_0:
void mcan_config_timebase(MCAN_Type *base)
{
// 选择外部时间输入源索引 0
mcan_set_tsu_ext_timebase_src(base, MCAN_TSU_EXT_TIMEBASE_SRC_TBSEL_0);
// 设置 TBSEL_0 的来源为 PTPC0
mcan_set_tsu_tbsel_option(base, 0, MCAN_TSU_TBSEL_PTPC0);
}- 控制待机脚:
void mcan_standby(MCAN_Type *base, bool enable)
{
if (enable) {
mcan_enable_standby_pin(base);
} else {
mcan_disable_standby_pin(base);
}
}测试与注意事项
- 在单元测试中应覆盖:
- 非法地址/大小/对齐时返回 status_invalid_argument。
- 设置后 get_ram_offset/get_ram_size 返回期望值。
- 越界实例(伪造 base)时 getter 返回 0。
- 若在中断或多核环境中更新 HPM_MCAN_TBSEL,建议加临界区,避免并发读改写。
weifengdq: 详细解读hpm_mcan_drv.h
GitHub Copilot: 下面是对 hpm_mcan_drv.h 的结构化解读、用法提示与可改进点。
文件职责概览
- 定义 HPM M_CAN 驱动的对外数据结构、宏与 API 原型,以及少量性能关键的内联寄存器访问函数。
- 覆盖功能:初始化/反初始化、RAM 布局配置(简化/灵活两种方案)、滤波器配置、收发帧格式、事件/状态/错误查询、TSU 时间戳访问、中断管理、超时计数、TDC 配置等。
- 与 soc 适配层 hpm_mcan_soc.h 配合使用(实例号、AHB RAM 边界、TSU 外部时间源 TBSEL 选择等)。
关键数据结构与用途
- 帧与事件
- mcan_tx_frame_t/mcan_rx_message_t:发送/接收帧结构,前两字包含标识符+控制域,后续为最大 64 字节数据。通过位段描述 std_id/ext_id、RTR、ESI、BRS、DLC 等。
- mcan_tx_event_fifo_elem_t:TX 事件元素,含标识符、DLC、BRS、CANFD、事件类型、时间戳/时间戳指针等。
- RAM 布局
- mcan_ram_flexible_config_t:最细粒度配置,需手动指定每一块(滤波、RXFIFO0/1、RXBUF、TXBUF、TXEVT)起始地址/元素数/水位等,适合熟悉 IP 的用户。
- mcan_ram_config_t:简化配置,仅提供各模块是否启用、元素数、数据域大小等,驱动自动计算布局与起始地址,适合大多数用户。
- 滤波相关
- mcan_filter_elem_t/mcan_filter_elem_list_t、mcan_all_filters_config_t:标准/扩展滤波元素列表与全局滤波配置(非匹配帧去向、远程帧拒绝、扩展 ID 掩码)。
- 时序与时间戳
- mcan_bit_timing_param_t + mcan_bit_timing_option_t:提供“自动算参数”与“直接给定分频/段/同步跳宽”的两种风格。
- mcan_tdc_config_t:发射延迟补偿。
- mcan_internal_timestamp_config_t:内部时间戳分频与选择。
- mcan_tsu_config_t:外部时间戳单元(TSU)配置,含是否用外部时间基、来源/tbsel 选项、64 位时间戳等;与 soc 层 TSU 相关宏配合。
- mcan_timestamp_value_t:统一封装 16/32/64 位时间戳读取结果。
- 错误与状态
- mcan_last_err_code_t、mcan_activity_state_t、mcan_error_count_t、mcan_protocol_status_t:错误码/活动状态/错误计数/协议状态抽象。
- 中断
- 一组 MCAN_INT_* 掩码与事件集合(接收/发送/错误)。
- 便捷内联:启停/使能/选择中断线、查询与清除中断标志、TXBUF 专属中断掩码等。
核心内联 API 速览
- 模式/控制:mcan_enter_init_mode/mcan_enter_normal_mode、mcan_enable_disable_*(TXP/EFBI/PXHD/WMM/UTSU/BRSE/DAR/ASM/MON/CSR)。
- 时钟与计数:mcan_enable_clock/mcan_stop_clock/mcan_is_clock_stopped、mcan_get_timestamp_counter_value、mcan_get_timeout_counter_value/mcan_reset_timeout_counter_value。
- 状态与错误:mcan_get_error_counter、mcan_get_last_error_code/mcan_get_last_data_error_code、mcan_get_activity、mcan_is_in_* 状态、mcan_get_transmitter_delay_compensation_value。
- 中断:mcan_enable/disable_interrupts、mcan_interrupt_line_select、mcan_get/clear_interrupt_flags;TXBUF 传输/取消完成中断的独立开关。
- 发送队列:mcan_is_txfifo_full、mcan_get_txfifo_put_index、mcan_send_add_request/mcan_send_add_multiple_requests、mcan_cancel_tx_buf_send_request、mcan_is_tx_buf_cancellation_finished、mcan_is_transmit_request_pending/mcan_is_transmit_occurred。
- 接收队列:mcan_is_rxbuf_data_available/mcan_clear_rxbuf_data_available_flag。
- TSU:mcan_enable_tsu/mcan_is_tsu_used、mcan_is_64bit_tsu_timestamp_used、mcan_is_tsu_timestamp_available;配套的读取函数原型 mcan_read_32bit_tsu_timestamp/mcan_read_64bit_tsu_timestamp。
非内联的主要函数原型
- 缺省配置:mcan_get_default_config、mcan_get_default_ram_flexible_config、mcan_get_default_ram_config。
- 初始化:mcan_init/mcan_deinit;其中 init 通常会处理位时序、模式、RAM 布局、滤波、TDC、时间戳、超时、中断等。
- RAM 配置:mcan_config_ram_with_flexible_config、mcan_config_ram。
- 滤波:mcan_config_all_filters、mcan_set_filter_element。
- 收发:mcan_write_txbuf、mcan_write_txfifo、mcan_request_and_fill_txfifo、mcan_transmit_*、mcan_read_rxbuf、mcan_read_rxfifo、mcan_read_tx_evt_fifo。
- 时间戳抽取:mcan_get_timestamp_from_tx_event、mcan_get_timestamp_from_received_message。
- 协议状态:mcan_parse_protocol_status、mcan_get_protocol_status。
- 工具:mcan_get_message_size_from_dlc、mcan_get_data_field_size。
与 soc 层的衔接
- RAM 空间与对齐限制由 soc 层定义(mcan_set_msg_buf_attr/mcan_get_ram_*)。
- TSU 外部时间源与 TBSEL 硬件寄存器地址在 soc 层(mcan_set_tsu_ext_timebase_src、mcan_set_tsu_tbsel_option)。
典型使用流程示例(简化)
#include "hpm_mcan_drv.h"
#include "hpm_clock.h"
static void can_init(MCAN_Type *base, uint32_t ahb_clk_hz)
{
mcan_config_t cfg;
mcan_get_default_config(base, &cfg);
cfg.mode = mcan_mode_normal;
cfg.enable_canfd = true;
cfg.enable_tdc = true;
cfg.use_lowlevel_timing_setting = false;
cfg.baudrate = 500000; // nominal
cfg.baudrate_fd = 2000000; // data
// RAM 简化配置(默认会在 mcan_get_default_ram_config 中给出合理值)
mcan_get_default_ram_config(base, &cfg.ram_config, cfg.enable_canfd);
// 中断:接收、新消息、传输完成等
cfg.interrupt_mask = MCAN_EVENT_RECEIVE | MCAN_EVENT_TRANSMIT;
if (mcan_init(base, &cfg, ahb_clk_hz) != status_success) {
// 处理错误
}
}
static void can_tx_example(MCAN_Type *base)
{
mcan_tx_frame_t tx = {0};
tx.use_ext_id = 0;
tx.std_id = 0x123;
tx.dlc = 8;
tx.canfd_frame = 1;
tx.bitrate_switch = 1;
for (int i = 0; i < 8; i++) tx.data_8[i] = (uint8_t)i;
(void)mcan_transmit_blocking(base, &tx);
}
static void can_rx_example(MCAN_Type *base)
{
mcan_rx_message_t rx;
(void)mcan_receive_from_fifo_blocking(base, 0, &rx); // FIFO0
}易错点与改进建议
- 中断线使能可能覆盖已有位
- mcan_interrupt_line_select 最后写 ptr->ILE = (1UL << line_index) 会清掉已使能的其它中断线位,建议改为 OR。
- 多处“超时配置”定义重复
- 已有 mcan_timeout_sel_t/mcan_timeout_config_t,同时又定义了 MCAN_TIMEOUT_SEL_TYPE_* 宏与 mcan_timeout_counter_config_t,语义上重复,建议仅保留一套 API,以免混淆。
- 滤波类型宏存在无值定义
- MCAN_FILTER_TYPE_DUAL_ID_EXT_FILTER_IGNORE_MASK 宏没有赋值,且 M_CAN 标准 SFT 仅有 0..3 四种类型,建议删除该多余宏。
- 文字/注释细节
- “SIze”“QQueue”等注释小拼写问题可修正,减少歧义。
- 索引范围校验
- 若对外暴露的非内联函数内部已做边界检查则无问题;内联如 mcan_is_transmit_request_pending/mcan_is_rxbuf_data_available 等,调用侧需确保 index 在硬件支持范围,否则读写无效位。
- 位段与可移植性
- 帧结构使用位段描述寄存器格式,编译器/ABI 对位段布局要求一致;作为寄存器访问用途问题不大,但不建议跨编译器/端序序列化为线上的报文。
- mcan_reset_timeout_counter_value
- 当前通过 32 位写指针清零,直接对 TOCV 赋 0 更直观,volatile 已保证写访问。
建议补丁(不影响对外 API)
// ...existing code...
#define MCAN_FILTER_TYPE_RANGE_FILTER (0U) /*!< CAN Identifier Range filter */
#define MCAN_FILTER_TYPE_SPECIFIED_ID_FILTER (1U) /*!< CAN Identifier ID filter */
#define MCAN_FILTER_TYPE_CLASSIC_FILTER (2U) /*!< CAN classic filter */
#define MCAN_FILTER_TYPE_FILTER_DISABLED (3U) /*!< CAN filter disabled */
// 删除多余且无取值的宏,避免误用
/* #define MCAN_FILTER_TYPE_DUAL_ID_EXT_FILTER_IGNORE_MASK */
// ...existing code...
static inline void mcan_interrupt_line_select(MCAN_Type *ptr, uint32_t mask, uint8_t line_index)
{
if (line_index == 0) {
ptr->ILS &= ~mask;
} else {
ptr->ILS |= mask;
}
// 仅置位目标线,不覆盖其他线的使能
ptr->ILE |= (1UL << line_index);
}
// ...existing code...
static inline void mcan_reset_timeout_counter_value(MCAN_Type *ptr)
{
// 直接对寄存器清零,volatile 可避免被优化掉
ptr->TOCV = 0U;
}
// ...existing code...
/* 修正文档小拼写 */
// #define MCAN_FILTER_ELEM_EXT_ID_SIZE (8U) /*!< Extended Filter Element Size in Bytes */
// “TXFIFO/QQueue” -> “TXFIFO/Queue”
// ...existing code...结语
- 该头文件提供了完整的 M_CAN 驱动“接口层”,与 soc 适配层共同覆盖从外设初始化、RAM 布局、滤波、收发到时间戳与中断管理的常见需求。上层应用可优先采用默认配置与简化 RAM 配置,快速跑通,再基于灵活配置做精细优化。
找到具有 1 个许可证类型的类似代码
weifengdq: 详细解读hpm_mcan_drv.c
GitHub Copilot: 下面是对当前 hpm_mcan_drv.c 的结构化解读,并给出若干明显问题与可选修复补丁。你当前选中的函数位于文件末段,已单独说明。
文件职责与结构
- 常量/限制定义:包含各类元素上限(标准/扩展滤波条目、RXFIFO/RXBUF/TXBUF/TXEVT 元素数)、位时序范围(CAN2.0、CANFD Nominal、CANFD Data)、采样点范围等。
- 位时序计算:
- mcan_calc_bit_timing_from_baudrate:根据时钟/波特率/采样点推导分频、Seg1、Seg2、SJW。
- mcan_set_bit_timing_from_baudrate:封装上面的计算并写入 NBTP/DBTP。
- is_mcan_bit_timing_param_valid:对用户自定义时序参数做合法性校验。
- RAM 默认布局:
- mcan_get_default_ram_config:为简化配置结构 mcan_ram_config_t 预分配标准/扩展滤波、TXBUF、RXFIFO0/1、RXBUF、TXEVT 的大小与顺序,依据是否 CANFD 选不同尺寸。
- mcan_get_default_ram_flexible_config:为灵活配置结构 mcan_ram_flexible_config_t 计算每段起始地址/大小。
- RAM 寄存器配置:
- mcan_config_ram:使用简化配置计算每段大小与元素数,写入 SIDFC/XIDFC、RXF0C/RXF1C、RXBC/RXESC、TXBC/TXESC、TXEFC,并检测超出 RAM。
- mcan_config_ram_with_flexible_config:直接写入灵活配置提供的寄存器值,同时做元素数上限检查。
- 过滤器配置:
- k_default_std_id_filter/k_default_ext_id_filter:经典过滤默认接受全部,放入 RXFIFO0。
- mcan_config_all_filters:写 GFC/XIDAM,并将标准/扩展列表逐条写入消息 RAM。
- mcan_set_filter_element:按标准/扩展编码写入对应 FLSSA/FLESA 列表项。
- 初始化/反初始化:
- mcan_get_default_config:生成一套默认的波特率、过滤、RAM、时间戳/TSU、超时等配置。
- mcan_init:开时钟、进 INIT/CCE、设置位时序(自动/手动)、模式、CANFD、NISO、TXP/EFBI/PXHD/WMM/DAR/ASM、TDC、TSU、内部时间戳、清空并配置 RAM、配置过滤器、中断、超时、退出 INIT。
- mcan_deinit:进入 INIT,恢复关键寄存器默认值,关闭中断并清标志。
- 发送/接收路径:
- 地址与尺寸辅助:mcan_get_rxfifo0_base/1_base、mcan_get_rxbuf_elem_addr、mcan_get_txbuf_elem_addr、mcan_get_message_size_from_dlc、mcan_get_data_field_size。
- 写入发送:mcan_write_txbuf、mcan_write_txfifo,非阻塞提交:mcan_transmit_via_txbuf_nonblocking/mcan_transmit_via_txfifo_nonblocking,请求并回填 FIFO:mcan_request_and_fill_txfifo,阻塞发送:mcan_transmit_blocking。
- 接收读取:mcan_read_rxbuf、mcan_read_rxfifo,阻塞接收:mcan_receive_from_buf_blocking/mcan_receive_from_fifo_blocking。
- 事件:mcan_read_tx_evt_fifo。
- 时间戳/TSU:
- mcan_set_tsu/mcan_set_internal_timestamp:配置 TSU 与内部时间戳。
- mcan_read_32bit_tsu_timestamp/mcan_read_64bit_tsu_timestamp:读取 TSU 时间戳(64 位存在索引对齐和清位 workaround)。
- mcan_get_timestamp_from_tx_event/mcan_get_timestamp_from_received_message:根据是否使用 TSU、是否捕获,返回 16/32/64 位时间戳。
- 协议状态:
- mcan_parse_protocol_status:解析 PSR,填充 protocol_status(异常、CANFD、BRS/ESI、BusOff/Warning/ErrorPassive、ACT 活动状态、TDCV、以及 LEC/DLEC)。
- mcan_get_protocol_status:读取 ptr->PSR 并调用解析。
你选中的函数详解
- 函数:mcan_get_protocol_status(MCAN_Type *ptr, mcan_protocol_status_t *protocol_status)
- 行为:
- 判空;若合法则读取 PSR 并调用 mcan_parse_protocol_status 填充 protocol_status。
- 解析规则在 mcan_parse_protocol_status 中:
- 若上一帧接收为 CAN FD 且 BRS 置位,使用 DLEC 作为 last_error_code;否则使用 LEC。
- activity 取自 PSR.ACT,tdc_val 取自 PSR.TDCV,其他布尔状态按各位判断。
- 返回:status_success 或参数非法。
潜在问题与建议
- memset 使用了错误的结构尺寸
- mcan_get_default_ram_flexible_config 中清零用了 sizeof(mcan_ram_config_t),应为 sizeof(mcan_ram_flexible_config_t)。
- CANFD 灵活配置的 TXBUF 空间计算错误
- 在 enable_canfd == true 分支,TXBUF 大小增量使用了 CAN 的默认尺寸与最大元素字节数,应改为 CANFD 对应值。
- 扩展滤波表空间增量错误
- mcan_config_ram 中 XIDFC 后的 start_addr 增量错误地使用了 std_filter_elem_count,应该用 ext_filter_elem_count。
- RXBUF 元素数上限检查与常量不匹配
- mcan_config_ram 对 RXBUF 用了 MCAN_RXFIFO_ELEM_CNT_MAX 检查,应改用 MCAN_RXBUF_ELEM_CNT_MAX。
- TXBUF 元素数上限检查常量不匹配
- mcan_config_ram 中把 TXBUF 元素数与 MCAN_TXEVT_FIFO_ELEM_CNT_MAX 比较,应使用 MCAN_TXBUF_ELEM_CNT_MAX。
- RXFIFO 水位未使用配置值
- mcan_config_ram 中 rxfifo_config.watermark 固定为 1U,应使用 config->rxfifos[i].watermark。
- deinit 中重复设置 XIDAM
- 先写 0 再写 0x1FFFFFFF,多余;保留后者即可。
可选修复补丁
- 修复以上问题,尽量小改动、向后兼容。
// ...existing code...
void mcan_get_default_ram_flexible_config(MCAN_Type *ptr, mcan_ram_flexible_config_t *ram_config, bool enable_canfd)
{
- (void) memset(ram_config, 0, sizeof(mcan_ram_config_t));
+ (void) memset(ram_config, 0, sizeof(mcan_ram_flexible_config_t));
uint32_t start_addr = mcan_get_ram_offset(ptr);
// ...existing code...
} else {
ram_config->enable_std_filter = true;
// ...existing code...
ram_config->txbuf_elem_config.data_field_size = MCAN_DATA_FIELD_SIZE_64BYTES;
- start_addr += MCAN_TXBUF_SIZE_CAN_DEFAULT * MCAN_TXRX_ELEM_SIZE_CAN_MAX;
+ start_addr += MCAN_TXBUF_SIZE_CANFD_DEFAULT * MCAN_TXRX_ELEM_SIZE_CANFD_MAX;
// ...existing code...
}
// ...existing code...
}
// ...existing code...
hpm_stat_t mcan_config_ram(MCAN_Type *ptr, mcan_ram_config_t *config)
{
hpm_stat_t status = status_invalid_argument;
do {
// ...existing code...
if (config->enable_ext_filter) {
if (config->ext_filter_elem_count > MCAN_EXT_FILTER_ELEM_CNT_MAX) {
break;
}
mcan_filter_config_t filter_config = { .reg_val = 0 };
filter_config.list_size = config->ext_filter_elem_count;
filter_config.list_start_addr = start_addr;
ptr->XIDFC = filter_config.reg_val;
- start_addr += MCAN_FILTER_ELEM_EXT_ID_SIZE * (uint32_t) config->std_filter_elem_count;
+ start_addr += MCAN_FILTER_ELEM_EXT_ID_SIZE * (uint32_t) config->ext_filter_elem_count;
} else {
ptr->XIDFC = MCAN_RAM_ADDR_INVALID;
}
// ...existing code...
mcan_rxfifo_config_t rxfifo_config = { .reg_val = 0 };
rxfifo_config.start_addr = start_addr;
- rxfifo_config.watermark = 1U;
+ rxfifo_config.watermark = config->rxfifos[i].watermark;
rxfifo_config.operation_mode = config->rxfifos[i].operation_mode;
rxfifo_config.fifo_size = elem_count;
mcan_config_rxfifo(ptr, i, rxfifo_config.reg_val);
// ...existing code...
if (config->enable_rxbuf) {
elem_bytes = mcan_get_data_field_size(config->rxbuf_data_field_size) + MCAN_MESSAGE_HEADER_SIZE_IN_BYTES;
elem_count = config->rxbuf_elem_count;
- if (elem_count > MCAN_RXFIFO_ELEM_CNT_MAX) {
+ if (elem_count > MCAN_RXBUF_ELEM_CNT_MAX) {
break;
}
ptr->RXBC = start_addr;
rx_fifo_buf_elem_config.buf_data_field_size = config->rxbuf_data_field_size;
// ...existing code...
}
// ...existing code...
if (config->enable_txbuf) {
// ...existing code...
elem_count = config->txbuf_fifo_or_queue_elem_count + config->txbuf_dedicated_txbuf_elem_count;
- if (elem_count > MCAN_TXEVT_FIFO_ELEM_CNT_MAX) {
+ if (elem_count > MCAN_TXBUF_ELEM_CNT_MAX) {
break;
}
// ...existing code...
ptr->TXESC = (uint32_t) config->txbuf_data_field_size;
} else {
- ptr->TXESC = MCAN_RAM_ADDR_INVALID;
+ ptr->TXESC = 0U;
}
// ...existing code...
} while (false);
return status;
}
// ...existing code...
hpm_stat_t mcan_config_ram_with_flexible_config(MCAN_Type *ptr, mcan_ram_flexible_config_t *config)
{
hpm_stat_t status = status_invalid_argument;
do {
// ...existing code...
if (config->enable_ext_filter) {
- if (config->std_filter_config.list_size > MCAN_EXT_FILTER_ELEM_CNT_MAX) {
+ if (config->ext_filter_config.list_size > MCAN_EXT_FILTER_ELEM_CNT_MAX) {
break;
}
ptr->XIDFC = config->ext_filter_config.reg_val;
} else {
ptr->XIDFC = MCAN_RAM_ADDR_INVALID;
}
// ...existing code...
} while (false);
return status;
}
// ...existing code...
void mcan_deinit(MCAN_Type *ptr)
{
if (ptr != NULL) {
// ...existing code...
ptr->GFC = 0UL;
ptr->SIDFC = 0UL;
- ptr->XIDAM = 0UL;
- ptr->XIDAM = 0x1FFFFFFFUL;
+ ptr->XIDAM = 0x1FFFFFFFUL;
ptr->RXBC = 0UL;
// ...existing code...
}
}
// ...existing code...使用提示
- 初始化时优先调用 mcan_get_default_config 并按需改动,再调用 mcan_init。
- 如需自定义 RAM 布局,建议先用 mcan_get_default_ram_config/…flexible_config 获得基线配置,修改数量/尺寸后调用 mcan_config_ram/…with_flexible_config。
- 解析协议状态推荐调用 mcan_get_protocol_status,避免直接读 PSR 并手动解码。
并发与健壮性注意
- RAM 与 TBSEL 等寄存器的读改写建议在临界区,避免中断竞争。
- 写 TX/RX 元素数据时确保 DLC 与 data_field_size 匹配,避免越界。
- 默认超时上限较大,阻塞 API 在总线异常时可能等待较久,可按场景调小重试计数。
Metadata
Metadata
Assignees
Labels
No labels