STM32H7 600MHz 下 FDCAN 与以太网并发传输的 DMA 仲裁优先级陷阱与规避
👁 1 阅读 · 2026-08-27 · 嵌入式
在 STM32H7 系列(如 H743/H750)中,当 FDCAN 与以太网 MAC 同时运行于 600MHz 主频时,DMA 仲裁机制可能引发隐蔽的数据丢失或延迟超时问题。本文深入剖析 AXI 总线矩阵与 DMA 控制器的优先级策略,揭示默认配置下的陷阱,并提供一套基于 CubeMX 和寄存器级的规避方案,确保实时性与带宽的平衡。
# 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 的实时性。推荐设置:
```c
// 设置 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 中设置:
```c
hdma_fdcan1.Init.Burst = DMA_BURST_SINGLE;
hdma_fdcan1.Init.TransferMode = DMA_NORMAL;
```
### 4.4 使用中断而非 DMA(低负载场景)
若 FDCAN 流量不大(<1Mbps),可改用中断方式,避免 DMA 仲裁问题。但注意中断延迟。
### 4.5 综合方案(推荐)
结合优先级调整与突发限制,并启用 FDCAN 的自动重传功能:
```c
// 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 库):
```c
// 全局变量
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 的自动重传和以太网的合并中断,可以有效规避数据丢失和超时问题。建议在实际项目中结合具体流量模型进行调优,并充分测试。