# 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 库): ```c 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,更精细。 **代码示例**(基于寄存器配置): ```c // 启用 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%,总线通信稳定。 希望本文能帮助开发者快速定位并解决类似问题,提升嵌入式系统的可靠性。