STM32H7 600MHz 下 FDCAN 与以太网并发传输的 DMA 仲裁优先级陷阱与规避

一、问题背景

STM32H7 系列采用双核或单核 Cortex-M7,主频高达 600MHz,内部总线架构为 AXI 总线矩阵(AXI-M7)与 AHB/APB 桥接。FDCAN 和以太网 MAC(Ethernet)均通过 DMA 控制器访问内存,但它们的 DMA 请求路径不同:FDCAN 使用 DMA1/DMA2(挂载于 AHB1),以太网使用独立的 DMA(挂载于 AXI 总线)。当两者并发传输时,AXI 总线矩阵的仲裁策略可能产生优先级反转,导致 FDCAN 帧丢失或以太网帧超时。

二、DMA 仲裁机制原理

2.1 AXI 总线矩阵仲裁

STM32H7 的 AXI 总线矩阵采用基于 ID 的仲裁算法,每个主设备(如 Cortex-M7、DMA1、DMA2、Ethernet DMA)拥有固定的 ID 和优先级。默认情况下,仲裁优先级由硬件固定,但可通过 AXI_CR 寄存器调整。关键点:

  • DMA1/DMA2 的优先级低于 Ethernet DMA(因为 Ethernet DMA 直接连接 AXI 总线,而 DMA1/2 通过 AHB 桥接)。
  • 当 Ethernet DMA 持续占用总线(如大包传输),FDCAN 的 DMA 请求会被阻塞,造成 FIFO 溢出。

2.2 FDCAN 的 DMA 请求特性

FDCAN 使用 DMA 进行消息收发,每个消息帧需要多次 DMA 传输(如从 SRAM 读取消息 RAM)。若 DMA 请求延迟超过 FDCAN 的硬件超时(如 1ms),则触发错误中断。在 600MHz 下,总线时钟快,但仲裁延迟可能成为瓶颈。

三、陷阱场景复现

假设系统配置:

  • FDCAN1 波特率 5Mbps,每个消息 64 字节数据,发送频率 10kHz。
  • Ethernet 使用 DMA 环形缓冲区,接收 1500 字节帧,中断频率 1kHz。

默认配置下,运行 10 分钟后,FDCAN 出现 FDCAN_IRQ 错误(如 DATA LOST),而 Ethernet 正常。通过逻辑分析仪发现,FDCAN 的 DMA 请求在 Ethernet 突发传输期间被延迟约 200μs,超过 FDCAN 的容忍阈值。

四、规避方案

4.1 调整 AXI 总线优先级

通过修改 AXI_CR 寄存器,提高 DMA1/DMA2 的优先级。但需注意,过高优先级可能影响 Cortex-M7 的实时性。推荐设置:

// 设置 DMA1 和 DMA2 为高优先级(高于 Ethernet DMA)
AXI->CR &= ~(AXI_CR_DMA1_PRI_MASK | AXI_CR_DMA2_PRI_MASK);
AXI->CR |= (0x3 << AXI_CR_DMA1_PRI_Pos) | (0x3 << AXI_CR_DMA2_PRI_Pos); // 优先级 3(最高)

但此方法可能影响其他 AXI 主设备,需评估。

4.2 使用 FDCAN 的 RAM 直接访问(DMA 旁路)

FDCAN 支持通过 AHB 直接访问消息 RAM(如使用 FDCAN_WriteToRAM 函数),绕过 DMA。但会占用 CPU 时间,不适合高负载。

4.3 优化 DMA 传输粒度

将 FDCAN 的 DMA 传输配置为单次突发(Burst=1),减少总线占用时间,降低冲突概率。在 CubeMX 中设置:

hdma_fdcan1.Init.Burst = DMA_BURST_SINGLE;
hdma_fdcan1.Init.TransferMode = DMA_NORMAL;

4.4 使用中断而非 DMA(低负载场景)

若 FDCAN 流量不大(<1Mbps),可改用中断方式,避免 DMA 仲裁问题。但注意中断延迟。

4.5 综合方案(推荐)

结合优先级调整与突发限制,并启用 FDCAN 的自动重传功能:

// 1. 调整 AXI 优先级(仅提升 DMA1,用于 FDCAN)
AXI->CR = (AXI->CR & ~AXI_CR_DMA1_PRI_MASK) | (0x2 << AXI_CR_DMA1_PRI_Pos);

