1. DMA 基础概念:为什么你的 CPU 不该干搬运的活
各位同学好,我是你们的嵌入式系统讲师。今天咱们开始《STM32F407 DMA 传输性能调优与调试实战》的第一章。
先问大家一个问题:你写单片机程序时,有没有遇到过这种情况——明明 CPU 主频不低,但一跑大数据量传输,系统就卡顿、响应变慢?
嗯,我刚开始做嵌入式开发那会儿也踩过这个坑。后来才发现,问题出在 CPU 干了太多「搬运工」的活。而 DMA,就是专门来解决这个问题的。
1.1 什么是 DMA?
DMA,全称 Direct Memory Access,直接存储器访问。说白了,就是硬件层面专门负责数据搬运的一个独立模块。
你可以把它想象成一个「专职快递员」:CPU 告诉它「把 A 地址的数据搬到 B 地址,搬完通知我」,然后 DMA 就自己干活去了,CPU 可以继续处理其他任务。
核心要点:DMA 是一种允许外设与存储器之间、或存储器与存储器之间直接传输数据的技术,传输过程不需要 CPU 参与。
在 STM32F407 上,DMA 控制器有 2 个(DMA1 和 DMA2),每个控制器有 8 个数据流(Stream),每个数据流支持最多 8 个通道(Channel)请求。这个资源量,说实话,在 Cortex-M4 系列里算很充裕了。
1.2 DMA 与 CPU 的关系:分工协作
很多人刚接触 DMA 时,会误以为 DMA 能「替代」CPU。其实不是这样。
CPU 是大脑,负责决策、运算、控制流程。DMA 是手脚,负责重复性的数据搬运。两者是协作关系,不是替代关系。
我画了一张图,帮大家理清这个关系:
从这张图可以看出:
- CPU 负责配置 DMA、处理中断、执行应用程序逻辑
- DMA 控制器 负责在存储器与外设之间、或存储器与存储器之间搬运数据
- AHB 总线矩阵 提供多主多从的互联架构,让 DMA 和 CPU 可以并行访问不同的从设备
个人经验:我在做一款数据采集设备时,ADC 采样率 1Msps,每次采样 12 位,如果不使用 DMA,CPU 每 1us 就要响应一次中断去读数据。用了 DMA 后,CPU 占用率从 85% 降到了 12%。这个差距,你品,你细品。
1.3 DMA 传输的优势
DMA 的优势,说白了就三个字:省 CPU。但具体省在哪?我列个表给大家看:
| 对比维度 | CPU 直接传输 | DMA 传输 |
|---|---|---|
| CPU 占用率 | 100%(传输期间无法做其他事) | 仅配置和中断处理时占用(通常 <5%) |
| 传输速度 | 受限于 CPU 指令执行速度 | 硬件级传输,可达 AHB 总线峰值带宽 |
| 实时性 | 受中断优先级和任务调度影响 | 独立硬件,响应延迟可预测 |
| 功耗 | CPU 持续运行,功耗较高 | CPU 可进入低功耗模式,DMA 独立工作 |
| 代码复杂度 | 简单直观,逐字节处理 | 需要配置 DMA 描述符,稍复杂 |
| 适用场景 | 小数据量、非实时、简单应用 | 大数据量、高实时、低功耗应用 |
这个表格很直观。但我想强调一点:DMA 不是万能的。对于几十个字节的小数据传输,配置 DMA 的开销可能比 CPU 直接搬还大。我见过有人为了传 4 个字节专门配了个 DMA——嗯,这属于杀鸡用牛刀。
1.4 DMA 的适用场景
根据我多年的项目经验,以下场景特别适合使用 DMA:
- 高速数据采集:ADC 连续采样、多通道同步采集
- 通信外设数据收发:USART、SPI、I2C 的大数据包传输
- 存储器间数据搬移:从 Flash 拷贝数据到 SRAM,或 SRAM 内部数据搬移
- 显示刷新:LCD 显存更新、图形缓冲区传输
- 音频处理:I2S 音频数据流传输
- 定时触发传输:配合定时器实现周期性数据搬移
避坑指南:我曾经在一个项目中,用 DMA 做 SPI 从机接收。结果发现 DMA 传输完成中断和 SPI 接收完成中断同时触发,导致中断嵌套混乱。后来我调整了中断优先级,并使用了 DMA 的 FIFO 模式才解决。这个坑,大家后面做实战时会遇到,我先提个醒。
1.5 STM32F407 DMA 资源概览
最后,给大家看看 F407 的 DMA 资源,心里有个数:
| DMA 控制器 | 数据流数 | 通道数/数据流 | FIFO 大小 | 支持的外设 |
|---|---|---|---|---|
| DMA1 | 8 | 8 | 4 字 | ADC、TIM、SPI、USART、I2C |
| DMA2 | 8 | 8 | 4 字 | SPI、USART、I2S、SDIO、DCMI、CRYP |