1. 课程导论:DMA与低功耗的“爱恨情仇”——为什么需要协同设计?
各位工程师朋友,欢迎来到这门课。
咱们开门见山。DMA(直接存储器访问)和低功耗设计,这两个东西单独拎出来,大家都不陌生。但把它们放在一起,很多人就开始头疼了。我见过不少项目,DMA用得挺溜,一进低功耗模式就“死机”;也见过为了省电,把DMA功能砍掉大半,结果CPU累得半死,功耗反而没降下来。
这俩家伙,到底是朋友还是敌人?
1.1 先聊聊DMA:它到底在忙什么?
DMA,说白了就是一个“数据搬运工”。CPU让它搬数据,它就去搬,搬完了告诉CPU一声。CPU呢?该睡觉睡觉,该算算术算算术,不用管这些琐事。
我举个例子。你做一个ADC连续采样,每秒要采集10000个数据。如果没有DMA,CPU每采一个数就得进一次中断,把数据从ADC寄存器搬到内存里。10000次中断,CPU基本就废了,啥也别干了。
有了DMA呢?你配置好源地址(ADC数据寄存器)、目的地址(内存数组)、传输长度(10000个),然后启动。DMA自己一趟一趟地搬,CPU全程可以睡大觉,或者干别的活。等DMA搬完了,给你一个完成中断,你一次性处理这10000个数据。
1.2 再聊聊低功耗:STM32的“省电秘籍”
STM32的低功耗模式,大家应该都接触过。从最简单的Sleep模式,到深度睡眠的Stop模式,再到几乎掉电的Standby模式,省电效果依次递增,但唤醒代价也越来越大。
我整理了一个表格,方便大家对比:
| 模式 | 典型电流 | CPU状态 | 外设状态 | 唤醒时间 |
|---|---|---|---|---|
| Run(运行) | 几十~几百mA | 全速运行 | 全部可用 | — |
| Sleep(睡眠) | 几~几十mA | 暂停,可被中断唤醒 | 全部可用(时钟继续) | 几us |
| Stop(停止) | 几十~几百uA | 暂停,SRAM保持 | 部分可选保持 | 几十us |
| Standby(待机) | 几uA以下 | 掉电,SRAM丢失 | 仅RTC、IWDT等 | 几百us~几ms |
嗯,这里要注意。很多工程师觉得,只要进了Stop模式,功耗就万事大吉了。但实际情况是,你如果没处理好DMA和外设的时钟关系,系统可能根本进不了Stop模式,或者进去了,DMA还在偷偷耗电。
1.3 冲突点:DMA和低功耗的“爱恨情仇”
问题来了。DMA要工作,需要时钟。低功耗模式要省电,第一件事就是关时钟。这不就冲突了吗?
我总结了一下,常见的冲突点有三个:
- 时钟依赖冲突: DMA控制器通常挂在AHB总线上。进入Stop模式时,AHB总线时钟会被关闭。如果DMA正在传输,突然断时钟,轻则传输错误,重则总线挂死。
- 请求源失效: DMA传输需要外设触发(比如ADC、USART、SPI)。进入低功耗模式后,这些外设的时钟可能被关闭,触发信号没了,DMA就傻等着。
- 唤醒后状态恢复: 从Stop模式唤醒后,DMA控制器的寄存器内容是否保持?有些系列是保持的,有些需要重新配置。我就在F4系列上踩过坑——唤醒后DMA的传输地址指针乱了,数据全写错地方。
1.4 协同设计:不是二选一,而是“既要又要”
所以,DMA和低功耗不是敌人。它们是合作伙伴。你需要做的,是学会如何让它们协同工作。
协同设计的核心思路,我画了一张图:
说白了,协同设计的精髓就是:在DMA干活的时候,让CPU睡;在DMA干完活之后,让整个系统睡。 这样既保证了数据吞吐,又实现了极致省电。
1.5 这门课能给你什么?
我设计这门课,就是要把这些“坑”和“招”系统地讲清楚。咱们不搞虚的,直接上实战。
- 你会学到: 如何在STM32F1/F4/L4/G0等主流系列上,配置DMA与低功耗模式的协同工作。
- 你会看到: 完整的代码示例,从初始化到低功耗切换,再到唤醒恢复,每一步都有注释。
- 你会避开: 我这些年踩过的坑——比如DMA FIFO在Stop模式下的行为、不同系列DMA寄存器保持特性的差异、以及如何用DMA+定时器实现“无CPU干预”的周期性采样。