2. DMA 基础回顾:工作原理、传输模式与请求仲裁

在深入串口 DMA 乒乓操作之前,必须牢固掌握 DMA 的核心机制。DMA(Direct Memory Access,直接存储器访问)允许外设或存储器之间直接交换数据,无需 CPU 逐字节干预。本章将系统梳理 DMA 的工作原理、三种传输模式以及请求与仲裁逻辑,为后续双缓冲设计打下硬件基础。

2.1 DMA 工作原理:从 CPU 卸载到专用通道

传统无 DMA 的串口收发中,CPU 需在每个字节到达或发送完成后进入中断服务函数,将数据从 DR 寄存器搬运到内存缓冲区。这种方式在高速通信(如 1 Mbps 以上)时会严重占用 CPU 时间,导致系统无法处理其他实时任务。

DMA 控制器本质上是一个独立的总线主设备,它拥有自己的地址寄存器、计数器和控制逻辑。一次典型的 DMA 传输包含以下四个阶段:

  1. 请求阶段:外设(如 USART)产生 DMA 请求信号(TXE / RXNE),通知 DMA 控制器需要传输一个数据单元。
  2. 仲裁阶段:当多个 DMA 通道同时请求时,仲裁器根据优先级规则选择当前最高优先级的通道。
  3. 传输阶段:DMA 控制器从源地址读取数据,写入目标地址,同时更新传输计数器和地址指针。
  4. 完成阶段:当传输计数器减至 0 时,DMA 通道产生传输完成中断(TCIF),通知 CPU 数据块已就绪。
关键概念:DMA 传输的最小单位是“数据单元”(字节、半字或字),由外设数据宽度决定。串口通常使用字节(8 位)宽度。
DMA 单次传输流程(以 USART 接收为例) 外设产生请求 DMA 仲裁 数据搬运 传输完成中断 CPU 处理数据 💡 整个传输过程中,CPU 仅在初始化配置和完成中断中参与,数据搬运阶段完全由 DMA 硬件自动完成。

2.2 DMA 传输模式:单次、循环与内存到内存

STM32 DMA 控制器支持三种核心传输模式,理解它们的差异是正确配置乒乓操作的前提。

传输模式 工作方式 传输完成后动作 典型应用场景
单次模式 (Normal) 传输指定数量的数据单元后停止 产生 TCIF 中断,通道关闭 单帧接收、一次性数据搬移
循环模式 (Circular) 传输完成后自动重载初始地址和计数,循环执行 每次循环结束产生 TCIF 中断 连续数据流、乒乓缓冲区、音频播放
内存到内存 (Memory-to-Memory) 由软件触发,无需外设请求 传输完成后产生 TCIF 中断 内存拷贝、数据整理、协议栈缓冲区移动
乒乓操作核心依赖:循环模式是双缓冲机制的基础。通过循环模式,DMA 可以在两个缓冲区之间自动切换,无需 CPU 在每次传输完成后重新配置地址和计数。
三种 DMA 传输模式对比 单次模式 源 目标 传输 N 个单元后停止 通道自动关闭 需重新配置才能再次启动 循环模式 源 目标 传输完成后自动重载 地址和计数回到初始值 循环持续运行 内存到内存 内存 A 内存 B 由软件触发启动 无需外设请求信号 常用于内存拷贝

2.3 DMA 请求与仲裁:多通道协同的规则

STM32 系列(如 F4/H7)通常拥有两个 DMA 控制器(DMA1 和 DMA2),每个控制器包含 8 个独立通道。每个通道可以响应多个外设的请求,但同一时刻只能服务于一个外设。

2.3.1 DMA 请求映射

每个外设的 DMA 请求被硬连线到特定的 DMA 通道。以 STM32F4 为例,USART1 的接收请求映射到 DMA2 通道 2,发送请求映射到 DMA2 通道 7。这种映射关系在参考手册的 DMA 请求映射表中定义,配置时必须严格对应。

外设 请求方向 DMA 控制器 通道 数据流
USART1_RX 外设 → 内存 DMA2 Channel 2 Stream 2
USART1_TX 内存 → 外设 DMA2 Channel 7 Stream 7
USART2_RX 外设 → 内存 DMA1 Channel 5 Stream 5
USART2_TX 内存 → 外设 DMA1 Channel 6 Stream 6
常见错误:初学者容易将 USART1_RX 配置到 DMA1 的某个通道,导致 DMA 请求永远无法触发。务必查阅芯片参考手册的 DMA 请求映射表,确认外设与通道的对应关系。

2.3.2 仲裁机制

当多个 DMA 通道同时请求总线访问时,仲裁器根据以下规则决定优先级:

  • 软件优先级:每个通道可配置为低、中、高、最高四个等级。
  • 硬件优先级:当软件优先级相同时,通道编号小的优先级更高(如 Channel 1 > Channel 2)。
  • 轮询策略:在循环模式下,DMA 控制器采用轮询方式确保所有通道都能获得总线访问机会,避免低优先级通道被饿死。
DMA 仲裁结构(多通道请求) USART1_RX USART1_TX SPI1_RX Ch2 Ch7 Ch3 仲裁器 优先级比较 轮询调度 AHB 总线 数据搬运 💡 仲裁器根据软件优先级和通道编号决定哪个请求获得总线访问权,确保高优先级实时任务不被阻塞。

2.4 DMA 配置关键参数速查

在 HAL 库中配置 DMA 时,以下参数直接影响传输行为:

// HAL 库 DMA 初始化结构体关键成员
DMA_HandleTypeDef hdma_usart1_rx;

hdma_usart1_rx.Instance                 = DMA2_Stream2;     // 数据流选择
hdma_usart1_rx.Init.Channel             = DMA_CHANNEL_4;    // 通道选择
hdma_usart1_rx.Init.Direction           = DMA_PERIPH_TO_MEMORY; // 传输方向
hdma_usart1_rx.Init.PeriphInc           = DMA_PINC_DISABLE; // 外设地址不递增
hdma_usart1_rx.Init.MemInc              = DMA_MINC_ENABLE;  // 内存地址递增
hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; // 外设数据宽度
hdma_usart1_rx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE; // 内存数据宽度
hdma_usart1_rx.Init.Mode                = DMA_CIRCULAR;     // 循环模式(乒乓操作关键)
hdma_usart1_rx.Init.Priority            = DMA_PRIORITY_HIGH; // 优先级
hdma_usart1_rx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE; // 直通模式
hdma_usart1_rx.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
hdma_usart1_rx.Init.MemBurst            = DMA_MBURST_SINGLE;
hdma_usart1_rx.Init.PeriphBurst         = DMA_PBURST_SINGLE;
乒乓操作配置要点:Mode 必须设置为 DMA_CIRCULAR,这样 DMA 在传输完一个缓冲区后会自动回到起始地址继续传输,配合双缓冲切换逻辑实现无缝数据流。