1、课程导学与DMA基础

1.1 这门课要解决什么问题?

做嵌入式开发久了,你会发现一个很头疼的问题:外设驱动代码写死了。

比如你写了一个 SPI 驱动,里面直接调了 HAL_SPI_Transmit。过两天换了个芯片,或者想加个 DMA 加速,得把整个驱动翻出来重写。我早期做项目时就吃过这个亏——一个温控模块,因为 SPI 驱动和 DMA 逻辑耦合太紧,换主控芯片时改了整整两周。

这门课的核心思路就一句话:把「外设操作」和「数据传输方式」拆开。你写驱动时只关心「我要发什么数据」,至于用轮询还是 DMA,那是上层配置的事。这样模块才能复用,代码才能移植。

我们会基于 STM32 的 HAL 库,从最基础的 DMA 讲起,一步步带你实现一个解耦的驱动框架。今天这第一节课,先把 DMA 的底子打牢。

1.2 DMA 到底是什么?

DMA,全称 Direct Memory Access,直接存储器访问。说白了,就是一个专门负责搬数据的小工。

没有 DMA 的时候,CPU 得亲自搬数据:从外设读一个字节,存到内存,再读下一个……整个过程 CPU 被死死拖住,啥也干不了。有了 DMA,你只需要告诉它:「从 ADC 的数据寄存器搬 100 个字节到内存缓冲区」,它自己就干完了,搬完再通知你一声。

核心理解:DMA 让 CPU 从「搬运工」变成「管理者」。CPU 只负责下指令、处理结果,中间的数据搬运全交给 DMA。

我在一个数据采集项目里用过这个特性。ADC 以 1MHz 采样,每 1µs 产生一个数据。如果用 CPU 搬,系统根本跑不了别的任务。换成 DMA 后,CPU 只在 DMA 搬完一整批数据后才去处理,负载从 90% 降到了 5%。

1.3 DMA 传输三要素

任何 DMA 传输,都离不开三个东西:源地址、目的地址、触发源。你想想看,搬数据总得知道从哪搬、搬到哪、什么时候开始搬吧?

要素 说明 常见例子
源地址 数据从哪来 外设数据寄存器(如 USART->DR)、内存数组
目的地址 数据搬到哪去 内存缓冲区、外设数据寄存器
触发源 什么时候开始搬 定时器溢出、ADC 转换完成、USART 接收非空

举个例子:你用 USART 接收一串数据。

  • 源地址:USART 的接收数据寄存器(USART1->DR)
  • 目的地址:你定义的一个数组 rx_buffer[100]
  • 触发源:USART 接收到一个字节(RXNE 标志)

每次 USART 收到一个字节,DMA 就自动把它搬到 rx_buffer 里。CPU 全程不用管。

个人习惯:我一般把源和目的都配置成「递增模式」——内存地址自动加 1,外设地址固定不变。这样连续传输时不用手动更新地址,省心很多。

1.4 DMA vs CPU 传输:到底快在哪?

很多人以为 DMA 比 CPU 快。其实不完全对。DMA 的传输速度并不比 CPU 快多少,它真正的优势是不占 CPU 时间。

来看一个对比:

对比项 CPU 轮询传输 DMA 传输
CPU 占用率 100%(全程搬运) 仅配置和完成中断时占用
传输速度 受 CPU 主频和指令周期影响 与 CPU 相当,但可并行
适合场景 单次、少量、实时性要求不高的数据 批量、连续、高速数据流
代码复杂度 简单,直接读写寄存器 需要配置 DMA 通道和中断
功耗 CPU 一直跑,功耗高 CPU 可以休眠,功耗低

我举个例子你就明白了。假设你要从 SPI Flash 读 1KB 数据:

  • CPU 轮询:CPU 发一个读命令,等 SPI 完成,读一个字节,再发下一个……循环 1024 次。这期间 CPU 啥也干不了。
  • DMA 方式:CPU 配置好 DMA,说「从 SPI 搬 1024 字节到内存」,然后就去处理别的任务了。DMA 搬完后触发中断,CPU 再来处理数据。

说白了,DMA 让 CPU 从「亲自搬砖」变成了「指挥搬砖」。效率提升不在速度,而在并行。

注意:DMA 不是万能的。如果每次只传几个字节,配置 DMA 的开销可能比直接 CPU 传输还大。我曾经在一个项目中过度使用 DMA,结果频繁的配置和中断反而拖慢了系统。后来改成:小数据用轮询,大数据用 DMA,效果好了很多。

1.5 DMA 传输的完整流程

下面这张图展示了 DMA 一次典型传输的完整流程。我建议你仔细看看,后面写代码时脑子里要有这个图。

DMA 一次完整传输流程 CPU 配置 DMA 外设触发请求 DMA 开始传输 传输完成? 触发完成中断 CPU 处理数据 继续配置 流程说明: 1. CPU 先配置 DMA 的源地址、目的地址、传输长度、触发源等参数 2. 外设产生触发信号(如 USART 收到数据),DMA 开始搬运 3. 传输完成后,DMA 触发中断,CPU 来处理这批数据 4. 如果需要继续传输,CPU 重新配置 DMA,进入下一轮

这个流程里有个关键点:DMA 传输是「触发式」的。没有触发信号,DMA 就闲着。触发信号一来,它才动一下。所以配置 DMA 时,触发源的选择特别重要——选错了,数据就丢了。

1.6 本章小结

好,第一节课的内容就这些。我们理清了几个核心概念:

  • DMA 是一个独立的数据搬运硬件模块
  • 任何 DMA 传输都离不开源地址、目的地址、触发源三要素
  • DMA 的优势不是速度,而是让 CPU 从搬运中解放出来
  • DMA 适合批量连续传输,小数据用轮询反而更高效