1. DMA 基础概念:CPU 的“数据搬运工”
各位同学,咱们今天正式开讲 DMA。说实话,我做了十几年嵌入式驱动,DMA 这玩意儿几乎天天打交道。你问它有多重要?这么说吧,没有 DMA 的嵌入式系统,就像让一个博士生天天去搬砖——不是不能干,是太浪费了。
1.1 什么是 DMA?
DMA,全称 Direct Memory Access,直接存储器访问。说白了,就是硬件层面专门负责数据搬运的一个独立模块。
我习惯这么跟新人解释:DMA 是一个硬件加速器,它可以在没有 CPU 参与的情况下,把数据从 A 点搬到 B 点。A 点和 B 点可以是内存、外设寄存器、或者内存和外设之间。
核心定义:DMA 是一种允许外设或内存之间直接传输数据的技术,传输过程由 DMA 控制器管理,CPU 只需在传输开始前配置参数,传输完成后接收中断。
你想想看,如果没有 DMA,每次外设有数据要处理,CPU 都得亲自去读寄存器、存内存。一次两次还行,如果数据量大了,比如音频采样、摄像头数据流,CPU 就彻底被绑死了。
1.2 DMA 与 CPU 数据搬运的区别
这个区别,我画个表格你就明白了。
| 对比维度 | CPU 直接搬运 | DMA 搬运 |
|---|---|---|
| 执行主体 | CPU 核心 | DMA 控制器(独立硬件) |
| CPU 占用 | 100% 占用,无法做其他事 | 仅配置和收尾时占用 |
| 传输速度 | 受限于 CPU 主频和指令执行 | 硬件级并行,通常更快 |
| 适用场景 | 小数据量、低频操作 | 大数据量、高频、实时流 |
| 编程复杂度 | 简单,直接读写寄存器 | 需要配置描述符、链表等 |
| 功耗 | 较高(CPU 全速运行) | 较低(专用硬件更高效) |
举个例子,我记得有一次做音频播放器项目,用 CPU 直接搬运 I2S 数据,结果系统一播放音乐,其他任务全部卡顿。换成 DMA 之后,CPU 占用从 80% 降到了 5%,效果立竿见影。
我的经验:判断是否该用 DMA,有个简单标准——如果数据传输量超过 64 字节,或者传输频率超过 1kHz,就值得考虑 DMA。低于这个阈值,CPU 直接搬反而更快,因为 DMA 配置本身也有开销。
1.3 DMA 在嵌入式系统中的作用
DMA 在嵌入式系统里,说白了就干三件事:
- 解放 CPU——让 CPU 从繁琐的数据搬运中解脱出来,去处理更重要的计算和控制逻辑。
- 提高吞吐量——DMA 可以背靠背传输,一个时钟搬一个数据,效率远高于 CPU 的取指-译码-执行流水线。
- 降低延迟——特别是对实时性要求高的场景,比如音频、视频、高速 ADC 采样。
我给大家画个图,看看 DMA 在整个系统中的位置。
从图上你能看到,DMA 控制器和 CPU、内存、外设都挂在系统总线上。但关键区别在于:DMA 可以绕过 CPU,直接在内存和外设之间建立数据传输通道。这就是它名字里 "Direct"(直接)的由来。
1.4 什么时候必须用 DMA?
我遇到过不少新手问:是不是所有项目都要上 DMA?当然不是。我总结了几种非用不可的场景:
- 高速数据流:比如摄像头 OV5640 输出 1080p 视频,每秒几十 MB 的数据量,CPU 根本扛不住。
- 实时音频:I2S 接口播放音乐,数据必须连续不间断,稍有延迟就是爆音。
- 多通道同步采集:比如 8 通道 ADC 同时采样,DMA 可以乒乓缓冲,一个缓冲区在传输,另一个在填充。
- 低功耗场景:CPU 可以进入睡眠模式,DMA 自己干活,完事了再唤醒 CPU。
避坑指南:我曾经在一个项目里,为了省事,用 CPU 轮询方式读取高速 SPI Flash。结果 CPU 占用率飙到 90%,系统 watchdog 频繁超时复位。后来改成 DMA + 中断,CPU 占用降到 10%,问题全解决了。记住:DMA 不是锦上添花,而是雪中送炭。
1.5 DMA 传输的基本流程
虽然不同芯片的 DMA 控制器实现有差异,但基本流程大同小异。我习惯把它分成五步:
- 请求:外设(或软件)发出 DMA 传输请求。
- 仲裁:如果多个 DMA 通道同时请求,仲裁器决定优先级。
- 传输:DMA 控制器从源地址读取数据,写入目的地址。
- 计数:每传输一次,计数器减一,直到完成设定的传输次数。
- 完成:传输结束,DMA 控制器发出中断通知 CPU。
嗯,这里要注意:DMA 传输的单位可以是字节、半字(16位)或字(32位),具体取决于你的配置。我一般建议优先使用字传输,效率最高。
1.6 本章小结
DMA 说白了就是一个硬件数据搬运工。它的核心价值在于:让 CPU 做 CPU 该做的事,让 DMA 做 DMA 该做的事。两者各司其职,系统性能才能最大化。