STM32H7 400MHz 下 FDCAN 总线仲裁位时序余量实测与优化

为什么关注仲裁位时序余量?

FDCAN(Flexible Data-rate CAN)在仲裁段使用标准 CAN 协议,位速率通常为 1Mbit/s 或更低,但数据段可提升至 5Mbit/s 甚至更高。仲裁段的时序余量(Phase Buffer Segment 的剩余量)决定了总线对时钟漂移、线缆长度、节点间晶振误差的容忍度。若余量不足,轻则出现位错误,重则导致总线离线。在 STM32H7 运行于 400MHz 时,外设时钟(FDCAN 内核时钟)通常为 20MHz(由 PLL1Q 分频得到),此时每个位时间对应的时钟周期数较少,时序余量的计算和优化尤为关键。

位时序原理回顾

FDCAN 的每个位时间(Bit Time)由四个段组成:

  • 同步段(Sync_Seg):用于同步总线上的各个节点,固定为 1 个时间量子(tq)。
  • 传播段(Prop_Seg):补偿物理层延迟(收发器、线缆、比较器)。
  • 相位缓冲段1(Phase_Seg1):用于补偿上升沿相位误差,采样点位于其末尾。
  • 相位缓冲段2(Phase_Seg2):采样点之后的缓冲,提供时序余量。

采样点位置 = (Sync_Seg + Prop_Seg + Phase_Seg1) / 总位时间。

时序余量通常指 Phase_Seg2 的长度,它决定了在重同步后还能容忍多少相位误差。若余量过小,任何微小的时钟漂移都可能导致采样错误。

实测环境与初始配置

  • 硬件:STM32H743ZI 开发板,FDCAN1 连接外部收发器(TJA1051),总线长度 2 米,终端电阻 120Ω。
  • 软件:STM32CubeMX 生成工程,HAL 库,主频 400MHz,FDCAN 内核时钟 20MHz。
  • 目标:仲裁段 1Mbit/s,数据段 5Mbit/s,采样点 75%(典型值)。

初始配置(CubeMX 中 FDCAN 参数):

  • 仲裁段:Prescaler = 1,Sync_Seg = 1,Prop_Seg = 2,Phase_Seg1 = 12,Phase_Seg2 = 5(总 tq = 20,采样点 = (1+2+12)/20 = 75%)。
  • 数据段:Prescaler = 1,Sync_Seg = 1,Prop_Seg = 1,Phase_Seg1 = 2,Phase_Seg2 = 1(总 tq = 5,采样点 = (1+1+2)/5 = 80%)。
  • 同步跳转宽度(SJW):仲裁段 = 4,数据段 = 1。

实测方法与数据

使用示波器(200MHz 带宽)测量 FDCAN TX 引脚波形,并利用 CAN 分析仪统计错误帧。测试条件:总线负载 50%,连续发送 10000 帧,每帧 8 字节数据。

初始配置下,错误帧计数为 0,但通过示波器观察,采样点附近的信号存在明显的振铃和过冲,尤其是在数据段切换时。进一步使用 CAN 分析仪的“位时序余量”功能(通过发送特定测试帧并测量 ACK 槽的相位偏移)得到:

  • 仲裁段实际采样点偏移:+0.3 tq(即采样点比理论值晚 0.3 tq)。
  • 仲裁段余量(Phase_Seg2 剩余):5 tq - 0.3 tq = 4.7 tq,看似充足,但在温度变化和总线长度增加时,余量会急剧下降。

优化策略

1. 调整同步跳转宽度(SJW)

SJW 决定了重同步时相位缓冲段可调整的最大步长。增大 SJW 可以更快地纠正大的相位误差,但过大会导致采样点抖动。在仲裁段,建议 SJW 设置为 4 或 5(最大不超过 Phase_Seg1),以应对总线长度变化。实测中,将仲裁段 SJW 从 4 改为 5,余量提升至 5.2 tq(因为重同步更积极)。

2. 优化采样点位置

采样点越靠后,余量越大,但会减少 Phase_Seg2 的长度。对于 1Mbit/s 仲裁段,推荐采样点 80%-85%。将 Phase_Seg1 增加到 14,Phase_Seg2 减少到 3(总 tq 仍为 20),采样点变为 (1+2+14)/20 = 85%,余量变为 3 tq,但实际偏移减小到 0.1 tq,因此有效余量 = 3 - 0.1 = 2.9 tq,比之前的 4.7 tq 小,但稳定性更好(因为采样点更靠后,抗干扰能力强)。实测错误帧仍为 0,但总线在 5 米长度下测试,错误帧从原来的 3 帧降为 0。

