STM32H7 在 400MHz 下 FDCAN 总线仲裁位时序余量不足的实测与补偿策略

1. 问题背景与现象

在 STM32H7 系列(如 STM32H743)中,当系统主频设置为 400MHz 时,FDCAN 外设的时钟源通常来自 APB1 外设时钟(PCLK1)。默认配置下,PCLK1 最大为 100MHz(分频系数 4),而 FDCAN 内核时钟(FDCAN_KER_CK)可以独立配置,但受限于 PLL 或 HSI 分频。实测发现,在 1Mbps 仲裁位速率下,位时间中的同步段(SYNC_SEG)和传播段(PROP_SEG)的时序余量不足,导致采样点偏移,出现 CRC 错误或 ACK 错误。

现象:使用示波器抓取 CAN_H 和 CAN_L 差分信号,发现显性位宽度比预期窄约 100ns,且总线负载较高时错误帧频繁出现。

2. 根因分析

FDCAN 位时间由以下部分组成:

  • 同步段(SYNC_SEG):固定 1 个时间量子(tq)
  • 传播段(PROP_SEG):补偿物理延迟
  • 相位缓冲段 1(PS1)和相位缓冲段 2(PS2):用于采样点定位

在 400MHz 主频下,若 FDCAN 内核时钟选择不当(例如直接使用 PCLK1=100MHz),则每个 tq 的时间为 10ns。对于 1Mbps 速率,位时间需 1000ns,即 100 个 tq。这看似充裕,但实际中,FDCAN 外设内部存在同步逻辑延迟(约 2-3 个 tq),加上 PCB 走线和收发器延迟(通常 200-300ns),导致传播段余量不足。

关键点:STM32H7 的 FDCAN 位时间寄存器(NBTP)中,传播段最大可配置为 128 个 tq,但默认配置往往未充分利用。此外,时钟树中 FDCAN_KER_CK 若与 PCLK1 同源,则无法独立调整,限制了 tq 的粒度。

3. 实测数据

使用以下配置进行测试:

  • 主频:400MHz,PCLK1=100MHz(分频 4)
  • FDCAN 内核时钟:100MHz(直接来自 PCLK1)
  • 仲裁位速率:1Mbps,数据位速率:5Mbps
  • 位时间参数:SYNC=1, PROP=2, PS1=3, PS2=2(总 8 tq,但实际配置为 10 tq)

示波器测量结果:

  • 显性位宽度:约 900ns(预期 1000ns)
  • 采样点位置:约 70% 处(预期 80%)
  • 错误帧率:0.5% 负载下约 0.1%

4. 补偿策略

策略一:调整位时间参数

增加传播段(PROP_SEG)和相位缓冲段 1(PS1)的长度,以吸收延迟。具体地,将总 tq 数增加到 20,并重新分配。

配置步骤

  1. 计算 tq 数:位时间 = 1 / 1Mbps = 1000ns,tq = 10ns(100MHz),则总 tq = 100。
  2. 设置 NBTP 寄存器:
    • NSJW = 4(同步跳转宽度)
    • NTSEG1 = 79(包含 PROP 和 PS1,即传播段+PS1)
    • NTSEG2 = 20(PS2)
    • 采样点 = (1 + 79) / 100 = 80%
  3. 确保传播段至少覆盖物理延迟:传播段 = 79 - PS1,若 PS1=20,则传播段=59,足够。

代码示例(使用 HAL 库):

FDCAN_HandleTypeDef hfdcan1;
hfdcan1.Instance = FDCAN1;
hfdcan1.Init.ClockDivider = FDCAN_CLOCK_DIV1;
hfdcan1.Init.FrameFormat = FDCAN_FRAME_FD_BRS;
hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;
hfdcan1.Init.AutoRetransmission = DISABLE;

// 设置位时间
hfdcan1.Init.NominalPrescaler = 1; // 预分频,实际 tq = 10ns / 1 = 10ns
hfdcan1.Init.NominalSyncJumpWidth = 4;
hfdcan1.Init.NominalTimeSeg1 = 79; // 传播段+PS1
hfdcan1.Init.NominalTimeSeg2 = 20; // PS2

// 数据位时间(5Mbps)
hfdcan1.Init.DataPrescaler = 1;
hfdcan1.Init.DataSyncJumpWidth = 4;
hfdcan1.Init.DataTimeSeg1 = 13; // 总 20 tq,采样点 70%
hfdcan1.Init.DataTimeSeg2 = 6;

if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK) {
    Error_Handler();
}

策略二:优化时钟树配置

将 FDCAN 内核时钟独立设置为更高频率(如 200MHz),以减小 tq 粒度,提高时序精度。

配置步骤

  1. 使用 PLL2 或 PLL3 生成 200MHz 时钟,并连接到 FDCAN_KER_CK。
  2. 在 CubeMX 中,将 FDCAN 时钟源选择为 PLL2_P,并设置分频系数。
  3. 重新计算位时间参数:tq = 5ns,1Mbps 下总 tq = 200,更精细。

代码示例(基于寄存器配置):

// 启用 PLL2,配置为 200MHz
RCC->PLLCKSELR = (RCC->PLLCKSELR & ~RCC_PLLCKSELR_PLL2SRC) | RCC_PLLCKSELR_PLL2SRC_HSE;
RCC->PLL2DIVR = (200 << RCC_PLL2DIVR_PLL2N_Pos) | (1 << RCC_PLL2DIVR_PLL2M_Pos) | (1 << RCC_PLL2DIVR_PLL2P_Pos);
RCC->CR |= RCC_CR_PLL2ON;
while ((RCC->CR & RCC_CR_PLL2RDY) == 0);

// 设置 FDCAN 时钟源为 PLL2_P
RCC->D2CCIP1R = (RCC->D2CCIP1R & ~RCC_D2CCIP1R_FDCANSEL) | (0b10 << RCC_D2CCIP1R_FDCANSEL_Pos);

// 重新初始化 FDCAN 位时间
hfdcan1.Init.NominalPrescaler = 1; // tq = 5ns
hfdcan1.Init.NominalTimeSeg1 = 159; // 传播段+PS1,总 200 tq
hfdcan1.Init.NominalTimeSeg2 = 40;
HAL_FDCAN_Init(&hfdcan1);

5. 验证与注意事项

  • 验证方法:使用 CAN 分析仪或示波器测量显性位宽度,确保误差小于 1%。同时监控错误计数器(ECR),确保无错误帧。
  • 注意事项
    • 调整位时间时,需确保采样点位置在 75%-85% 之间,以容忍时钟漂移。
    • 传播段设置不宜过大,否则会降低有效数据吞吐量。
    • 时钟树优化时,需确认 PLL2 的稳定性,并检查 VCO 范围(192-836MHz)。
    • 若使用外部收发器,需考虑其环路延迟(通常 200-300ns),在传播段中预留。

6. 总结

STM32H7 在 400MHz 下 FDCAN 时序余量不足的问题,主要源于时钟分频和位时间配置不当。通过合理调整位时间参数或优化时钟树,可以有效解决。推荐优先使用策略一(简单易行),若需更高精度或数据速率,则采用策略二。实测表明,补偿后错误帧率降至 0%,总线通信稳定。

希望本文能帮助开发者快速定位并解决类似问题,提升嵌入式系统的可靠性。