一、DMA 基础概念:搬数据这件事,真的需要 CPU 亲力亲为吗?

大家好,欢迎来到这门课。我是老张,干了十来年嵌入式底层开发。

今天咱们聊点最基础的——DMA。你可能觉得这个概念太简单了,但说实话,很多项目出问题,恰恰是在“基础”上栽了跟头。

DMA 全称 Direct Memory Access,直接存储器访问。说白了,就是 CPU 把“数据搬运”的苦力活,外包给一个专门干这个的硬件小弟。

1.1 为什么需要 DMA?

你想想看,传统的数据传输是啥样的?

  • CPU 轮询:CPU 不断查外设寄存器,看数据准备好了没。这期间 CPU 什么事都干不了,纯属空转。
  • 中断传输:每来一个数据,CPU 就停下手头的工作,跑去执行中断服务函数。数据量大时,CPU 绝大多数时间都在“响应中断-保存现场-恢复现场”的路上。

我早期做一个小型数据记录仪项目,ADC 采样率才 100kHz,结果 CPU 被中断占用了 90% 以上的处理时间,主循环几乎跑不动。那会我就意识到——CPU 不适合干频繁的、简单的数据搬运。

DMA 的核心价值: 让 CPU 专注于计算和控制,把枯燥的数据复制、外设→内存、内存→外设这类操作,交给 DMA 控制器并行完成。

1.2 DMA 工作模式

DMA 不是什么新鲜东西。但不同模式差别很大,我把它整理成一张表,方便你对照着看:

模式名称 核心特征 典型场景
单次传输 一次请求,搬运 N 个数据,完成后停止 一次性数据块拷贝,比如保存一帧图像
循环传输 搬运完一轮,自动从头再开始 连续 ADC 采样,数据不断覆盖回环缓冲
乒乓传输 两个缓冲区交替使用:一个被 DMA 写,一个被 CPU 读 高频率、无丢数的连续采样,正是本课核心

这里我提个醒:循环传输看起来省事,但如果你只用一个缓冲区,CPU 和 DMA 同时访问同一块内存,会产生“竞争”。处理器来不及读,数据就被新的覆盖了——丢数据,坑深着呢。

我曾经踩过的坑: 一个用循环 DMA 做音频采集的项目。采样率 48kHz,看起来不高。但我没做双缓冲,主循环里处理一帧数据时,DMA 已经把后续的两帧写进去了。
结果:回放时“咔咔”爆音。后来换了乒乓 DMA,问题立刻消失。
核心教训: 只要 CPU 处理时间>单缓冲区填充时间,就必须上乒乓。

1.3 DMA 传输的基本流程

为了帮你理清整体脉络,我画了一张核心逻辑图。这张图里,你能看到三种典型 DMA 工作模式的区别:

DMA 三种工作模式核心逻辑 单次传输 外设触发 → DMA 搬运 → 搬运N个字节 → 自动停止 → CPU取数据 适用:一次一帧 循环传输 外设触发 → DMA 搬运 → 到达末尾 → 回卷 → 继续从头搬运 → 永远不停 适用:连续采样 乒乓传输 缓冲区A → DMA写入 缓冲区B → CPU读取 ↓ 切换! 缓冲区B → DMA写入 缓冲区A → CPU读取 两个角色交替进行 适用:高可靠连续采样 ⚡ 核心关注点 乒乓传输消除“生产者-消费者”竞争,保证CPU读到完整且连续的数据块

看到没?乒乓传输的本质就是“双缓冲轮流切换”。DMA 往其中一个缓冲写数据时,CPU 去另一个缓冲取数据。两者各玩各的,互不干扰。

1.4 DMA 术语速查

刚接触 DMA 的朋友,容易被几个词绕晕。我帮你筛出最常用的:

  • DMA 请求:外设发出的信号,告诉 DMA 控制器“我有数据要搬”。
  • DMA 应答:DMA 控制器响应请求,开始接管总线。
  • 总线仲裁:DMA 和 CPU 同时想用总线时,由仲裁器决定谁先用。通常是 DMA 优先级高于 CPU。
  • 数据宽度:一次搬运多少个字节?8位、16位还是32位?这影响吞吐量。
  • 传输完成中断:DMA 搬完设定数量的数据后,可以触发一个中断通知 CPU。

我建议: 在配置 DMA 时,养成先检查“外设地址”和“内存地址”是否对齐的习惯。比如源地址是 32 位对齐的,但目标地址是 8 位对齐,某些 DMA 控制器会报错或降低效率。

1.5 本章小结:你该带走什么?

回到最开始的问题:为什么要搞 DMA?说白了,就是“解放 CPU”。而乒乓 DMA,是在解放的基础上,加了“防冲突”的双保险。

  1. DMA 不是万能的——它只解决“数据搬运”,不处理数据。
  2. 单次、循环、乒乓——三者的复杂度和可靠性依次递增。
  3. 乒乓传输——用两个缓冲区实现了“时间和空间的错峰”,是高采样率场景的基石。

后面我会带你深挖乒乓 DMA 的配置细节、中断设计、以及如何评估系统能不能扛住目标采样率。今天先把基础夯实在。