3. 使用硬件重同步(Hardware Resync)

FDCAN 支持在检测到显性位时自动重同步。确保在 CubeMX 中启用“Automatic Retransmission”和“Protocol Exception Handling”,并设置正确的“Resync Jump Width”。实测中,启用硬件重同步后,即使 SJW 较小,余量也得到改善。

完整代码示例(基于 HAL 库)

// FDCAN 初始化配置结构体
FDCAN_HandleTypeDef hfdcan1;

void FDCAN1_Init(void)
{
    hfdcan1.Instance = FDCAN1;
    hfdcan1.Init.ClockDivider = FDCAN_CLOCK_DIV1; // 内核时钟 20MHz
    hfdcan1.Init.FrameFormat = FDCAN_FRAME_FD_BRS; // 允许 BRS
    hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;
    hfdcan1.Init.AutoRetransmission = ENABLE;
    hfdcan1.Init.TransmitPause = DISABLE;
    hfdcan1.Init.ProtocolException = ENABLE;

    // 仲裁段配置:1Mbit/s,采样点 85%
    hfdcan1.Init.NominalPrescaler = 1;
    hfdcan1.Init.NominalSyncJumpWidth = 5; // SJW = 5
    hfdcan1.Init.NominalTimeSeg1 = 14;     // Prop_Seg + Phase_Seg1 = 2+14=16
    hfdcan1.Init.NominalTimeSeg2 = 3;      // Phase_Seg2 = 3

    // 数据段配置:5Mbit/s,采样点 80%
    hfdcan1.Init.DataPrescaler = 1;
    hfdcan1.Init.DataSyncJumpWidth = 1;
    hfdcan1.Init.DataTimeSeg1 = 2;         // Prop_Seg + Phase_Seg1 = 1+2=3
    hfdcan1.Init.DataTimeSeg2 = 1;         // Phase_Seg2 = 1

    hfdcan1.Init.StdFiltersNbr = 1;
    hfdcan1.Init.ExtFiltersNbr = 0;
    hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;

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

// 发送一帧 FDCAN 数据
void FDCAN1_SendFrame(uint32_t id, uint8_t *data, uint8_t len)
{
    FDCAN_TxHeaderTypeDef txHeader;
    txHeader.Identifier = id;
    txHeader.IdType = FDCAN_STANDARD_ID;
    txHeader.TxFrameType = FDCAN_DATA_FRAME;
    txHeader.DataLength = (len << 16); // 设置 DLC,例如 8 字节
    txHeader.BitRateSwitch = FDCAN_BRS_ON; // 启用 BRS
    txHeader.FDFormat = FDCAN_FD_CAN;      // FD 格式
    txHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;

    if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &txHeader, data) != HAL_OK)
    {
        // 处理错误
    }
}

// 主循环示例
int main(void)
{
    HAL_Init();
    SystemClock_Config(); // 配置 400MHz
    FDCAN1_Init();

    uint8_t txData[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};

    while (1)
    {
        FDCAN1_SendFrame(0x123, txData, 8);
        HAL_Delay(10); // 10ms 间隔
    }
}

注意事项

  • 时钟源选择:确保 FDCAN 内核时钟来自 PLL1Q,且频率稳定。在 400MHz 主频下,若使用 HSI 作为 PLL 源,误差可能较大,建议使用 HSE 晶振。
  • PCB 布局:FDCAN 差分线应等长、阻抗匹配(120Ω),并远离高频干扰源。实测中,若布线不当,即使时序余量充足,也会出现错误帧。
  • 采样点调整:不要盲目追求高采样点,需结合总线长度和节点数。长总线(>10m)建议采样点 80%,短总线(<1m)可到 85%。
  • SJW 与重同步:SJW 过大(如等于 Phase_Seg1)可能导致采样点抖动,引发错误。建议 SJW 不超过 Phase_Seg1 的一半。
  • 测试验证:优化后务必在极限条件(高温、长线、多节点)下进行压力测试,使用 CAN 分析仪统计错误帧和位错误率。

总结

通过实测和优化,STM32H7 在 400MHz 下 FDCAN 仲裁位时序余量可以从初始的 4.7 tq 提升至 5.2 tq(通过增大 SJW),同时通过调整采样点至 85% 增强了抗干扰能力。关键是要理解位时序各段的作用,并根据实际总线环境进行微调。本文提供的方法和代码可直接应用于工业控制、汽车电子等对可靠性要求高的场景。