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。

我画个图你就明白了:

DMA 与 CPU 的分工协作关系 CPU 核心运算 / 控制逻辑 DMA 控制器 数据搬运 / 地址生成 总线仲裁器 分配总线使用权 内存 (SRAM / Flash) 数据缓冲区 / 代码区 外设 (USART / ADC / SPI) 数据寄存器 / FIFO 系统总线 (AHB / APB) 关键点 • CPU 和 DMA 共享总线 • 同一时刻只能一个主控 • DMA 传输时 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:

  1. 大数据块传输:比如从 ADC 连续采集 1024 个点,或者从 Flash 加载一张图片到 SRAM。
  2. 周期性数据传输:定时器触发 DMA,每隔固定时间搬运一次数据。比如音频播放、波形生成。
  3. 外设到外设传输:比如从 ADC 直接到定时器,或者从 USART 到 SPI,不需要经过内存中转。
  4. 低功耗场景:CPU 休眠时,DMA 可以继续工作。比如在待机模式下用 DMA 采集传感器数据。
  5. 高速通信接口:USART、SPI、I2C 等外设,配合 DMA 可以实现无 CPU 干预的全双工通信。

避坑指南:我曾经在一个项目中,用 DMA 做 USART 发送,结果发现数据发出去是乱的。查了半天,原来是 DMA 的地址递增配置错了——源地址设成了递增,但 USART 的数据寄存器地址是固定的。记住:外设寄存器地址通常不递增,内存缓冲区地址才需要递增。

1.5 什么时候不该用 DMA?

嗯,这里也得说清楚。DMA 不是银弹,以下情况我建议你慎重:

  • 传输数据量极小(比如 1-8 字节):DMA 的配置开销可能超过直接搬运。
  • 传输频率极低(比如几秒一次):CPU 完全有空闲处理,没必要引入 DMA 的复杂度。
  • 需要实时修改数据:DMA 传输过程中,CPU 不能直接修改源数据,否则可能造成数据不一致。
  • 资源紧张:每个 DMA 通道都是有限的硬件资源,别为了省事把通道全占满。