2. DMA基础概念

在嵌入式与高性能计算系统中,数据搬运往往比数据计算更消耗时间。如果每一次外设与内存之间的数据交换都要CPU亲自执行加载和存储指令,CPU就会被大量“搬砖”工作拖住,无法专注于算法与控制逻辑。DMA(Direct Memory Access,直接存储器访问)正是为解决这一矛盾而设计的硬件机制:它允许外设与内存之间、内存与内存之间直接传输数据,而CPU只需发起配置和接收完成通知,无需逐字节参与搬运。

一、DMA的定义与核心工作原理

DMA是一种由专用控制器(DMAC,DMA Controller)代替CPU完成数据搬运的技术。CPU不再执行“读—写”循环,而是把源地址、目的地址、传输长度、传输方向、数据宽度、触发方式等参数写入DMA控制器的寄存器,然后启动传输。DMA控制器随后向总线申请控制权,获得授权后按配置自动完成数据块搬运,传输结束后通过中断或状态位通知CPU。

从信号链角度看,一次典型DMA传输包含以下关键环节:

  • 请求:外设(如UART、ADC、SPI)产生DMA请求信号,表示有数据待发送或已接收。
  • 仲裁:DMA控制器向总线仲裁器申请总线使用权,获得授权后才能访问内存和外设。
  • 搬运:DMA控制器在源与目的之间执行读/写操作,每次搬运一个数据单元(字节、半字或字)。
  • 计数:每搬运一次,传输计数器递减,直到达到设定长度。
  • 完成:计数器归零后产生传输完成中断,CPU在中断服务程序中处理后续逻辑。

下面这张信号链与数据流示意图展示了DMA控制器在CPU、内存与外设之间的位置关系,以及请求线、总线授权和完成中断的流向:

DMA控制器在系统中的位置与信号流 CPU 配置 / 中断处理 DMA控制器 源/目的/长度/方向 通道仲裁与计数 内存 缓冲区 / 数据区 外设 UART / ADC / SPI 请求线 DRQ 配置寄存器 数据搬运 DMA请求 完成中断 系统总线(地址 / 数据 / 控制)

二、DMA与CPU轮询、PIO的对比

理解DMA的价值,最直接的方式是与CPU轮询(Polling)和PIO(Programmed I/O)进行对比。PIO模式下,CPU执行循环指令逐字节读写外设数据寄存器;轮询模式下,CPU不断查询状态位判断数据是否就绪。两者都会让CPU长时间处于“忙等”或“搬运”状态,吞吐量受限于CPU指令周期,且难以同时处理其他任务。

对比维度 CPU轮询 / PIO DMA传输
CPU占用 高,逐字节参与 低,仅配置与中断
数据吞吐率 受指令周期限制 接近总线带宽
适用数据量 小批量、低速 大批量、高速
实现复杂度 简单,无需额外控制器 需配置DMA通道与描述符
实时性影响 易阻塞其他任务 CPU可并行处理其他逻辑
提示:DMA并非在所有场景都优于PIO。对于极短的数据传输(如几个字节的寄存器读写),配置DMA的开销可能超过直接PIO搬运的成本。工程上应根据数据量、频率和CPU负载综合选择。

三、传输方向、通道与请求线

DMA传输方向通常分为三类:外设到内存(Peripheral-to-Memory)、内存到外设(Memory-to-Peripheral)、内存到内存(Memory-to-Memory)。前两者最常见于串口收发、ADC采样、音频播放等场景;内存到内存则用于大块数据拷贝,如帧缓冲区复制。

DMA控制器内部通常包含多个独立通道(Channel),每个通道可绑定一个外设请求线。通道之间通过仲裁器分配优先级,避免多个外设同时请求时发生冲突。请求线(DRQ)是外设与DMA控制器之间的握手信号:外设数据就绪时拉高请求,DMA控制器响应后执行搬运,搬运完成后再释放总线。

典型DMA通道配置参数(以STM32为例):
- Channel:        DMA1_Channel5
- Direction:      Peripheral to Memory
- PeriphAddr:     0x40013804  (USART1->DR)
- MemAddr:        &rx_buffer[0]
- BufferSize:     128
- PeriphDataSize: Byte
- MemDataSize:    Byte
- Mode:           Circular
- Priority:       High
- Interrupt:      Transfer Complete + Half Transfer

四、典型应用场景与常见误区

DMA的典型应用场景包括:高速串口通信中的连续收发、ADC多通道扫描采样、SPI/I2S音频数据流、摄像头图像采集、SD卡与内存之间的大块读写、以及网络数据包搬运。在这些场景中,DMA能够显著降低CPU中断频率,提高系统整体吞吐量。

常见误区:许多初学者认为“用了DMA就不需要中断”。实际上,DMA传输完成、半传输完成或出错时,仍需要通过中断通知CPU进行缓冲区切换、数据处理或错误恢复。DMA减少的是“每字节中断”,而不是“所有中断”。

另一个常见误区是忽略缓存一致性(Cache Coherency)。在带Cache的处理器中,DMA直接访问内存,可能绕过Cache,导致CPU读到旧数据或DMA写入的数据未及时同步。此时需要使用Cache清理(Clean)或无效化(Invalidate)操作,或使用非缓存内存区域。

复盘来看,掌握DMA基础概念的关键在于三点:第一,明确DMA是“控制器代替CPU搬运”的硬件机制;第二,理解请求线、通道、仲裁和完成中断构成的信号链;第三,根据数据量和实时性要求,在PIO与DMA之间做出合理选择。只有把这三层关系理清,后续学习dmaengine接口和环形缓冲区设计时才能有的放矢。