DMA 基础概念:这东西到底怎么工作的?

说起 DMA,很多人第一反应是「哦,就是那个不用 CPU 参与的数据搬运工具」。这话对,但不够。DMA 全称 Direct Memory Access,直接存储器访问。说白了,它就是一个硬件协处理器,专门负责在内存和外设之间搬数据。

我刚开始做嵌入式那会儿,总觉得 DMA 是个锦上添花的东西。后来发现,没有它,很多系统根本跑不起来。你想想看,一个千兆网卡,每秒要处理上百万个数据包,全让 CPU 去搬,CPU 还干不干别的了?

DMA 的工作原理:谁在干活?

DMA 的核心是一个叫做 DMA 控制器 (DMAC) 的硬件模块。它有自己的地址寄存器、字节计数寄存器和控制寄存器。

一次典型的 DMA 传输流程是这样:

  1. 外设发请求:比如 UART 收到一个字节,向 DMA 控制器发出 DMA 请求信号。
  2. DMA 仲裁:如果总线上没有更高优先级的任务,DMA 控制器接管总线控制权。
  3. 传输数据:DMA 直接从源地址读数据,写到目的地址。
  4. 计数递减:每传输一个单元,字节计数器减 1。
  5. 传输完成:计数器减到 0,DMA 发送中断给 CPU,通知传输结束。

嗯,这里要注意——在整个传输过程中,CPU 是被 旁路 的。数据根本不经过 CPU,直接从外设到内存,或者内存到外设。

我遇到过有人问:「DMA 传输的时候 CPU 在干嘛?」答案是:CPU 可以继续执行其他指令,除非发生总线争用。

关键点:DMA 传输的本质是「数据直接在源和目的之间流通,CPU 只负责发起和结束时的处理」。

DMA vs CPU 传输:差距有多大?

我们拿一个实际的场景来对比。假设你要从 UART 接收 1024 字节数据。

对比项 CPU 逐字节搬运 DMA 搬运
每字节传输 CPU 读取外设寄存器 → CPU 写入内存 DMA 硬件直接搬运
CPU 占用 100%,全程陷入中断 仅开始时初始化 + 结束时处理中断
传输速度 受限于 CPU 指令执行速度 接近内存带宽上限
延迟抖动 受其他中断影响大 硬件固定延迟,确定性高
适用场景 小数据量、非实时 大数据量、高实时性

我做个项目时,直接把一个 UART 驱动的接收从 PIO 模式(CPU 逐字节搬)改成 DMA 模式。你猜怎么着?同样的波特率,CPU 占用从 35% 降到了不到 2%。这就是 DMA 的威力——说白了,它解放了 CPU,让它去干更值钱的事。

注意:DMA 并不是万能的。对于一次传输只有几个字节的小数据量,DMA 初始化的开销可能比直接 CPU 传输还大。我建议:传输量小于 32 字节的场景,用 CPU 直传反而更高效。

DMA 分类:不同场景选不同家伙

DMA 控制器不是只有一种。根据设计架构,我习惯把它们分为三类:

  1. 块 DMA (Block DMA):一次性申请总线,传输完整个数据块才释放。吞吐率高,但总线占用时间长,可能影响其他外设。
  2. 周期窃取 DMA (Cycle Stealing DMA):窃取一个总线周期传输一个数据单元,然后释放总线。适合慢速外设,对系统干扰小。
  3. 透明 DMA (Transparent DMA):只在 CPU 不使用总线的时候才传输。对 CPU 完全透明,但实现复杂,速度慢。

从功能角度看,还有两个重要的分类维度:

  • 按通道数:单通道 vs 多通道。多通道可以同时为多个外设服务,但需要仲裁。
  • 按传输宽度:字节、半字、字、甚至突发传输。选择取决于外设和存储器的位宽。
  • 按寻址模式:固定地址(比如外设寄存器)vs 递增地址(比如内存 buffer)。

我记得有次调试一个音频驱动,播放时总是有咔哒声。查了半天,发现是 DMA 配置成了块模式,传输期间抢占了显卡的总线。换成周期窃取模式,问题就解决了。你说这个分类重不重要?

我的经验:做嵌入式 Linux 驱动时,别默认用块 DMA。我习惯先用周期窃取测试,确认没问题再考虑换块 DMA 追求极致吞吐率。

一张图看懂 DMA 体系

下面这张图总结了 DMA 的核心概念和工作关系:

DMA 核心工作逻辑 CPU 发起&结束处理 DMA 控制器 地址/计数/控制 内存 源/目的 buffer 外设 UART/SPI/以太网 总线仲裁 优先级管理 配置寄存器 DMA 读/写 DMA 请求/响应 数据流(不经过CPU) 请求总线 CPU 也可向仲裁请求总线 传输完成中断 图释说明 蓝色 ⬤ CPU:只做初始化与完成处理,不参与数据搬运 红色 ⬤ DMA 控制器:核心搬运引擎,拥有地址/计数寄存器 绿色/黄色 ⬤ 内存/外设:数据源与目的地,通过 DMA 直连

核心理解:DMA 不是一个简单的「搬运工」,它是一个拥有总线控制权的子系统。理解它的工作流程和分类,是后续排查延迟瓶颈和提升吞吐率的基础。