STM32H7 400MHz 下 FDCAN 总线仲裁位时序裕量不足的实测与修正
👁 1 阅读 · 2026-08-27 · 嵌入式
STM32H7 在 400MHz 主频下运行 FDCAN 时,由于内核时钟与 FDCAN 外设时钟的相位关系,仲裁位时序裕量可能不足,导致总线通信偶发错误。本文通过实测波形分析,定位到问题根源在于 FDCAN 位时间参数配置未考虑内核时钟抖动,并给出基于硬件延迟线和软件重同步的修正方案,确保 1Mbps 仲裁段稳定运行。
# 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 和增加硬件延迟线,可有效消除错误。建议在项目初期就进行时序裕量分析,避免后期返工。