DMA 基础:CPU 的数据搬运工

大家好,我是你们的讲师。咱们搞嵌入式或驱动开发的,绕不开 DMA 这个词。说白了,它就是帮 CPU 搬数据的。

我自己刚接触嵌入式开发时,觉得 DMA 这东西挺神秘。后来被一个高速数据采集项目逼得不得不搞懂它,才发现原理其实很直白。这一章咱们就把它聊透。

1.1 什么是 DMA

DMA,全称 Direct Memory Access,直接存储器访问。别被这名字唬住,你就记住一点:它是一个不需要 CPU 干预就能在内存和外设之间搬运数据的硬件模块。

没有 DMA 时,数据搬运靠 CPU 一条指令一条指令地执行,这叫 PIO(Programmed I/O)模式。有 DMA 后,CPU 只负责说一声“开始搬”,剩下的累活全交给 DMA 控制器。

核心区别一句话: PIO 是 CPU 亲自搬砖,DMA 是 CPU 当包工头。

我记得有一次做一个摄像头图像采集,数据量大概每秒几十兆字节。用 PIO 模式跑,CPU 占用率直接冲到 95% 以上,系统几乎卡死。换成 DMA 后,CPU 占用率掉到个位数,这才算把项目救回来。

1.2 DMA vs PIO:谁更省 CPU?

咱们把这两种方式的关键差异掰开来看。

对比项 PIO 模式 DMA 模式
CPU 参与度 全程参与 仅启动和结束时介入
数据吞吐量 受 CPU 主频限制 接近总线带宽
CPU 负载 极高,80%~100% 很低,通常低于 5%
实现复杂度 简单,裸机都能写 需要初始化 DMA 通道
应用场景 少量数据、低频率 大数据块、高频率

为什么 PIO 这么费 CPU?你想想看,CPU 每搬一个字节,就要取指令、解码、执行、写回。整个过程陷入到数据搬运里,根本没空干别的。而 DMA 呢?它自己有一套地址寄存器和计数器,能边搬边数,搬完了发个中断告诉 CPU “活干完了”。

避坑提醒: PIO 并非一无是处。我曾经在调试一个 SPI 温度传感器时,数据量只有几十个字节,用 DMA 反而因为初始化开销导致延迟变高。这种情况用 PIO 更划算。

1.3 DMA 工作原理:三步走

DMA 的工作流程其实就三件事:请求→传输→完成。我习惯把它拆成下面几步来理解。

  1. CPU 配置 DMA 控制器: 告诉它源地址在哪、目标地址在哪、要搬多少字节、用哪个外设触发。
  2. 外设发起 DMA 请求: 比如串口收到一个字节,它会向 DMA 控制器发请求信号。DMA 控制器拿到总线控制权,执行一次或多次传输。
  3. 传输完成产生中断: DMA 计数器减到 0,它产生一个中断给 CPU。CPU 就知道数据已经到位了。

这里面有个关键点:DMA 传输期间,CPU 基本上可以睡大觉或者做其他计算。因为它俩分时复用系统总线——要么 CPU 用,要么 DMA 用。不过现在很多芯片的总线架构支持并行操作,CPU 访问 Cache 时 DMA 可以同时访问主存,效率更高了。

经验之谈: 配置 DMA 时务必检查源地址和目标地址是否对齐。如果地址没按字对齐,某些 DMA 控制器会工作异常。我曾在 STM32 上踩过这个坑,折腾了两天才发现是地址对齐的问题。

1.4 DMA 的触发机制

DMA 不是随便什么时候都动,它需要被触发。触发方式主要有两种。

  • 硬件触发: 外设发出 DMA 请求信号。例如定时器溢出、ADC 转换完成、UART 收到数据。这种最常见,适合实时性要求高的场景。
  • 软件触发: CPU 写一个寄存器位来启动 DMA。适合内存到内存的拷贝,比如把一张图片从临时缓存搬到显存。

我的做法是:外设数据流固定且连续时,用硬件触发;数据块需要按条件搬运时,用软件触发。

1.5 DMA 的传输模式

不同的 DMA 控制器支持的模式不太一样,但核心就三种。

模式 描述 典型场景
单次传输 每次 DMA 请求只搬一个数据单元 低速外设,如按键扫描
块传输 一次请求搬完整个数据块 高速数据采集,如音频录音
循环传输 传输完自动重载计数器,循环不停 实时数据流,如麦克风输入

我个人最常用循环传输。比如在做一个音频回放项目时,DMA 源源不断把音频数据往 DAC 里送,CPU 只管维护一个缓冲区队列。DMA 自己在那循环搬,CPU 一点不操心。

1.6 DMA 传输流程图

这张图把整个 DMA 传输过程串起来了。

DMA 传输全流程 CPU 配置 DMA 控制器 设置源/目标地址、字节数 外设发出 DMA 请求 DMA 控制器接管总线 CPU 暂停访问主存或继续执行 执行数据传输 外设 ↔ 存储器 DMA 中断通知 CPU

嗯,这里要注意一个细节:DMA 中断服务程序里要尽快清除中断标志位,别在里面做太多逻辑判断。我见过有人把数据处理也放在 DMA 中断里,直接导致后续传输延迟。

1.7 本章小结

DMA 说白了就一句话:让硬件干硬件的活,CPU 干 CPU 的活。它的价值不在于功能本身,而在于解放了 CPU。你掌握了 DMA,就等于有了让系统性能翻倍的能力。

记住这三点:
1. DMA 是硬件搬运工,CPU 只负责下达命令。
2. 大数据量场景用 DMA,小数据量用 PIO。
3. 配置时注意地址对齐和中断服务程序的简洁。