1. DMA 基础概念:什么是 DMA、DMA 与 CPU 的关系、DMA 的优势与适用场景
各位同学,咱们正式开始这门课之前,得先把地基打牢。DMA 这东西,说白了就是嵌入式系统里的「数据搬运工」。我见过不少新手,一上来就急着调定时器、配中断,结果数据传输把 CPU 累得半死,系统响应一塌糊涂。嗯,咱们今天就把 DMA 的底裤扒干净。
1.1 什么是 DMA?
DMA,全称 Direct Memory Access,直接存储器访问。它的核心能力就一句话:在不占用 CPU 的情况下,在内存和外设之间搬数据。
你想想看,没有 DMA 的时候,CPU 要干多少杂活?
- 从 ADC 寄存器读一个采样值
- 把数据写到内存缓冲区
- 再读下一个采样值
- 再写……
CPU 明明是来做核心运算的,结果变成了「数据搬运工」。这就像让一个顶级外科医生去端茶倒水,浪费啊。
DMA 的本质:一个独立于 CPU 的硬件模块,拥有自己的总线接口和地址发生器。它可以在系统总线上直接发起读写操作,不需要 CPU 一条一条指令去执行。
我个人习惯把 DMA 理解成一个「智能 DMA 控制器」。你给它三个参数:源地址、目标地址、传输长度,它就能自己把活干完,干完了再通知你一声。
1.2 DMA 与 CPU 的关系
这里有个关键点:DMA 不是替代 CPU,而是解放 CPU。
我画个图你就明白了:
看到没?CPU 和 DMA 都挂在系统总线上。但同一时刻,只能有一个主控设备占用总线。DMA 要传输数据时,会向总线仲裁器发起请求,仲裁器根据优先级决定谁先用总线。
我的经验:在 STM32 上,DMA 的优先级可以配置。我一般把高实时性的传输(比如 ADC 采样)设成高优先级,把后台数据搬运(比如日志输出)设成低优先级。这样既保证关键数据不丢,又不影响 CPU 的正常工作。
1.3 DMA 的优势
DMA 的好处,我用一个表格给你说清楚:
| 对比维度 | CPU 直接搬运 | DMA 搬运 |
|---|---|---|
| CPU 占用率 | 100% 被占用,无法处理其他任务 | 仅初始化时参与,传输过程零占用 |
| 传输速度 | 受限于指令执行速度,通常较慢 | 硬件直接操作总线,速度接近总线极限 |
| 功耗 | CPU 持续运行,功耗高 | CPU 可进入休眠模式,功耗大幅降低 |
| 实时性 | 受中断响应延迟影响 | 硬件触发,延迟极低且确定 |
| 代码复杂度 | 简单直观,但效率低 | 配置稍复杂,但一劳永逸 |
说白了,DMA 最大的优势就是让 CPU 从繁重的数据搬运中解脱出来。CPU 可以去做更重要的事,比如跑算法、处理协议栈、响应人机交互。
注意:DMA 不是万能的。如果传输的数据量很小(比如几个字节),DMA 的初始化开销可能比直接 CPU 搬运还大。我曾经在一个项目中,用 DMA 传输 4 个字节的 SPI 数据,结果发现配置 DMA 的时间比 CPU 直接搬还长……后来果断改回 CPU 搬运。
1.4 DMA 的适用场景
根据我多年的实战经验,以下场景特别适合用 DMA:
- 大数据块传输:比如从 ADC 连续采集 1024 个点,或者从 Flash 加载一张图片到 SRAM。
- 周期性数据传输:定时器触发 DMA,每隔固定时间搬运一次数据。比如音频播放、波形生成。
- 外设到外设传输:比如从 ADC 直接到定时器,或者从 USART 到 SPI,不需要经过内存中转。
- 低功耗场景:CPU 休眠时,DMA 可以继续工作。比如在待机模式下用 DMA 采集传感器数据。
- 高速通信接口:USART、SPI、I2C 等外设,配合 DMA 可以实现无 CPU 干预的全双工通信。
避坑指南:我曾经在一个项目中,用 DMA 做 USART 发送,结果发现数据发出去是乱的。查了半天,原来是 DMA 的地址递增配置错了——源地址设成了递增,但 USART 的数据寄存器地址是固定的。记住:外设寄存器地址通常不递增,内存缓冲区地址才需要递增。
1.5 什么时候不该用 DMA?
嗯,这里也得说清楚。DMA 不是银弹,以下情况我建议你慎重:
- 传输数据量极小(比如 1-8 字节):DMA 的配置开销可能超过直接搬运。
- 传输频率极低(比如几秒一次):CPU 完全有空闲处理,没必要引入 DMA 的复杂度。
- 需要实时修改数据:DMA 传输过程中,CPU 不能直接修改源数据,否则可能造成数据不一致。
- 资源紧张:每个 DMA 通道都是有限的硬件资源,别为了省事把通道全占满。