引言

在工业自动化和车载网络中,时间同步是分布式系统协同工作的基石。STM32H7 系列以 400MHz 主频和丰富的外设,成为实现 FDCAN(灵活数据速率控制器局域网)与 TSN(时间敏感网络)桥接的理想平台。然而,FDCAN 的位时间与 TSN 的纳秒级时钟存在固有延迟,若不做补偿,同步误差可达数十微秒。本文聚焦硬件级延迟补偿,利用 STM32H7 的定时器输入捕获和 FDCAN 硬件时间戳,实现精确的时钟对齐。

时间同步原理与延迟来源

同步机制概述

  • TSN 侧:基于 IEEE 802.1AS(gPTP),通过 Sync 和 Follow_Up 报文传递主时钟时间,从节点计算路径延迟并修正本地时钟。
  • FDCAN 侧:CAN 协议本身无全局时钟,需借助时间戳寄存器记录报文收发时刻,再通过上层协议(如 CANopen)同步。

延迟组成

  • 传输延迟:FDCAN 总线上的信号传播时间,通常固定。
  • 处理延迟:从报文到达 FDCAN 控制器到 CPU 读取时间戳的软件开销,可达数微秒。
  • 时钟域偏差:TSN 的 125MHz 参考时钟与 FDCAN 的 40MHz 外设时钟不同步,导致累计漂移。

硬件级补偿的核心是:利用 STM32H7 的 TIM 定时器捕捉 FDCAN 收发时刻的硬件信号,并关联到 TSN 的全局时间基准,从而消除软件延迟。

STM32H7 硬件资源分析

FDCAN 时间戳功能

  • STM32H7 的 FDCAN 内核内置 16 位或 32 位时间戳计数器,可配置为基于外设时钟或外部定时器。
  • 每个报文在 SOF(帧起始)或 EOF(帧结束)时自动捕获时间戳,无需 CPU 干预。

高级定时器 TIM1/TIM8

  • 支持输入捕获和外部时钟模式,可连接 FDCAN 的 TX/RX 引脚,捕捉边沿事件。
  • 定时器时钟可来自内部 PLL,与 TSN 的时钟同步(通过 PLL 分频)。

TSN 接口(如 FMC 或 ETH)

  • 部分 STM32H7 型号集成 TSN 以太网 MAC,提供硬件时间戳单元(IEEE 1588v2),可输出同步脉冲。

硬件级延迟补偿实现方案

方案设计

  • 将 FDCAN 的 RX 引脚连接到 TIM1 的通道 1,配置为输入捕获,上升沿触发。
  • TIM1 的时钟源设为 TSN 的同步时钟(例如 125MHz),确保与 TSN 时间基准一致。
  • 当 FDCAN 报文到达时,TIM1 捕获当前计数值,该值即报文到达的硬件时间戳。
  • 同时,FDCAN 内部时间戳寄存器记录报文接收时刻,两者差值即为硬件延迟,可写入补偿寄存器。

配置步骤

  1. 时钟树配置:使用 CubeMX 将 TIM1 时钟设为 125MHz(与 TSN 同步),FDCAN 时钟设为 40MHz。
  2. FDCAN 配置:启用时间戳,选择外部时钟源(TIM1),设置时间戳分辨率。
  3. TIM1 配置:输入捕获模式,通道 1 映射到 FDCAN_RX,预分频器设为 0,捕获边沿为上升沿。
  4. 中断处理:在捕获中断中读取 TIM1->CCR1,并与 FDCAN 时间戳比较,计算补偿值。
  5. TSN 同步:通过 TSN 的 gPTP 协议获取主时钟,调整 TIM1 的 ARR 以实现微调。

完整代码示例

以下代码基于 STM32H743 和 HAL 库,演示核心配置与中断处理。

// 初始化 FDCAN 时间戳
void FDCAN_Init_With_Timestamp(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;
    // 配置时间戳:使用外部定时器 TIM1,分辨率 8ns(125MHz)
    hfdcan1.Init.TimestampConfig = FDCAN_TIMESTAMP_EXTERNAL;
    hfdcan1.Init.TimestampPrescaler = 0; // 直接使用外部时钟
    HAL_FDCAN_Init(&hfdcan1);
}

// 初始化 TIM1 输入捕获
void TIM1_InputCapture_Init(void) {
    TIM_HandleTypeDef htim1;
    htim1.Instance = TIM1;
    htim1.Init.Prescaler = 0;
    htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim1.Init.Period = 0xFFFFFFFF; // 32 位计数器
    HAL_TIM_IC_Init(&htim1);

    TIM_IC_InitTypeDef sConfigIC;
    sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
    sConfigIC.ICSelection = TIM_IC_SELECTION_DIRECTTI;
    sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
    sConfigIC.ICFilter = 0;
    HAL_TIM_IC_ConfigChannel(&htim1, &sConfigIC, TIM_CHANNEL_1);
    HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_1);
}

// 捕获中断回调:计算补偿
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
    if (htim->Instance == TIM1) {
        uint32_t hw_timestamp = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
        // 读取 FDCAN 时间戳(假设已存储)
        uint32_t fdcan_timestamp = get_fdcan_timestamp();
        int32_t delay = (int32_t)(hw_timestamp - fdcan_timestamp);
        // 将补偿值写入 FDCAN 的延迟补偿寄存器(需根据具体型号)
        FDCAN1->TSCC |= (delay & 0xFFFF); // 示例,实际需参考手册
    }
}

// 主函数中初始化并启动
int main(void) {
    HAL_Init();
    SystemClock_Config(); // 配置 400MHz 主频,TIM1 时钟 125MHz
    FDCAN_Init_With_Timestamp();
    TIM1_InputCapture_Init();
    HAL_FDCAN_Start(&hfdcan1);
    while (1) {
        // 主循环处理 TSN 同步任务
    }
}

注意事项与调试技巧

  • 时钟对齐:确保 TIM1 时钟与 TSN 的 125MHz 基准同源,否则补偿值会漂移。可使用 PLL 的专用输出。
  • 中断优先级:捕获中断应设为最高优先级,避免延迟导致时间戳误差。
  • 补偿值范围:FDCAN 延迟补偿寄存器通常为 16 位,若延迟超过范围,需调整预分频器。
  • 调试方法:使用逻辑分析仪同时监测 FDCAN 报文和 TSN 同步脉冲,对比时间戳差值。
  • 温度影响:晶振漂移会导致补偿失效,建议定期通过 TSN 的 Follow_Up 报文校准。

结语

通过 STM32H7 的硬件定时器与 FDCAN 时间戳协同,可以在 400MHz 主频下实现亚微秒级的延迟补偿,满足 TSN 的严格同步要求。本文的方案避免了软件轮询的延迟,适合对实时性要求极高的嵌入式系统。开发者可根据具体应用调整时钟源和补偿算法,进一步优化同步精度。