引言

STM32H7 系列(如 H743/H750)凭借 Cortex-M7 内核和双总线架构,在工业控制和车载应用中常需同时处理 FDCAN(CAN FD)与以太网通信。当两者并发访问内部 SRAM 或外设时,总线仲裁(Bus Arbitration)会导致额外延迟,尤其在 480MHz 主频下,外设时钟与总线频率不匹配可能加剧问题。本文通过实测揭示延迟分布,并提供可落地的优化手段。

一、总线架构与仲裁机制

STM32H7 使用 AXI 总线矩阵连接内核、DMA 和外设。FDCAN 和以太网 MAC 均通过 AHB 总线访问 SRAM(如 DTCM、AXI SRAM)。当两个外设同时发起传输时,总线矩阵依据固定优先级(由 AHB1/AHB2PRICTL 寄存器配置)进行仲裁。默认情况下,优先级为轮询(Round-Robin),但高负载时会产生不确定延迟。

实测环境:

  • MCU:STM32H743VIT6,主频 480MHz
  • FDCAN1:1Mbps 仲裁段,5Mbps 数据段,发送周期 1ms
  • 以太网:100Mbps,接收中断频繁,DMA 突发传输 32 字节
  • 测量点:FDCAN 发送完成中断(TX Complete)到实际总线发送起始的时间差

二、实测延迟数据

使用逻辑分析仪捕获 FDCAN TX 引脚和以太网 TX 使能信号,统计 10 万次发送的延迟分布:

| 场景 | 平均延迟 (µs) | 最大延迟 (µs) | 抖动 (µs) | |------|--------------|--------------|----------| | 仅 FDCAN 发送 | 0.8 | 1.2 | 0.4 | | 仅以太网接收 | - | - | - | | 并发(默认配置) | 2.3 | 5.7 | 3.4 | | 并发(优化后) | 1.1 | 1.8 | 0.7 |

可见,默认配置下最大延迟达 5.7µs,可能违反 CAN FD 的帧间间隔要求(通常需 < 3µs)。延迟主要来自:

  • 以太网 DMA 突发占用总线,FDCAN 等待仲裁
  • 中断优先级不当导致 FDCAN 发送被延迟
  • SRAM 访问冲突(FDCAN 使用 AXI SRAM,以太网使用 DTCM)

三、优化策略与实现

1. 调整总线仲裁优先级

将 FDCAN 的 AHB 接口优先级设为高,以太网设为低。在 HAL_RCC_ClockConfig 后配置:

// 使能 AHB1 外设时钟
__HAL_RCC_AHB1_CLK_ENABLE();

// 设置 AHB1 总线矩阵优先级:FDCAN1 高,以太网低
MODIFY_REG(AHB1->PRICTL, AHB_PRICTL_PRIO_0 | AHB_PRICTL_PRIO_1, 
           (0x2 << AHB_PRICTL_PRIO_0_Pos) | (0x1 << AHB_PRICTL_PRIO_1_Pos));
// 注意:具体位域需参考参考手册,此处示意

2. 分离 SRAM 区域

将 FDCAN 的发送/接收 FIFO 分配到 DTCM(数据紧耦合内存),以太网 DMA 描述符和缓冲区分配到 AXI SRAM。DTCM 具有独立总线,不与 AHB 冲突。

// 在链接脚本中定义 DTCM 段
__attribute__((section(".dtcm"))) FDCAN_RxHeaderTypeDef can_rx_header;
__attribute__((section(".dtcm"))) uint8_t can_rx_data[8];

// 以太网 DMA 描述符放在 AXI SRAM(默认)
ETH_DMADescTypeDef dma_rx_desc[ETH_RX_DESC_CNT] __attribute__((section(".eth_dma")));

3. 优化中断优先级和 DMA 突发长度

将 FDCAN TX 中断优先级设为最高(抢占优先级 0),以太网中断设为较低(如 2)。同时减小以太网 DMA 突发长度,从 32 字节降至 16 字节,减少单次占用总线时间。

// 配置 NVIC
HAL_NVIC_SetPriority(FDCAN1_IT0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn);
HAL_NVIC_SetPriority(ETH_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(ETH_IRQn);

// 以太网 DMA 配置:设置突发长度
ETH_DMAConfTypeDef dma_conf;
dma_conf.BurstMode = ETH_BURST_LENGTH_16; // 默认 32
HAL_ETH_ConfigDMA(&heth, &dma_conf);

4. 使用 FDCAN 的 Tx Event FIFO 和硬件时间戳

启用 Tx Event FIFO,可精确记录发送起始时间,便于调试延迟。同时,利用 FDCAN 的自动重传功能,避免软件重传引入额外延迟。

FDCAN_TxEventFifoConfigTypeDef tef_config;
tef_config.TxEventFifoWatermark = 1;
HAL_FDCAN_ConfigTxEventFifo(&hfdcan1, &tef_config);
HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_TX_EVENT_FIFO_NEW_MESSAGE, 0);

四、完整代码示例(关键部分)

以下为初始化后配置优先级的示例,集成上述优化:

void System_OptimizeForConcurrent(void) {
    // 1. 设置总线仲裁优先级(AHB1)
    __HAL_RCC_AHB1_CLK_ENABLE();
    AHB1->PRICTL = (AHB1->PRICTL & ~(AHB_PRICTL_PRIO_0_Msk | AHB_PRICTL_PRIO_1_Msk)) |
                   (0x2 << AHB_PRICTL_PRIO_0_Pos) | (0x1 << AHB_PRICTL_PRIO_1_Pos);

    // 2. 配置中断优先级
    HAL_NVIC_SetPriority(FDCAN1_IT0_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn);
    HAL_NVIC_SetPriority(ETH_IRQn, 2, 0);
    HAL_NVIC_EnableIRQ(ETH_IRQn);

    // 3. 调整以太网 DMA 突发长度
    ETH_DMAConfTypeDef dma_conf;
    dma_conf.BurstMode = ETH_BURST_LENGTH_16;
    HAL_ETH_ConfigDMA(&heth, &dma_conf);

    // 4. 启用 FDCAN Tx Event FIFO
    FDCAN_TxEventFifoConfigTypeDef tef_config;
    tef_config.TxEventFifoWatermark = 1;
    HAL_FDCAN_ConfigTxEventFifo(&hfdcan1, &tef_config);
    HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_TX_EVENT_FIFO_NEW_MESSAGE, 0);
}

五、注意事项

  • 优先级配置需谨慎:将 FDCAN 优先级设太高可能饿死以太网,导致丢包。建议根据实际负载调整,并监控以太网吞吐量。
  • DTCM 容量有限:H743 的 DTCM 为 128KB,若 FDCAN 数据量大,可只将关键描述符放入,数据缓冲区仍用 AXI SRAM。
  • 中断服务函数要短:在 FDCAN 中断中只做标志位设置,实际处理放到主循环或低优先级任务,避免阻塞高优先级中断。
  • 实测验证:优化后需用示波器或逻辑分析仪重新测量延迟,确保满足应用需求。

结语

通过调整总线仲裁优先级、分离 SRAM 区域、优化中断和 DMA 配置,STM32H7 在 FDCAN 与以太网并发时的最大仲裁延迟从 5.7µs 降至 1.8µs,降幅达 68%。该方法适用于其他外设并发场景,开发者可举一反三。记住,实时性优化需结合实测数据,避免盲目调整。