DMA 基础概念:为什么你的 CPU 不该干搬运的活

做嵌入式开发这些年,我见过太多工程师把 CPU 当苦力使。数据从外设搬到内存,又从内存搬到外设,CPU 忙得团团转,真正该做的算法运算反而没时间搞。说白了,这就是没用好 DMA。

DMA 全称 Direct Memory Access,直接存储器访问。名字挺绕口,但本质很简单——它是个专门干数据搬运的硬件模块。CPU 把搬运任务交代给它,就能腾出手干正事了。

核心观点:DMA 不是魔法,它只是把 CPU 从「数据搬运工」的角色解放出来,让 CPU 回归「计算决策者」的本职。

1.1 什么是 DMA?一个硬件搬运工

DMA 是芯片内部的一个独立硬件模块。它有自己的总线接口,能直接访问存储器和外设寄存器。你给它配好源地址、目标地址、传输长度,它就能自己把数据搬完,搬完了再通知 CPU 一声。

我习惯把 DMA 比作工厂里的自动叉车。CPU 是厂长,负责下指令、做决策。如果没有叉车,厂长就得亲自搬货,效率可想而知。有了 DMA 这个自动叉车,厂长只要说「把 A 仓库的货搬到 B 车间」,叉车自己就干完了。

DMA 的典型工作流程:

  1. CPU 配置 DMA 控制器:设置源地址、目标地址、传输长度、传输模式
  2. DMA 启动传输:CPU 写一个启动位,DMA 开始干活
  3. DMA 搬运数据:DMA 通过总线读取源数据,写入目标地址,不需要 CPU 参与
  4. 传输完成中断:DMA 发中断通知 CPU「活干完了」

我的经验:刚开始用 DMA 时,我总忍不住在启动 DMA 后轮询它的完成标志。后来发现这完全多余——DMA 自己会处理好一切,你只管等中断就行。轮询反而浪费了 DMA 的优势。

1.2 DMA 与 CPU 数据搬运:天壤之别

很多人觉得「CPU 也能搬数据啊,为什么非要用 DMA?」。嗯,这里面的差别大了去了。我整理了一个对比表,你看完就明白了。

对比维度 CPU 搬运 DMA 搬运
执行方式 逐条指令执行,每搬一个字节都要取指、译码、执行 硬件自动完成,一个时钟周期搬一个数据单元
CPU 占用 100% 占用 CPU,CPU 无法做其他事 仅配置和完成中断时占用 CPU,传输过程 CPU 可做其他事
传输速度 受限于指令执行速度,通常几十 MB/s 接近总线带宽,可达几百 MB/s 甚至更高
功耗 CPU 全速运行,功耗高 DMA 模块功耗远低于 CPU,适合低功耗场景
实时性 受中断和任务调度影响,延迟不确定 硬件级传输,延迟可预测
适用场景 小数据量、非频繁传输 大数据块、周期性传输、高速外设

你想想看,如果 CPU 每接收一个字节都要跑一趟中断服务程序,那系统还能干别的吗?我曾经在一个音频项目里,用 CPU 轮询方式读取 I2S 数据,结果 CPU 负载飙到 90% 以上,系统几乎卡死。换成 DMA 后,CPU 负载直接降到 15%,音频处理算法也能流畅跑了。

避坑指南:我曾经在一个项目中,为了省事直接用 CPU 搬运 SPI Flash 的数据。结果发现 CPU 被完全占死,按键响应延迟超过 200ms。后来改成 DMA 传输,CPU 负载从 85% 降到 12%,问题迎刃而解。记住:凡是涉及大数据块传输的场景,优先考虑 DMA。

1.3 DMA 在嵌入式系统中的角色

DMA 在嵌入式系统里扮演什么角色?我总结了三个核心定位:

  • 性能加速器:让 CPU 从数据搬运中解脱,专注于计算和控制
  • 实时性保障:硬件级传输保证确定性的延迟,适合音频、视频等实时场景
  • 功耗优化器:DMA 模块功耗远低于 CPU,在低功耗 IoT 设备中至关重要

具体到实际应用,DMA 最常见的场景包括:

  • 外设数据采集:ADC 采样数据通过 DMA 直接存入内存缓冲区
  • 显示刷新:LCD 显存数据通过 DMA 传输到显示控制器
  • 通信协议:UART、SPI、I2C 等接口的数据收发
  • 存储器操作:内存拷贝、Flash 读写、SRAM 间数据传输
  • 多媒体处理:音频播放、视频采集的数据流传输

我的建议:新手入门 DMA,先从「外设到内存」的单次传输开始练手。比如用 DMA 把 ADC 的采样结果自动存到一个数组里。这个模式最简单,也最容易验证效果。等熟悉了再尝试「内存到内存」和「循环模式」。

1.4 DMA 传输的核心流程

为了让你更直观地理解 DMA 的工作机制,我画了一张流程图。这张图展示了从 CPU 配置到传输完成的完整链路。

DMA 传输核心流程图 DMA 传输核心流程 CPU 配置 DMA 控制器 源地址 | 目标地址 | 传输长度 传输模式 | 触发源 CPU 写启动位 DMA 自动搬运数据(CPU 可做其他事) 总线读取 → 总线写入 → 地址递增 → 计数递减 DMA 发送完成中断 整个传输过程 CPU 只需参与配置和中断处理,数据搬运完全由 DMA 硬件完成

这张图把 DMA 传输拆成了五个关键步骤。你仔细看第三步到第四步之间——CPU 写完启动位后,就可以去干别的事了。DMA 自己完成总线读写、地址递增、计数递减这些琐碎工作。这就是 DMA 的精髓所在。

1.5 什么时候该用 DMA?

不是所有场景都需要 DMA。我总结了一个简单的判断标准:

  • 数据量 > 100 字节:用 DMA 收益明显
  • 传输频率 > 1 kHz:用 DMA 避免频繁中断
  • CPU 负载 > 30%:考虑用 DMA 分担
  • 实时性要求高:DMA 的确定性延迟更可靠

反过来,如果只是偶尔传几个字节,或者传输频率很低,用 CPU 直接操作反而更简单。没必要为了用 DMA 而用 DMA。

一句话总结:DMA 是嵌入式系统性能调优的第一把钥匙。用好它,你的 CPU 就能从「搬运工」变成「指挥官」。接下来的章节,我会带你深入 DMA 的配置细节和实战技巧。