1. DMA 基础概念
1.1 DMA 的定义
DMA(Direct Memory Access,直接存储器访问) 是一种允许硬件设备(如磁盘控制器、网卡、声卡、图形加速器、摄像头接口等)在 不经过 CPU 参与 的情况下,直接与系统内存进行批量数据传输的硬件机制。DMA 控制器(DMAC)作为系统总线上的独立主控设备,接管总线控制权,完成从源地址到目的地址的数据搬运,搬运完成后通过中断通知 CPU。
核心要点: DMA 的本质是“硬件搬运工”——CPU 只需告诉 DMA 控制器“从哪里搬、搬到哪里、搬多少”,然后 DMA 控制器自动完成传输,CPU 可以并行执行其他任务。
1.2 DMA 与 CPU 数据传输的区别
传统的数据传输方式(PIO,Programmed I/O)由 CPU 逐字或逐字节地从外设读取数据到寄存器,再写入内存。DMA 方式则将这一过程完全卸载给专用硬件。下表从多个维度对比两种方式:
| 对比维度 | PIO(CPU 直接传输) | DMA(直接存储器访问) |
|---|---|---|
| CPU 参与程度 | 全程参与,逐字搬运 | 仅初始化配置,传输过程不参与 |
| 总线占用 | CPU 持续占用系统总线 | DMA 控制器占用总线,CPU 可访问 Cache 或执行非内存密集型指令 |
| 传输速率 | 受限于 CPU 时钟和指令吞吐量 | 接近内存/外设接口的硬件极限带宽 |
| CPU 利用率 | 传输期间 CPU 100% 被占用 | CPU 利用率接近 0%(传输期间) |
| 适用数据量 | 小数据量(< 64 字节) | 大数据量(≥ 64 字节,典型为 KB/MB 级) |
| 实时性影响 | 阻塞 CPU,影响中断响应 | 不阻塞 CPU,中断仅在传输完成时触发 |
| 硬件复杂度 | 无需额外硬件 | 需要 DMA 控制器、描述符表、中断控制器配合 |
经验法则: 在嵌入式 Linux 驱动开发中,对于每次传输超过 64 字节的外设(如 SPI 帧、I2C 批量数据、UART 大包、MMC 块数据),几乎总是应该使用 DMA 而非 PIO。PIO 仅适合寄存器级别的状态查询或极短的控制帧。
1.3 DMA 传输的优势
DMA 传输带来的核心优势可以归纳为以下四点:
- CPU 卸载(Offloading): CPU 从繁重的数据搬运中解放出来,可以执行协议栈处理、任务调度、算法计算等更有价值的工作。
- 高吞吐量(High Throughput): DMA 控制器通常以硬件状态机运行,能够以总线时钟频率连续传输,消除 CPU 取指、译码、执行的开销。
- 低延迟(Low Latency): 对于批量传输,DMA 的启动延迟(通常几十个总线周期)远低于 CPU 逐字搬运的累积延迟。
- 功耗优化(Power Efficiency): CPU 在 DMA 传输期间可以进入低功耗状态(如 WFI/WFE),显著降低系统功耗,这对电池供电的嵌入式设备至关重要。
1.4 典型应用场景
DMA 在嵌入式 Linux 系统中无处不在,以下是几个最典型的应用场景:
- 存储子系统: eMMC/SD 卡/NAND Flash 控制器使用 DMA 搬运块数据(512B ~ 4KB 每块),避免 CPU 逐块拷贝。
- 网络子系统: 以太网 MAC 控制器通过 DMA 将接收到的网络帧直接送入内存 Ring Buffer,CPU 只处理协议解析。
- 多媒体处理: 摄像头传感器通过 DMA 将图像帧(如 1080p YUV 数据,每帧约 3 MB)直接传输到显存或系统内存。
- 音频子系统: I2S 控制器使用 DMA 循环搬运音频样本,实现低延迟的播放/录音。
- 高速串行接口: SPI、UART、I2C 在高速模式(SPI 时钟 > 10 MHz)下依赖 DMA 避免 FIFO 溢出。
1.5 DMA 系统架构图
下图展示了一个典型的嵌入式 SoC 中 DMA 控制器与 CPU、内存、外设之间的连接关系:
1.6 DMA 传输的基本流程
一个典型的 DMA 传输过程包含以下步骤,可以用一个简洁的流程图表示:
常见误区: 初学者常误以为 DMA 传输“不需要 CPU”。实际上,DMA 传输的 初始化阶段 必须由 CPU 完成——CPU 需要设置源地址、目的地址、传输长度、传输方向(内存→外设 或 外设→内存)以及触发方式。传输完成后,CPU 还需要在中断处理函数中检查状态并启动下一轮传输(对于循环 DMA 模式则无需重启)。