引言

在高速嵌入式系统中,FDCAN(Flexible Data-rate CAN)总线作为车载和工业控制的关键通信接口,其仲裁位时序的稳定性直接决定网络可靠性。STM32H7 系列最高运行在 400MHz,但 FDCAN 外设的位时序由 APB1 时钟(通常为 100MHz)分频而来,这引入了量化误差和抖动。本文从原理出发,分析抖动来源,并给出可落地的补偿策略。

1. 仲裁位时序抖动根源

1.1 时钟分频与位时间量化

FDCAN 位时间由 TQ(Time Quantum)组成,每个 TQ 长度 = (BRP + 1) / F_APB1。在 400MHz 主频下,APB1 通常配置为 100MHz(分频系数 4)。若设置 BRP=0,则 TQ = 10ns。仲裁位时间(如 500kbps)需要 20 个 TQ,但 100MHz 时钟无法精确产生 2μs(20 个 10ns 正好,但若目标速率非整数倍则产生误差)。

1.2 同步段与重同步

FDCAN 协议规定每个位时间包含同步段(SYNC_SEG)、传播段(PROP_SEG)、相位缓冲段 1/2(PS1/PS2)。重同步机制会调整 PS1/PS2 长度,但调整步长为一个 TQ,这导致仲裁位边沿出现 ±1 TQ 的抖动。在 400MHz 下,1 TQ = 10ns,对于 500kbps 的位时间(2μs),抖动占比 0.5%,可能引发位错误。

1.3 硬件延迟差异

STM32H7 的 FDCAN 内核与 APB1 总线之间存在同步逻辑,加上 GPIO 输出驱动延迟,实际信号边沿与理想时刻存在固定偏移和随机抖动。固定偏移可通过软件补偿,随机抖动则需硬件机制抑制。

2. 补偿策略

2.1 优化时钟树配置

  • 将 APB1 时钟设为 100MHz,并确保 FDCAN 内核时钟(FDCAN_KER)直接来自 PLL2Q,而非 APB1 分频。STM32H7 支持 FDCAN 使用独立时钟源,可避免 APB1 分频误差。
  • 配置示例(使用 CubeMX):
    • PLL2 输出 Q 时钟 = 400MHz / 4 = 100MHz,直接作为 FDCAN_KER。
    • 设置 FDCAN 位时间参数:BRP=0,TQ=10ns,目标 500kbps 时,位时间=200 TQ,但 200 个 TQ 超出寄存器范围(最大 256),可行。

2.2 位时间参数精细调整

通过调整 SJW(同步跳转宽度)和 PS1/PS2 比例,减少重同步幅度。建议 SJW=1 TQ,PS1=10,PS2=10(对称),这样重同步最大调整 1 TQ,且相位裕量充足。

2.3 硬件定时器触发补偿

利用高级定时器(如 TIM1)产生与 FDCAN 发送起始对齐的 PWM 信号,通过比较匹配中断微调发送时刻。具体步骤:

  1. 配置 TIM1 时钟 = 400MHz,输出比较通道映射到 FDCAN TX 引脚(需 GPIO 复用)。
  2. 在 FDCAN 发送前,计算预期发送时刻,设置 TIM1 比较值,并在中断中触发 FDCAN 发送(通过软件触发)。
  3. 由于 TIM1 与 FDCAN 共享时钟源,可消除 APB1 分频抖动。

2.4 软件相位补偿

在 FDCAN 初始化时,读取实际发送边沿(通过捕获通道),计算与理想时刻的偏差,写入一个偏移寄存器,在后续发送中调整。但此方法仅补偿固定偏移,随机抖动仍需硬件。

3. 完整代码示例

以下代码基于 STM32H743,使用 HAL 库,配置 FDCAN1 为 500kbps 仲裁速率,并启用 TIM1 触发补偿。

// 初始化 FDCAN1
void FDCAN1_Init(void) {
    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.TransmitPause = DISABLE;
    hfdcan1.Init.ProtocolException = DISABLE;
    
    // 位时间参数:TQ=10ns,仲裁位时间=200TQ=2us
    hfdcan1.Init.NominalPrescaler = 0; // BRP=0
    hfdcan1.Init.NominalSyncJumpWidth = 1;
    hfdcan1.Init.NominalTimeSeg1 = 10; // PS1
    hfdcan1.Init.NominalTimeSeg2 = 10; // PS2
    
    // 数据段位时间(2Mbps)
    hfdcan1.Init.DataPrescaler = 0;
    hfdcan1.Init.DataSyncJumpWidth = 1;
    hfdcan1.Init.DataTimeSeg1 = 5;
    hfdcan1.Init.DataTimeSeg2 = 5;
    
    if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK) {
        Error_Handler();
    }
}

// 配置 TIM1 为 400MHz,用于触发发送
void TIM1_Trigger_Init(void) {
    TIM_HandleTypeDef htim1;
    htim1.Instance = TIM1;
    htim1.Init.Prescaler = 0; // 400MHz
    htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim1.Init.Period = 399; // 1us 周期
    htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    HAL_TIM_OC_Init(&htim1);
    
    // 配置比较通道1
    TIM_OC_InitTypeDef sConfigOC;
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = 200; // 50% 占空比
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);
    
    // 使能更新中断
    HAL_TIM_OC_Start_IT(&htim1, TIM_CHANNEL_1);
}

// 中断回调:在比较匹配时发送 FDCAN 帧
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim) {
    if (htim->Instance == TIM1) {
        FDCAN_TxHeaderTypeDef txHeader;
        uint8_t data[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
        txHeader.Identifier = 0x123;
        txHeader.IdType = FDCAN_STANDARD_ID;
        txHeader.TxFrameType = FDCAN_DATA_FRAME;
        txHeader.DataLength = FDCAN_DLC_BYTES_8;
        txHeader.FDFormat = FDCAN_FD_CAN;
        txHeader.BitRateSwitch = ENABLE;
        HAL_FDCAN_AddMessageToTxMailbox(&hfdcan1, &txHeader, data);
    }
}

// 主函数中启动发送
int main(void) {
    HAL_Init();
    SystemClock_Config(); // 配置 400MHz 主频,PLL2Q=100MHz 给 FDCAN
    FDCAN1_Init();
    TIM1_Trigger_Init();
    
    // 启动 FDCAN
    HAL_FDCAN_Start(&hfdcan1);
    HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0);
    
    while (1) {
        // 主循环空转,发送由 TIM1 中断触发
    }
}

4. 注意事项

  • 时钟源选择:务必确认 FDCAN_KER 来自 PLL2Q,而非 APB1,否则补偿无效。
  • 中断优先级:TIM1 中断优先级应高于 FDCAN 发送完成中断,避免延迟。
  • 抖动测量:使用逻辑分析仪或示波器测量实际边沿,验证补偿效果。建议在 400MHz 下,抖动应小于 5ns。
  • 温度漂移:晶振温漂会影响时钟精度,补偿策略需考虑温度补偿,或使用 TCXO。
  • 软件补偿局限性:软件方法无法消除随机抖动,仅适用于固定偏移。

5. 总结

STM32H7 的 FDCAN 在 400MHz 下,通过独立时钟源和精细位时间配置,可将仲裁位抖动控制在 1 TQ 内。结合硬件定时器触发,可进一步消除 APB1 分频误差,实现纳秒级稳定性。开发者应根据实际网络拓扑和速率需求,灵活调整 SJW 和相位段,并利用示波器验证。