1. 为什么需要双路FDCAN?
在工业控制和汽车电子领域,CAN总线是最常用的现场总线之一。STM32H743作为高性能MCU,内置了新一代的FDCAN控制器,相比传统CAN控制器,它支持更高的通信速率(最高8Mbps)和更大的FIFO缓冲区。实际项目中,我们经常遇到需要同时与多个CAN节点通信的场景,比如:
- 汽车电子中同时连接车身控制模块和发动机控制模块
- 工业设备中同时连接多个传感器和执行器
- 需要隔离不同优先级通信的场合
传统做法是使用外部CAN控制器扩展,但这会增加硬件成本和布线复杂度。STM32H743内置双FDCAN控制器的特性,让我们可以在单芯片上实现双路独立CAN通信,既节省成本又提高可靠性。
2. CubeMX基础配置
2.1 时钟树配置要点
FDCAN的时钟源选择很关键,直接影响通信稳定性。在CubeMX中按以下步骤配置:
- 在RCC配置中启用外部晶振(HSE)
- 进入Clock Configuration界面
- 将PLL1Q时钟配置为120MHz(这是FDCAN的推荐时钟源)
- 确认FDCAN时钟显示为120MHz
这里有个坑我踩过:如果FDCAN时钟显示为0MHz,通常是因为PLL1Q没有正确配置。记得检查PLL1Q是否已启用并正确分频。
2.2 FDCAN1基础参数
在Connectivity选项卡下找到FDCAN1,配置关键参数:
- Mode: Normal Mode
- Nominal Bit Rate:
- Prescaler: 12
- Time Quanta in Bit Segment 1: 13
- Time Quanta in Bit Segment 2: 2
- ReSynchronization Jump Width: 1
- 启用FDCAN1 Global Interrupt
波特率计算公式为:120MHz / (Prescaler * (BS1 + BS2)) = 1Mbps。这里BS1=13,BS2=2,Prescaler=12,计算得120MHz/(12*15)=1Mbps。
2.3 FDCAN2的特别配置
配置完FDCAN1后,FDCAN2的配置有个关键点:
- 先回到Clock Configuration
- 确认FDCAN2时钟源也是PLL1Q
- 返回FDCAN2配置界面,参数与FDCAN1相同
- 注意使用不同的中断通道(如FDCAN2_IT0)
实测发现,如果两个FDCAN使用相同的中断优先级,在高负载时可能出现中断丢失。建议将两个FDCAN的中断优先级设置为不同值。
3. Keil工程关键设置
3.1 编译器优化选项
在Target选项卡下:
- 选择Use MicroLIB(减少代码体积)
- Optimization等级建议选择-O1(平衡性能和代码可调试性)
在C/C++选项卡下:
- 添加预定义宏:USE_HAL_DRIVER, STM32H743xx
- Include paths添加所有头文件路径
3.2 调试接口配置
在Debug选项卡下:
- 选择正确的调试器(如ST-Link)
- 在Settings中:
- 勾选Reset and Run
- 将Flash Download中的Reset选项设为"Hardware Reset"
这里有个实用技巧:在Flash Download配置中,建议勾选"Verify"选项,可以避免因下载失败导致的奇怪问题。
4. 核心代码实现
4.1 初始化代码解析
在main.c中添加以下初始化代码:
/* FDCAN初始化 */ MX_FDCAN1_Init(); MX_FDCAN2_Init(); /* 启用FDCAN控制器 */ HAL_FDCAN_Start(&hfdcan1); HAL_FDCAN_Start(&hfdcan2); /* 配置滤波器 - 接收所有标准帧 */ FDCAN_FilterTypeDef sFilterConfig; sFilterConfig.IdType = FDCAN_STANDARD_ID; sFilterConfig.FilterIndex = 0; sFilterConfig.FilterType = FDCAN_FILTER_MASK; sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; sFilterConfig.FilterID1 = 0x000; sFilterConfig.FilterID2 = 0x000; HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig); HAL_FDCAN_ConfigFilter(&hfdcan2, &sFilterConfig);4.2 中断配置技巧
在bsp_fdcan.c中添加中断处理:
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) { if((RxFifo0ITs & FDCAN_IT_RX_FIFO0_NEW_MESSAGE) != RESET) { /* 处理新消息 */ FDCAN_RxHeaderTypeDef RxHeader; uint8_t RxData[8]; HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &RxHeader, RxData); /* 判断是哪个FDCAN接收到的数据 */ if(hfdcan->Instance == FDCAN1) { // 处理FDCAN1数据 } else { // 处理FDCAN2数据 } } if((RxFifo0ITs & FDCAN_IT_RX_FIFO0_WATERMARK) != RESET) { /* 水印中断处理 */ } }5. 稳定性测试方案
5.1 双路同时发送测试
创建测试任务,同时通过两路FDCAN发送数据:
void test_dual_fdcan_send(void) { FDCAN_TxHeaderTypeDef TxHeader; uint8_t TxData[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; /* 配置发送头 */ TxHeader.Identifier = 0x123; TxHeader.IdType = FDCAN_STANDARD_ID; TxHeader.TxFrameType = FDCAN_DATA_FRAME; TxHeader.DataLength = FDCAN_DLC_BYTES_8; TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE; TxHeader.BitRateSwitch = FDCAN_BRS_OFF; TxHeader.FDFormat = FDCAN_CLASSIC_CAN; TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS; TxHeader.MessageMarker = 0; while(1) { /* FDCAN1发送 */ HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader, TxData); /* FDCAN2发送 */ HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan2, &TxHeader, TxData); HAL_Delay(1); /* 修改数据内容 */ for(int i=0; i<8; i++) { TxData[i]++; } } }5.2 高负载稳定性测试
为了验证1M波特率下的稳定性,我设计了一个压力测试方案:
- 使用两路CAN分析仪分别连接两个FDCAN接口
- 设置发送间隔为0.1ms(理论极限是每1ms可发送约120帧)
- 持续发送24小时,检查:
- 丢帧率(应小于0.001%)
- 错误帧数量(应为0)
- 总线负载率(建议保持在70%以下)
实测结果:在环境温度25℃下,STM32H743的双FDCAN可以稳定工作在1Mbps,连续工作24小时无错误帧,丢帧率为0。