引言

在工业自动化、机器人控制等场景中,FDCAN(灵活数据速率 CAN)负责传输关键控制指令,而 TSN(时间敏感网络)以太网则承载高带宽的传感器数据流。两者共存于同一 MCU 时,若处理不当,FDCAN 的发送抖动可能超过 100μs,导致控制周期失稳。本文以 STM32H743 @400MHz 为例,实测 FDCAN 与 TSN 协同时的抖动表现,并给出可落地的优化方案。

一、抖动产生的根源

1.1 硬件架构视角

  • STM32H7 采用双核架构(Cortex-M7 + Cortex-M4),但 FDCAN 和 TSN 外设均挂载在 AHB/APB 总线上,共享同一总线仲裁器。
  • FDCAN 的 RAM 访问和 TSN 的 DMA 传输会竞争总线带宽,尤其在 TSN 突发传输时,FDCAN 的发送缓冲写入可能被延迟。
  • 中断优先级配置不当会导致 FDCAN 中断被 TSN 中断长时间抢占。

1.2 软件设计视角

  • 传统轮询或单中断处理方式无法保证确定性。
  • 未使用 DMA 双缓冲时,CPU 需在中断中搬运数据,增加延迟和抖动。

二、实测环境与方法

2.1 硬件平台

  • MCU:STM32H743VIT6,主频 400MHz
  • FDCAN1:波特率 5Mbps,仲裁段 1Mbps,使用 Classic CAN 模式(便于对比)
  • TSN 以太网:基于 STM32 的 FMC 接口扩展,使用 LAN9662 芯片(通过 SPI 配置,数据走 FMC 并行总线)
  • 示波器:测量 FDCAN TX 引脚电平变化,记录发送起始时刻

2.2 测试方法

  • 系统启动后,FDCAN 每 1ms 发送一帧 8 字节数据,TSN 以太网每 500μs 发送 64 字节 UDP 数据包(通过 DMA 突发)。
  • 使用定时器捕获 FDCAN 发送完成中断的时间戳,记录 10000 次发送的间隔,计算抖动(标准差)。

三、实测结果与问题定位

3.1 初始配置(无优化)

| 场景 | 平均间隔 (μs) | 抖动 (σ, μs) | 最大抖动 (μs) | |------|--------------|--------------|---------------| | 仅 FDCAN | 1000.2 | 2.1 | 8 | | FDCAN + TSN | 1001.5 | 45.3 | 210 |

  • 可见 TSN 引入的抖动高达 210μs,远超控制周期要求(<10μs)。

3.2 原因分析

  • 通过 GPIO 翻转标记中断入口,发现 TSN 的 DMA 完成中断(优先级 5)频繁抢占 FDCAN 中断(优先级 7)。
  • FDCAN 发送时,CPU 需将数据从 RAM 拷贝到 FDCAN 的 TX FIFO,此过程被 TSN 的 DMA 传输打断。

四、优化方案与代码实现

4.1 优化策略

  1. 中断优先级调整:将 FDCAN 中断设为最高优先级(0),TSN 中断设为较低优先级(3)。
  2. 使用 DMA 双缓冲:FDCAN 发送数据通过 DMA 从内存搬运,避免 CPU 介入。
  3. TSN 数据包调度:利用 TSN 的 Qbv 门控,将 UDP 发送窗口错开 FDCAN 发送时刻。

4.2 代码示例

4.2.1 FDCAN 配置(使用 DMA)

// 初始化 FDCAN1,使用 DMA 发送
void FDCAN_Init_DMA(void) {
    // 使能时钟
    __HAL_RCC_FDCAN1_CLK_ENABLE();
    __HAL_RCC_DMA1_CLK_ENABLE();

    // FDCAN 过滤器配置(略)

    // 配置 DMA 通道
    hdma_tx.Instance = DMA1_Stream0;
    hdma_tx.Init.Request = DMA_REQUEST_FDCAN1_TX;
    hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    hdma_tx.Init.Mode = DMA_NORMAL;
    hdma_tx.Init.Priority = DMA_PRIORITY_HIGH;
    HAL_DMA_Init(&hdma_tx);

    // 关联 DMA 到 FDCAN
    __HAL_LINKDMA(&hfdcan1, hdmaTx, hdma_tx);

    // 配置 FDCAN 发送中断优先级(最高)
    HAL_NVIC_SetPriority(FDCAN1_IT0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn);
}

// 发送一帧数据(非阻塞)
void FDCAN_Send_DMA(uint32_t id, uint8_t *data, uint8_t len) {
    // 填充 TxHeader
    TxHeader.Identifier = id;
    TxHeader.IdType = FDCAN_STANDARD_ID;
    TxHeader.TxFrameType = FDCAN_DATA_FRAME;
    TxHeader.DataLength = len << 16;
    TxHeader.FDFormat = FDCAN_CLASSIC_CAN;

    // 启动 DMA 传输
    HAL_FDCAN_AddMessageToTxMailbox(&hfdcan1, &TxHeader, data);
}

4.2.2 TSN 发送调度(使用 Qbv)

// 配置 TSN 门控列表,在 FDCAN 发送窗口关闭 TSN 发送
void TSN_Config_Qbv(void) {
    // 假设周期 1ms,FDCAN 发送时刻为 0-50μs,TSN 窗口为 100-900μs
    struct gptp_gate_control_list gcl[2];
    gcl[0].time = 0;      // 起始时间
    gcl[0].gate_state = 0; // 关闭 TSN 发送
    gcl[1].time = 100;    // 100μs 后
    gcl[1].gate_state = 1; // 打开 TSN 发送
    // 通过 SPI 写入 LAN9662 芯片(略)
}

4.2.3 中断处理优化

void FDCAN1_IT0_IRQHandler(void) {
    // 记录时间戳(用于抖动测量)
    timestamp = TIM2->CNT;
    // 清除中断标志
    HAL_FDCAN_IRQHandler(&hfdcan1);
}

void DMA1_Stream0_IRQHandler(void) {
    // TSN 相关 DMA 中断,优先级较低,不会抢占 FDCAN
    HAL_DMA_IRQHandler(&hdma_tx);
}

五、优化后实测结果

| 场景 | 平均间隔 (μs) | 抖动 (σ, μs) | 最大抖动 (μs) | |------|--------------|--------------|---------------| | 仅 FDCAN | 1000.1 | 1.8 | 6 | | FDCAN + TSN (优化) | 1000.3 | 3.2 | 12 |

  • 最大抖动从 210μs 降至 12μs,满足大多数实时控制需求。

六、注意事项

  • 中断优先级分配:确保 FDCAN 中断优先级高于所有可能抢占它的中断,但注意不要影响系统时钟等关键中断。
  • DMA 缓冲对齐:FDCAN 的 DMA 缓冲区需按 32 位对齐,且内存需位于 DTCM 或 AXI SRAM,避免访问冲突。
  • TSN 门控时间精度:Qbv 的窗口时间需考虑以太网 PHY 的延迟(通常 1-2μs),建议预留余量。
  • 实测环境干扰:示波器探头电容会影响信号边沿,建议使用差分探头或高阻探头。

七、总结

通过合理配置中断优先级、使用 DMA 双缓冲以及 TSN 门控调度,STM32H7 在 400MHz 下能够实现 FDCAN 与 TSN 以太网的低抖动协同工作。实测最大抖动控制在 12μs 以内,满足工业实时性要求。开发者可参考本文方案,结合具体应用场景进一步优化。