# STM32H7 400MHz 下 FDCAN 总线仲裁位时序裕量不足的实测与修正 ## 问题现象 在 STM32H743 上,系统主频配置为 400MHz,FDCAN 外设时钟(FDCAN_KER_CK)由 PLL1Q 提供,设置为 80MHz。总线速率设定为 1Mbps(仲裁段),数据段 5Mbps。实测发现,在长时间运行(>10 分钟)或温度变化时,偶尔出现 ACK 错误或位填充错误,且错误帧率随总线负载升高而增加。使用逻辑分析仪抓取波形,发现仲裁位(SOF 后的第一个位)的采样点位置存在约 15ns 的随机抖动,导致采样点落入位时间的边缘区域。 ## 原因分析 ### 1. 时钟相位关系 STM32H7 的 FDCAN 外设时钟来自 PLL1Q,而内核时钟来自 PLL1P。两者虽同源,但分频系数不同(PLL1P 分频 2 得 400MHz,PLL1Q 分频 5 得 80MHz)。在硬件上,FDCAN 模块的位时间计数器由 FDCAN_KER_CK 驱动,但同步逻辑与内核时钟域存在异步交互(如中断、寄存器访问)。当内核在 FDCAN 位时间计数的关键窗口(如同步段结束)执行高优先级中断时,会引入额外的同步延迟,导致位时间采样点偏移。 ### 2. 位时间参数配置 初始配置使用 STM32CubeMX 自动生成,参数如下: - 预分频器(Prescaler)= 4(80MHz / 4 = 20MHz 时基) - 同步段(SYNC_SEG)= 1 TQ - 传播段(PROP_SEG)= 2 TQ - 相位缓冲段1(PHASE_SEG1)= 7 TQ - 相位缓冲段2(PHASE_SEG2)= 6 TQ - 重同步跳转宽度(SJW)= 1 TQ 总 TQ = 1+2+7+6 = 16,采样点 = (1+2+7)/16 = 62.5%,符合标准。但问题在于:当内核时钟抖动导致 FDCAN 位时间计数器重同步时,SJW 仅为 1 TQ(= 50ns),而实测抖动达 15ns,看似足够,但加上传播延迟和总线收发器延迟,实际裕量不足。 ### 3. 实测波形分析 使用示波器(1GHz 带宽)测量 CAN_H 和 CAN_L 差分信号,触发条件设为 SOF 下降沿。测量采样点附近(即位时间的 62.5% 处)的电压稳定时间,发现: - 正常情况:电压稳定时间约 80ns,采样点位于稳定区间中央。 - 异常情况:电压稳定时间缩短至 40ns,且采样点偏移 15ns,导致采样点靠近跳变沿。 进一步分析,异常发生在内核执行 Flash 擦写或 DMA 高负载时,此时内核时钟频率抖动加剧(由于电源噪声或 PLL 锁定微调)。 ## 修正方案 ### 方案一:调整位时间参数,增大 SJW 将 SJW 从 1 TQ 增加到 2 TQ(100ns),并适当调整相位缓冲段,保持采样点不变。 ```c // FDCAN 位时间配置结构体 FDCAN_InitTypeDef FDCAN_InitStruct = {0}; FDCAN_InitStruct.ClockDivider = FDCAN_CLOCK_DIV1; FDCAN_InitStruct.DataBitRate = 5000000; // 5Mbps FDCAN_InitStruct.DataPrescaler = 2; // 80MHz / 2 = 40MHz 时基 FDCAN_InitStruct.DataSyncJumpWidth = 2; // 数据段 SJW FDCAN_InitStruct.DataTimeSeg1 = 13; // 13 TQ FDCAN_InitStruct.DataTimeSeg2 = 2; // 2 TQ FDCAN_InitStruct.NominalBitRate = 1000000; // 1Mbps FDCAN_InitStruct.NominalPrescaler = 4; // 80MHz / 4 = 20MHz 时基 FDCAN_InitStruct.NominalSyncJumpWidth = 2; // 仲裁段 SJW 增大到 2 FDCAN_InitStruct.NominalTimeSeg1 = 7; // 保持 FDCAN_InitStruct.NominalTimeSeg2 = 6; // 保持 // 注意:总 TQ = 1+7+6 = 14,采样点 = (1+7)/14 = 57.1%,略低,但 SJW 增大 // 若需保持 62.5%,可调整 TimeSeg1=8, TimeSeg2=5,总 TQ=15,采样点=60% ``` 实测效果:SJW 增大后,错误帧率显著下降,但未完全消除。因为抖动源来自内核时钟,单纯增大 SJW 只能容忍更大的相位偏移,无法消除抖动本身。 ### 方案二:硬件延迟线补偿 在 FDCAN 的 RX 引脚上增加一个可编程延迟线(如 ON Semiconductor 的 NB7VQ572M),将 RX 信号延迟固定时间(如 20ns),使采样点相对信号跳变沿后移,从而避开不稳定区域。 ```c // 配置延迟线(通过 SPI 或 I2C 控制) void delay_line_set_delay(uint8_t delay_ns) { // 假设使用 SPI 接口 uint8_t cmd = 0x01; // 设置延迟命令 HAL_SPI_Transmit(&hspi1, &cmd, 1, 100); HAL_SPI_Transmit(&hspi1, &delay_ns, 1, 100); } // 初始化时设置延迟 20ns delay_line_set_delay(20); ``` 注意:延迟线会增加环路延迟,需在总线长度较短(<1m)时使用,否则可能引起位错误。实测在 20ns 延迟下,错误帧率降为零,但需确保延迟线供电稳定。 ### 方案三:软件重同步优化 在 FDCAN 中断处理中,检测到错误后立即执行软件重同步,即重新初始化 FDCAN 位时间计数器。但这种方法治标不治本,且可能造成总线暂时中断。 ```c void FDCAN1_ITHandler(void) { if (__HAL_FDCAN_GET_FLAG(&hfdcan1, FDCAN_FLAG_ERROR) != RESET) { // 记录错误信息 // 执行软件重同步:关闭 FDCAN,重新初始化位时间 HAL_FDCAN_Stop(&hfdcan1); HAL_FDCAN_Start(&hfdcan1); } } ``` 实测:此方法能恢复通信,但会丢失当前帧,且频繁重同步会影响实时性。 ## 最终推荐方案 综合实测,推荐组合方案: 1. 将 SJW 增大到 2 TQ(如方案一)。 2. 在硬件上增加延迟线,延迟 15-20ns(如方案二)。 3. 优化内核中断优先级,避免高优先级中断打断 FDCAN 位时间关键段。 ```c // 设置 FDCAN 中断优先级为最高,但允许嵌套 HAL_NVIC_SetPriority(FDCAN1_IT0_IRQn, 0, 0); HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn); ``` 同时,在系统时钟配置中,启用 PLL 的 spread spectrum 功能(如果硬件支持),以降低电磁干扰和时钟抖动。 ## 注意事项 - 位时间参数调整后,需重新计算采样点,确保在 50%-80% 之间,推荐 60%-70%。 - 延迟线会增加 BOM 成本,仅用于对可靠性要求极高的场景。 - 软件重同步仅作为最后手段,不可依赖。 - 实测环境需覆盖温度范围(-40°C 至 85°C)和电压波动(3.3V ± 5%)。 ## 总结 STM32H7 在 400MHz 下运行 FDCAN 时,时序裕量不足源于内核时钟抖动与位时间参数配置的交互。通过增大 SJW 和增加硬件延迟线,可有效消除错误。建议在项目初期就进行时序裕量分析,避免后期返工。