1. DMA 基础概念:它凭什么解放 CPU?
各位同学,咱们今天聊 DMA。很多初学者觉得 DMA 是个玄学——不就是搬数据吗?CPU 自己搬不就行了?
嗯,我刚开始做嵌入式时也这么想。直到有一次做高速数据采集,CPU 被中断淹没了,系统直接卡死。从那以后,我才真正理解了 DMA 的价值。
1.1 DMA 工作原理:一个“硬件搬运工”
DMA,全称 Direct Memory Access,直接存储器访问。说白了,它是一个专门负责数据搬运的硬件模块。
CPU 就像公司的 CEO,负责决策和运算。DMA 就像快递小哥,只管把数据从 A 点搬到 B 点。CEO 不需要亲自搬货,对吧?
DMA 的工作流程其实很简单:
- CPU 配置 DMA:告诉它“从哪搬、搬到哪、搬多少”
- DMA 发起传输:直接控制总线,开始搬数据
- 传输完成触发中断:DMA 通知 CPU “活干完了”
- CPU 处理结果:CPU 只需要在最后收尾
核心要点:DMA 传输过程中,CPU 可以干别的事。这才是真正的并行工作。
1.2 DMA vs CPU:谁更适合搬数据?
我经常被问到:“DMA 和 CPU 搬数据,到底差在哪?” 咱们直接看对比:
| 对比项 | CPU 搬运 | DMA 搬运 |
|---|---|---|
| 执行方式 | 逐字节/逐字搬运,占用内核 | 硬件自动搬运,不占内核 |
| CPU 占用率 | 100%(搬运期间啥也干不了) | 仅配置和中断时占用(通常 <1%) |
| 传输速度 | 受限于 CPU 主频和指令周期 | 接近总线极限速度 |
| 适用场景 | 小数据量(几十字节以内) | 大数据量(几百字节以上) |
| 代码复杂度 | 简单,直接写循环 | 需要配置寄存器,稍复杂 |
| 功耗 | 高(CPU 全速运行) | 低(CPU 可以休眠) |
举个例子。你想想看,如果 SPI 屏幕刷新一帧 320×240 的图像,用 CPU 逐像素搬运,CPU 得忙活好几毫秒。这期间中断来了怎么办?任务调度怎么办?
用 DMA 的话,CPU 只需要配置好源地址、目的地址和长度,然后就可以去处理其他任务,或者干脆进入休眠模式省电。DMA 搬完数据后,通过中断告诉 CPU:“搞定了,你来收尾吧。”
我的经验:在低功耗项目中,我习惯把所有的数据搬运都交给 DMA。这样 CPU 可以在大部分时间处于睡眠状态,系统功耗能降低 30%-50%。
1.3 DMA 传输三大要素:源地址、目的地址、传输长度
DMA 传输的核心,其实就是三个参数。记住这三个,你就掌握了 DMA 的精髓。
1.3.1 源地址(Source Address)
数据从哪来。可以是:
- 外设数据寄存器:比如 UART 的 DR 寄存器、ADC 的数据寄存器
- 内存缓冲区:比如一个数组或者 malloc 出来的内存块
- 另一个外设:某些芯片支持外设到外设的 DMA 传输
1.3.2 目的地址(Destination Address)
数据搬到哪。常见的有:
- 内存缓冲区:接收数据时,从外设搬到内存
- 外设数据寄存器:发送数据时,从内存搬到外设
- 另一个外设:比如从 SPI 直接搬到 DAC
1.3.3 传输长度(Transfer Length)
搬多少数据。单位可以是字节、半字(16位)或字(32位)。
避坑指南:我曾经在一个项目中,DMA 传输长度配置错了单位。我以为是字节数,结果配置的是字数。导致数据只搬了四分之一,系统跑飞了。排查了整整两天才找到问题。所以,一定要仔细看芯片手册,确认传输长度的单位。
1.4 DMA 传输模式:不止一种玩法
DMA 不是只能“搬一次就完事”。根据需求,有几种常见模式:
| 模式 | 说明 | 典型应用 |
|---|---|---|
| 单次传输 | 搬完指定长度就停止 | 一次性数据读取 |
| 循环传输 | 搬完后自动从头开始 | 音频播放、ADC 连续采样 |
| 触发传输 | 每次由外设触发搬一个单位 | UART 逐字节收发 |
| 突发传输 | 一次触发搬多个单位 | 高速数据传输 |
我个人最常用的是循环传输模式。比如做音频播放时,DMA 循环从内存缓冲区搬数据到 DAC,CPU 只需要在缓冲区快空时补充数据就行。CPU 大部分时间都在睡大觉,功耗自然就低了。
1.5 DMA 传输流程:一张图看懂
下面这张图展示了 DMA 的完整工作流程。我建议你仔细看看,理解每个环节的交互关系。
从这张图你能看到,DMA 传输的核心流程就是:CPU 配置 → DMA 搬运 → DMA 通知。CPU 只在第一步和最后一步参与,中间的数据搬运完全由 DMA 独立完成。
1.6 什么时候该用 DMA?
不是所有场景都适合用 DMA。我总结了几条经验:
- 数据量大:超过 100 字节,建议用 DMA
- 数据频繁:比如 ADC 以 1kHz 采样,每秒 1000 次中断,CPU 受不了
- 需要低功耗:CPU 想睡觉,让 DMA 干活
- 实时性要求高:DMA 传输不依赖 CPU 响应中断,延迟更稳定
小技巧:我习惯在项目初期就把所有外设的数据传输都设计成 DMA 方式。即使暂时用不到,预留 DMA 通道也比后期改设计容易得多。
1.7 本章小结
DMA 的本质,就是一个硬件数据搬运工。它解放了 CPU,让 CPU 能专注于更重要的计算和决策。三大要素——源地址、目的地址、传输长度——是配置 DMA 的核心。理解这些,你就迈出了 DMA 学习的第一步。