1. 概述
FlexCAN(Flexible Controller Area Network)是YTM32B1M微控制器中的高性能CAN总线控制器,支持CAN 2.0A/B协议和CAN FD(Flexible Data-rate)扩展协议。本文档详细解析YTM32B1M SDK中FlexCAN驱动的实现,包括消息缓冲区管理、FIFO操作、位时序配置和错误处理等功能。
2. 文件组织结构
2.1 头文件
-
flexcan_driver.h: FlexCAN驱动的主要头文件,定义了所有公共接口和数据结构
-
flexcan_hw_access.h: FlexCAN硬件访问层头文件
-
flexcan_irq.h: FlexCAN中断处理相关头文件
2.2 源文件
-
flexcan_driver.c: FlexCAN驱动的主要实现文件
-
flexcan_irq.c: FlexCAN中断服务程序实现
-
flexcan_hw_access.c: FlexCAN硬件抽象层实现
2.3 架构层次
应用层 ↓ flexcan_driver.h/c (高层API) ↓ flexcan_hw_access.h/c (硬件抽象层) ↓ FlexCAN寄存器定义 ↓ FlexCAN硬件控制器
3. 核心数据结构解析
3.1 消息ID类型枚举
typedef enum { FLEXCAN_MSG_ID_STD, // 标准ID (11位) FLEXCAN_MSG_ID_EXT // 扩展ID (29位) } flexcan_msgbuff_id_type_t;
3.2 事件类型枚举
typedef enum { FLEXCAN_EVENT_RX_COMPLETE, // 接收完成 FLEXCAN_EVENT_RXFIFO_COMPLETE, // RxFIFO接收完成 FLEXCAN_EVENT_RXFIFO_WARNING, // RxFIFO警告(接近满) FLEXCAN_EVENT_RXFIFO_OVERFLOW, // RxFIFO溢出 FLEXCAN_EVENT_TX_COMPLETE, // 发送完成 FLEXCAN_EVENT_ENHANCE_RXFIFO_AVAILABLEDATA, // 增强RxFIFO数据可用 FLEXCAN_EVENT_ENHANCE_RXFIFO_WATERMARK, // 增强RxFIFO水位 FLEXCAN_EVENT_ENHANCE_RXFIFO_OVERFLOW, // 增强RxFIFO溢出 FLEXCAN_EVENT_WAKEUP_TIMEOUT, // 唤醒超时 FLEXCAN_EVENT_WAKEUP_MATCH, // 唤醒匹配 FLEXCAN_EVENT_SELF_WAKEUP, // 自唤醒 FLEXCAN_EVENT_DMA_COMPLETE, // DMA传输完成 FLEXCAN_EVENT_DMA_ERROR, // DMA传输错误 FLEXCAN_EVENT_ERROR // 一般错误 } flexcan_event_type_t;
3.3 错误事件类型枚举
typedef enum { FLEXCAN_ERROR_OVERRUN_EVENT = CAN_ESR1_ERROVR_MASK, // 过载错误 FLEXCAN_FD_DATA_BIT_ERROR_EVENT = CAN_ESR1_ERRINT_FAST_MASK, // FD数据位错误 FLEXCAN_BUS_OFF_DONE_EVENT = CAN_ESR1_BOFFDONEINT_MASK, // 总线关闭完成 FLEXCAN_TX_WARNING_EVENT = CAN_ESR1_TXWRN_MASK, // 发送警告 FLEXCAN_RX_WARNING_EVENT = CAN_ESR1_RXWRN_MASK, // 接收警告 FLEXCAN_BUS_OFF_ENTER_EVENT = CAN_ESR1_BOFFINT_MASK, // 进入总线关闭 FLEXCAN_BIT_ERROR_EVENT = CAN_ESR1_ERRINT_MASK, // 位错误 FLEXCAN_WAKEUP_EVENT = CAN_ESR1_WAKINT_MASK, // 唤醒事件 FLEXCAN_RAM_ECC_ERROR_EVENT = CAN_ERRSR_FANCEIF_MASK | CAN_ERRSR_HANCEIF_MASK // RAM ECC错误 } flexcan_error_event_type_t;
3.4 消息缓冲区状态枚举
typedef enum { FLEXCAN_MB_IDLE, // 消息缓冲区空闲 FLEXCAN_MB_RX_BUSY, // 消息缓冲区接收忙 FLEXCAN_MB_TX_BUSY, // 消息缓冲区发送忙 FLEXCAN_MB_DMA_ERROR // DMA传输错误 } flexcan_mb_state_t;
3.5 操作模式枚举
typedef enum { FLEXCAN_NORMAL_MODE, // 正常模式 FLEXCAN_LISTEN_ONLY_MODE, // 只听模式 FLEXCAN_LOOPBACK_MODE, // 回环模式 FLEXCAN_FREEZE_MODE, // 冻结模式 FLEXCAN_DISABLE_MODE // 禁用模式 } flexcan_operation_modes_t;
3.6 RxFIFO传输类型枚举
typedef enum { FLEXCAN_RXFIFO_USING_INTERRUPTS, // 使用中断 FLEXCAN_RXFIFO_USING_DMA // 使用DMA } flexcan_rxfifo_transfer_type_t;
3.7 消息缓冲区结构
typedef struct { uint32_t cs; // 控制和状态字段 uint32_t msgId; // 消息ID uint8_t data[64]; // 数据字节(最大64字节) uint8_t dataLen; // 数据长度 } flexcan_msgbuff_t;
3.8 数据信息结构
typedef struct { flexcan_msgbuff_id_type_t msg_id_type; // 消息ID类型 uint32_t data_length; // 数据长度 bool fd_enable; // FD使能 uint8_t fd_padding; // FD填充值 bool enable_brs; // 位速率切换使能 bool is_remote; // 远程帧标志 } flexcan_data_info_t;
3.9 位时序配置结构
typedef struct { uint32_t propSeg; // 传播段 uint32_t phaseSeg1; // 相位段1 uint32_t phaseSeg2; // 相位段2 uint32_t preDivider; // 时钟预分频器 uint32_t rJumpwidth; // 重同步跳跃宽度 } flexcan_time_segment_t;
3.10 消息缓冲区句柄结构
typedef struct { flexcan_msgbuff_t *mb_message; // 消息缓冲区指针 semaphore_t mbSema; // 信号量 volatile flexcan_mb_state_t state; // 缓冲区状态 bool isBlocking; // 阻塞标志 bool isRemote; // 远程帧标志 } flexcan_mb_handle_t;
3.11 FlexCAN状态结构
typedef struct FlexCANState { flexcan_mb_handle_t mbs[FEATURE_CAN_MAX_MB_NUM]; // 消息缓冲区数组 void (*callback)(uint8_t instance, // 回调函数指针 flexcan_event_type_t eventType, uint32_t buffIdx, struct FlexCANState *driverState); void *callbackParam; // 回调参数 void (*error_callback)(uint8_t instance, // 错误回调函数 flexcan_error_event_type_t eventType, struct FlexCANState *driverState); void *errorCallbackParam; // 错误回调参数 uint8_t rxFifoDMAChannel; // RxFIFO DMA通道 flexcan_mb_handle_t enhanceRxFifoState; // 增强RxFIFO状态 flexcan_rxfifo_transfer_type_t transferType; // 传输类型 } flexcan_state_t;
3.12 用户配置结构
typedef struct { uint32_t max_num_mb; // 最大消息缓冲区数量 flexcan_rx_fifo_id_filter_num_t num_id_filters; // ID过滤器数量 bool is_rx_fifo_needed; // 是否需要RxFIFO flexcan_operation_modes_t flexcanMode; // 操作模式 flexcan_fd_payload_size_t payload; // 载荷大小 bool fd_enable; // FD使能 flexcan_clk_source_t pe_clock; // 协议引擎时钟源 flexcan_time_segment_t bitrate; // 标准帧位速率 flexcan_time_segment_t bitrate_cbt; // FD数据相位位速率 flexcan_rxfifo_transfer_type_t transfer_type; // 传输类型 uint8_t rxFifoDMAChannel; // RxFIFO DMA通道 bool is_enhance_rx_fifo_needed; // 是否需要增强RxFIFO uint32_t num_enhance_rx_fifo_filters; // 增强RxFIFO过滤器数量 uint32_t num_enhance_rx_fifo_extid_filters; // 扩展ID过滤器数量 uint32_t num_enhance_rx_fifo_min_messages; // 最小消息数量 } flexcan_user_config_t;
4. FlexCAN系统架构图
CAN总线 FlexCAN控制器 应用层 ┌─────────────┐ ┌─────────────────────────┐ ┌─────────────┐ │ │ │ 消息缓冲区 │ │ │ │ CAN_H │◄─────────►│ ┌─────┬─────┬─────┐ │◄──►│ 应用程序 │ │ │ │ │ MB0 │ MB1 │ ... │ │ │ │ │ CAN_L │ │ └─────┴─────┴─────┘ │ └─────────────┘ │ │ │ │ │ └─────────────┘ │ RxFIFO │ ┌─────────────┐ │ ┌─────────────────┐ │ │ │ │ │ 过滤器表 │ │◄──►│ 中断处理 │ │ └─────────────────┘ │ │ │ │ │ └─────────────┘ │ 位时序控制器 │ │ │ ┌─────────────────┐ │ ┌─────────────┐ │ │ 时钟分频器 │ │ │ │ │ └─────────────────┘ │◄──►│ DMA控制 │ │ │ │ │ │ 错误管理单元 │ └─────────────┘ │ ┌─────────────────┐ │ │ │ 错误计数器 │ │ │ └─────────────────┘ │ └─────────────────────────┘
5. 核心API接口详解
5.1 初始化和配置接口
// 获取默认配置 void FLEXCAN_DRV_GetDefaultConfig(flexcan_user_config_t *config); // 初始化FlexCAN status_t FLEXCAN_DRV_Init(uint8_t instance, flexcan_state_t *state, const flexcan_user_config_t *config); // 去初始化FlexCAN status_t FLEXCAN_DRV_Deinit(uint8_t instance);
5.2 位速率配置接口
// 设置标准帧位速率 void FLEXCAN_DRV_SetBitrate(uint8_t instance, const flexcan_time_segment_t *bitrate); // 设置FD数据相位位速率 void FLEXCAN_DRV_SetBitrateCbt(uint8_t instance, const flexcan_time_segment_t *bitrate); // 获取位速率配置 void FLEXCAN_DRV_GetBitrate(uint8_t instance, flexcan_time_segment_t *bitrate);
5.3 消息发送接口
// 配置发送消息缓冲区 status_t FLEXCAN_DRV_ConfigTxMb(uint8_t instance, uint8_t mb_idx, const flexcan_data_info_t *tx_info, uint32_t msg_id); // 发送数据(阻塞) status_t FLEXCAN_DRV_SendBlocking(uint8_t instance, uint8_t mb_idx, const flexcan_data_info_t *tx_info, uint32_t msg_id, const uint8_t *mb_data, uint32_t timeout_ms); // 发送数据(非阻塞) status_t FLEXCAN_DRV_Send(uint8_t instance, uint8_t mb_idx, const flexcan_data_info_t *tx_info, uint32_t msg_id, const uint8_t *mb_data); // 获取发送状态 status_t FLEXCAN_DRV_GetTransferStatus(uint8_t instance, uint8_t mb_idx); // 中止发送 status_t FLEXCAN_DRV_AbortTransfer(uint8_t instance, uint8_t mb_idx);
5.4 消息接收接口
// 配置接收消息缓冲区 status_t FLEXCAN_DRV_ConfigRxMb(uint8_t instance, uint8_t mb_idx, const flexcan_data_info_t *rx_info, uint32_t msg_id); // 接收数据(阻塞) status_t FLEXCAN_DRV_ReceiveBlocking(uint8_t instance, uint8_t mb_idx, flexcan_msgbuff_t *data, uint32_t timeout_ms); // 接收数据(非阻塞) status_t FLEXCAN_DRV_Receive(uint8_t instance, uint8_t mb_idx, flexcan_msgbuff_t *data);
5.5 RxFIFO接口
// 配置RxFIFO status_t FLEXCAN_DRV_ConfigRxFifo(uint8_t instance, flexcan_rx_fifo_id_element_format_t id_format, const flexcan_id_table_t *id_filter_table); // 从RxFIFO接收(阻塞) status_t FLEXCAN_DRV_RxFifoBlocking(uint8_t instance, flexcan_msgbuff_t *data, uint32_t timeout_ms); // 从RxFIFO接收(非阻塞) status_t FLEXCAN_DRV_RxFifo(uint8_t instance, flexcan_msgbuff_t *data);
5.6 掩码配置接口
// 设置掩码类型 void FLEXCAN_DRV_SetRxMaskType(uint8_t instance, flexcan_rx_mask_type_t type); // 设置RxFIFO全局掩码 void FLEXCAN_DRV_SetRxFifoGlobalMask(uint8_t instance, flexcan_msgbuff_id_type_t id_type, uint32_t mask); // 设置消息缓冲区全局掩码 void FLEXCAN_DRV_SetRxMbGlobalMask(uint8_t instance, flexcan_msgbuff_id_type_t id_type, uint32_t mask); // 设置个别掩码 status_t FLEXCAN_DRV_SetRxIndividualMask(uint8_t instance, flexcan_msgbuff_id_type_t id_type, uint8_t mb_idx, uint32_t mask);
6. 外设应用描述
6.1 FlexCAN的主要应用场景
-
汽车电子: 车身控制、发动机管理、仪表通信
-
工业自动化: 现场总线通信、设备控制
-
医疗设备: 设备间通信、数据采集
-
航空航天: 飞行控制系统、数据总线
-
能源管理: 电池管理系统、充电桩通信
6.2 典型应用示例
6.2.1 基本FlexCAN初始化
#include "flexcan_driver.h" // FlexCAN状态结构 flexcan_state_t canState; // 回调函数 void canCallback(uint8_t instance, flexcan_event_type_t eventType, uint32_t buffIdx, flexcan_state_t *flexcanState) { switch (eventType) { case FLEXCAN_EVENT_TX_COMPLETE: // 发送完成处理 break; case FLEXCAN_EVENT_RX_COMPLETE: // 接收完成处理 break; case FLEXCAN_EVENT_RXFIFO_COMPLETE: // RxFIFO接收完成处理 break; default: break; } } void flexcan_init_example(void) { flexcan_user_config_t canConfig; // 获取默认配置 FLEXCAN_DRV_GetDefaultConfig(&canConfig); // 修改配置参数 canConfig.max_num_mb = 16; // 16个消息缓冲区 canConfig.is_rx_fifo_needed = true; // 启用RxFIFO canConfig.num_id_filters = FLEXCAN_RX_FIFO_ID_FILTERS_8; // 8个过滤器 canConfig.flexcanMode = FLEXCAN_NORMAL_MODE; // 正常模式 canConfig.fd_enable = false; // 禁用FD // 配置位时序(500kbps) canConfig.bitrate.propSeg = 7; canConfig.bitrate.phaseSeg1 = 4; canConfig.bitrate.phaseSeg2 = 1; canConfig.bitrate.preDivider = 9; canConfig.bitrate.rJumpwidth = 1; // 初始化FlexCAN status_t status = FLEXCAN_DRV_Init(0, &canState, &canConfig); if (status != STATUS_SUCCESS) { // 初始化失败处理 } // 安装回调函数 FLEXCAN_DRV_InstallEventCallback(0, canCallback, NULL); }
6.2.2 发送CAN消息示例
void can_send_example(void) { // 配置发送消息缓冲区 flexcan_data_info_t dataInfo = { .msg_id_type = FLEXCAN_MSG_ID_STD, // 标准ID .data_length = 8, // 8字节数据 .fd_enable = false, // 非FD帧 .is_remote = false // 数据帧 }; uint32_t msgId = 0x123; // 消息ID uint8_t txData[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; // 配置发送消息缓冲区0 status_t status = FLEXCAN_DRV_ConfigTxMb(0, 0, &dataInfo, msgId); if (status != STATUS_SUCCESS) { return; } // 发送数据(阻塞方式) status = FLEXCAN_DRV_SendBlocking(0, 0, &dataInfo, msgId, txData, 1000); if (status == STATUS_SUCCESS) { // 发送成功 } else if (status == STATUS_TIMEOUT) { // 发送超时 } }
6.2.3 接收CAN消息示例
void can_receive_example(void) { // 配置接收消息缓冲区 flexcan_data_info_t dataInfo = { .msg_id_type = FLEXCAN_MSG_ID_STD, // 标准ID .data_length = 8, // 8字节数据 .fd_enable = false, // 非FD帧 .is_remote = false // 数据帧 }; uint32_t msgId = 0x456; // 期望接收的消息ID flexcan_msgbuff_t rxMsg; // 配置接收消息缓冲区1 status_t status = FLEXCAN_DRV_ConfigRxMb(0, 1, &dataInfo, msgId); if (status != STATUS_SUCCESS) { return; } // 接收数据(阻塞方式) status = FLEXCAN_DRV_ReceiveBlocking(0, 1, &rxMsg, 5000); if (status == STATUS_SUCCESS) { // 处理接收到的数据 processReceivedMessage(&rxMsg); } else if (status == STATUS_TIMEOUT) { // 接收超时 } }
6.2.4 RxFIFO配置和使用示例
void can_rxfifo_example(void) { // 配置ID过滤器表 flexcan_id_table_t idFilterTable[8] = { {false, false, 0x100}, // 接受ID 0x100 {false, false, 0x200}, // 接受ID 0x200 {false, false, 0x300}, // 接受ID 0x300 // ... 更多过滤器 }; // 配置RxFIFO status_t status = FLEXCAN_DRV_ConfigRxFifo(0, FLEXCAN_RX_FIFO_ID_FORMAT_A, idFilterTable); if (status != STATUS_SUCCESS) { return; } // 从RxFIFO接收消息 flexcan_msgbuff_t rxMsg; while (1) { status = FLEXCAN_DRV_RxFifoBlocking(0, &rxMsg, 1000); if (status == STATUS_SUCCESS) { // 处理接收到的消息 processRxFifoMessage(&rxMsg); } } }
6.2.5 CAN FD配置示例
void can_fd_example(void) { flexcan_user_config_t canConfig; // 获取默认配置 FLEXCAN_DRV_GetDefaultConfig(&canConfig); // 启用CAN FD canConfig.fd_enable = true; canConfig.payload = FLEXCAN_PAYLOAD_SIZE_64; // 64字节载荷 // 仲裁相位位时序(500kbps) canConfig.bitrate.propSeg = 7; canConfig.bitrate.phaseSeg1 = 4; canConfig.bitrate.phaseSeg2 = 1; canConfig.bitrate.preDivider = 9; canConfig.bitrate.rJumpwidth = 1; // 数据相位位时序(2Mbps) canConfig.bitrate_cbt.propSeg = 2; canConfig.bitrate_cbt.phaseSeg1 = 1; canConfig.bitrate_cbt.phaseSeg2 = 1; canConfig.bitrate_cbt.preDivider = 4; canConfig.bitrate_cbt.rJumpwidth = 1; // 初始化FlexCAN FLEXCAN_DRV_Init(0, &canState, &canConfig); // 发送FD消息 flexcan_data_info_t dataInfo = { .msg_id_type = FLEXCAN_MSG_ID_STD, .data_length = 32, // 32字节数据 .fd_enable = true, // FD帧 .enable_brs = true, // 启用位速率切换 .is_remote = false }; uint8_t fdData[32]; // 填充数据... FLEXCAN_DRV_ConfigTxMb(0, 0, &dataInfo, 0x123); FLEXCAN_DRV_Send(0, 0, &dataInfo, 0x123, fdData); }
6.2.6 错误处理示例
void canErrorCallback(uint8_t instance, flexcan_error_event_type_t eventType, flexcan_state_t *flexcanState) { switch (eventType) { case FLEXCAN_TX_WARNING_EVENT: // 发送警告处理 handleTxWarning(); break; case FLEXCAN_RX_WARNING_EVENT: // 接收警告处理 handleRxWarning(); break; case FLEXCAN_BUS_OFF_ENTER_EVENT: // 总线关闭处理 handleBusOff(); break; case FLEXCAN_ERROR_OVERRUN_EVENT: // 过载错误处理 handleOverrun(); break; default: break; } } void can_error_handling_setup(void) { // 安装错误回调函数 FLEXCAN_DRV_InstallErrorCallback(0, canErrorCallback, NULL); }
7. 与数据手册的对应关系
根据YTM32B1ME0数据手册中的FlexCAN章节:
-
消息缓冲区: SDK中的消息缓冲区直接对应硬件的MB结构
-
位时序参数: 传播段、相位段等参数与硬件寄存器一一对应
-
过滤器机制: ID过滤器表对应硬件的过滤器寄存器
-
中断系统: 各种事件中断与硬件中断源匹配
-
错误管理: 错误计数器和错误状态与硬件错误管理单元对应
8. 最佳实践建议
-
位时序配置: 根据总线负载和节点数量选择合适的位时序参数
-
过滤器设置: 合理配置过滤器,减少不必要的中断和处理
-
错误处理: 实现完善的错误检测和恢复机制
-
总线仲裁: 合理分配消息ID优先级
-
FD使用: 在需要高数据吞吐量时使用CAN FD
-
DMA优化: 大量数据传输时使用DMA模式
9. 调试技巧
-
总线分析: 使用CAN分析仪监控总线通信
-
位时序验证: 确认位时序参数符合CAN规范
-
错误统计: 监控错误计数器,分析总线质量
-
过滤器调试: 验证过滤器配置是否正确
-
时序分析: 分析消息发送和接收的时序关系
10. 总结
YTM32B1M的FlexCAN控制器提供了完整的CAN总线通信功能,支持CAN 2.0和CAN FD协议。通过合理配置和使用FlexCAN驱动,可以实现可靠的总线通信,满足各种实时控制和数据传输需求。掌握FlexCAN的配置和使用方法对于开发汽车电子和工业控制应用至关重要。
本文档基于YTM32B1M SDK v1.0,如有更新请参考最新版本文档。