1. DMA 概述:为什么我们需要它?

1.1 DMA 是什么?

DMA,全称 Direct Memory Access,直接存储器访问。说白了,就是一种不需要 CPU 插手的数据搬运机制。

我刚开始接触嵌入式开发时,总觉得 CPU 才是老大,什么事情都得它亲自干。后来做视频采集卡的项目,发现 200 MHz 的 ARM 核全速运行也就勉强跟上 1080p 的帧率——CPU 根本没空处理业务逻辑了。那时候才明白:数据的终极敌人是 CPU 的“事必躬亲”。

DMA 的本质是:让硬件控制器直接接管内存外设之间的数据通道。CPU 只需要告诉 DMA 控制器:“从地址 A 搬 N 个字节到地址 B,搬完了通知我一声。”剩下的,不用管了。

1.2 DMA 的核心作用

我习惯把 DMA 的作用归纳为三点,你品品:

  • 解放 CPU:CPU 从 1 字节 1 字节的拷贝中解脱出来,去做真正需要它决策的事——比如跑算法、处理中断、管理任务。
  • 提升吞吐量:DMA 控制器通常独立于 CPU 核心,可以全速搬数据。我记得在 PCIe Gen3 x4 的项目里,DMA 跑满 3.9 GB/s 带宽时,CPU 占用率不到 5%。
  • 降低延迟:特别是对于周期性、批量数据传输,DMA 能保证确定性延迟,不会因为 CPU 调度抖动。
避坑经验:别以为 DMA 一定快。如果数据量很小(比如几十字节),启动 DMA 的开销(设置描述符、刷新缓存)反而比 CPU 直接拷贝还大。我曾经在一个 SPI 传感器项目中就踩了这个坑,后来改成了 PIO 模式才解决。

1.3 基本工作原理:谁动了我的数据?

DMA 的工作流程不复杂,你想象一下快递运输:

  1. 配置:CPU 设置 DMA 控制器的源地址、目的地址、传输长度、传输方向(内存→外设 / 外设→内存 / 内存→内存)。
  2. 启动:CPU 写一个控制位(比如 DMA 通道使能),DMA 开始工作。
  3. 搬运:DMA 控制器从源地址读取数据,写入目的地址;每完成一个单元(字节/字/突发),源地址和目的地址自动增减,计数器递减。
  4. 完成:当计数器归零,DMA 控制器向 CPU 发送中断(或者通过事件链触发其他 DMA 通道)。

举个例子,UART 接收:当 UART 收到一个字节,它会拉起一个 DMA 请求信号。DMA 控制器响应该请求,把 UART 接收寄存器的值写入内存缓冲区。整个过程 CPU 完全不知道——直到缓冲区满了 DMA 发出中断。

1.4 历史上的那些事儿

DMA 概念其实很早就有了。我记得第一个广泛使用的 DMA 控制器是 Intel 8237,1980 年代就在 PC/XT 上出现了。那会儿的 DMA 很简陋:只支持 8 位传输,最大寻址 16 MB,传输模式只有单字节和块传输。

90 年代 PCI 总线带来了总线主控 DMA,外设可以直接成为总线主设备发起传输,不再需要专门的 DMA 控制器。这算是 DMA 的一次革命。

如今,现代 SoC 里的 DMA 控制器已经很复杂:

  • 多个独立通道(16/32 路)
  • 支持链式描述符(硬件自动处理下一段传输)
  • 支持分散/聚集(Scatter-Gather)——把物理上不连续的内存块串起来传输
  • 支持数据宽度自动调整
  • 集成在高速接口内部(比如 PCIe DMA、USB DMA、Ethernet DMA)
我的观察:现代 DMA 的趋势是把控制逻辑从 CPU 进一步下放到硬件。比如 IOMMU(I/O 内存管理单元)允许 DMA 直接访问用户态虚拟地址,省去了驱动里的复杂拷贝。嗯,这个后面章节会细讲。

1.5 本章知识图谱

下图帮你梳理本章的核心逻辑:DMA 不是什么黑魔法,它就是一套配置→启动→搬运→完成的硬件机制。

DMA 整体知识结构 DMA 定义 解放 CPU 提升吞吐量 降低延迟 配置(源/目的/长度) 启动(使能 DMA) 搬运(自动增减地址) 完成(中断/事件链) Intel 8237 (1980s) PCI 总线主控 DMA (1990s) 链式描述符 / SG IOMMU / 虚拟地址 DMA

1.6 一个小表格:DMA vs CPU 搬运

很多人问我:既然 DMA 这么好,为什么有时候还是用 CPU 拷贝?我通常用这个对比表格说明:

场景 DMA 适合 CPU 适合
数据量 大块数据(≥ 1 KB) 小块数据(≤ 64 B)
传输频率 持续高速流 零星、突发
实时性要求 确定性延迟 允许 jitter
CPU 负载 极低 占用 CPU 100%
地址对齐 对对齐有要求(否则性能下降) 任意地址
注意:我见过不少工程师在项目初期就拍脑袋上 DMA,结果调试时发现 cache 一致性问题、描述符指针错误、触发时机不对——反而花了更多时间。建议:先用 CPU 搬运把功能跑通,再用 DMA 优化性能。别反着来。

好了,关于 DMA 的概述就先讲这么多。记住一句话:DMA 是高速接口的灵魂。后面章节我们会逐个深挖它在 PCIe、USB、Ethernet、DDR 等等场景下的具体玩法。