// 2. 配置 FDCAN 自动重传(避免瞬时丢失)
FDCAN_InitTypeDef init = {0};
init.AutoRetransmission = ENABLE;
HAL_FDCAN_Init(&hfdcan1, &init);

// 3. 以太网 DMA 设置循环模式,并降低中断频率(使用 coalescing)
HAL_ETH_ConfigRxCoalesce(&heth, ETH_RX_COALESCE_TIMER_100US);

五、完整代码示例

以下为基于 STM32H743 的初始化代码片段(使用 HAL 库):

// 全局变量
FDCAN_HandleTypeDef hfdcan1;
ETH_HandleTypeDef heth;

void SystemClock_Config(void);

static void MX_FDCAN1_Init(void) {
    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 = ENABLE;
    hfdcan1.Init.TransmitPause = DISABLE;
    hfdcan1.Init.ProtocolException = DISABLE;
    hfdcan1.Init.NominalPrescaler = 10;
    hfdcan1.Init.NominalSyncJumpWidth = 1;
    hfdcan1.Init.NominalTimeSeg1 = 13;
    hfdcan1.Init.NominalTimeSeg2 = 2;
    hfdcan1.Init.DataPrescaler = 5;
    hfdcan1.Init.DataSyncJumpWidth = 1;
    hfdcan1.Init.DataTimeSeg1 = 13;
    hfdcan1.Init.DataTimeSeg2 = 2;
    hfdcan1.Init.StdFiltersNbr = 1;
    hfdcan1.Init.ExtFiltersNbr = 0;
    hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
    if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK) { Error_Handler(); }
    // 配置 DMA 为单次突发
    hdma_fdcan1.Init.Burst = DMA_BURST_SINGLE;
    hdma_fdcan1.Init.TransferMode = DMA_NORMAL;
    HAL_DMA_Init(&hdma_fdcan1);
}

static void MX_ETH_Init(void) {
    heth.Instance = ETH;
    heth.Init.MACAddr[0] = 0x00;
    // ... 其他 MAC 配置
    heth.Init.RxMode = ETH_RX_INTERRUPT_MODE;
    heth.Init.ChecksumMode = ETH_CHECKSUM_BY_HARDWARE;
    if (HAL_ETH_Init(&heth) != HAL_OK) { Error_Handler(); }
    // 启用接收合并(coalescing)
    HAL_ETH_ConfigRxCoalesce(&heth, ETH_RX_COALESCE_TIMER_100US);
}

void main(void) {
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_FDCAN1_Init();
    MX_ETH_Init();

    // 调整 AXI 优先级:提升 DMA1(FDCAN 使用)
    AXI->CR = (AXI->CR & ~AXI_CR_DMA1_PRI_MASK) | (0x2 << AXI_CR_DMA1_PRI_Pos);

    // 启动 FDCAN
    HAL_FDCAN_Start(&hfdcan1);
    HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0);

    // 启动以太网
    HAL_ETH_Start(&heth);

    while (1) {
        // 主循环
    }
}

六、注意事项

  • 优先级调整的副作用:提高 DMA1 优先级可能增加 Cortex-M7 访问 AXI 总线的延迟,影响实时任务。建议在系统初始化时设置,并通过压力测试验证。
  • FDCAN 自动重传:启用后,若发送失败会自动重传,但会增加总线负载,需确保波特率余量。
  • 以太网合并中断:降低中断频率可减少 CPU 负载,但会增加延迟,适合非实时应用。
  • 调试建议:使用逻辑分析仪监测 DMA 请求信号(如 DMA_REQ)和总线占用,确认冲突点。
  • 不同型号差异:H7 系列中,H743 与 H750 的 AXI 优先级寄存器可能略有不同,请参考对应参考手册。

七、总结

STM32H7 的 DMA 仲裁优先级陷阱是并发传输中的隐性杀手。通过理解 AXI 总线矩阵的仲裁机制,合理调整优先级、优化 DMA 突发模式,并利用 FDCAN 的自动重传和以太网的合并中断,可以有效规避数据丢失和超时问题。建议在实际项目中结合具体流量模型进行调优,并充分测试。