描述
做嵌入式开发时,大家是不是都有过这种崩溃场景:
- 采集一个传感器数据,本来以为只是简单的 ADC → 内存,结果发现 CPU 忙得要死;
- 想收点串口数据,CPU 每次被中断打断,延迟累积到系统卡顿;
- 数据传输量一上来,系统直接掉帧甚至死机。
很多初学者遇到这种情况,第一反应是“是不是代码写得不够高效”。但事实是:你再怎么优化循环,CPU 亲自搬数据就是效率低。
解决方案其实很明确——用 DMA(Direct Memory Access,直接存储器访问)。如果你会合理使用 DMA,很多“看似不可避免的性能瓶颈”都能迎刃而解。今天我们就来聊聊 DMA 的工作原理、常见应用和实战技巧。
一、DMA 究竟是什么?
DMA 的核心思路很简单:把数据搬运工作交给硬件去做。
在没有 DMA 的情况下,数据传输的流程大概是:
- 外设产生数据;
- CPU 中断响应;
- CPU 把数据读出来放到内存。
而有了 DMA:
- 外设和 DMA 控制器直接“勾搭”;
- 数据绕过 CPU,直接搬到内存。
这样一来,CPU 不用再做“快递员”,可以专心处理逻辑,系统响应速度和并发能力都能上一个台阶。
二、DMA 的常见应用场景
1. 串口数据接收(UART DMA)
如果你做过大数据量的串口通信,就会发现中断方式很容易丢数据。
- DMA 可以配置成循环缓冲区,数据一来就自动写入 RAM;
- CPU 只需要在合适的时候检查缓冲区,不用每个字节都处理中断。
2. ADC 连续采样
很多传感器需要高速采样,比如电机控制中的电流检测。
- 普通方式下,CPU 每次采样要响应 ADC 中断,很快就“累趴”;
- 用 DMA,可以把采样结果自动存到数组里,形成数据流,CPU 后续再批量处理。
3. 内存到外设数据传输
比如 SPI 发送、DAC 输出波形:
- 传统方式要一个字节一个字节写寄存器;
- DMA 可以直接把内存中的一段缓冲区刷到外设寄存器,效率极高。
4. 内存到内存传输
一些芯片的 DMA 支持 内存块搬运,可以用来快速清零数组、搬运数据结构,CPU 不用一个循环一个循环写。
三、DMA 配置的关键要点
很多同学第一次用 DMA,发现配置比想象中复杂。其实总结起来,主要是以下几个步骤:
- 确定通道/流
- DMA 控制器通常有多个通道,对应不同的外设。
- 要查手册,看你的外设挂在哪个 DMA 通道上。
- 配置源地址和目的地址
- 源地址可以是外设寄存器,比如 ADC_DR。
- 目的地址一般是内存数组。
- 有时候是反过来,比如内存 → SPI。
- 配置传输方向
- 外设到内存(ADC、UART RX);
- 内存到外设(SPI TX、DAC);
- 内存到内存。
- 配置数据长度和传输模式
- 单次搬运几个字节?总共搬多少?
- 是循环模式(buffer 自动回绕)还是普通模式?
- 启动 DMA
- 记得在外设使能之前配置好 DMA;
- 启动顺序有讲究,比如 UART DMA 要先开 DMA 再开 UART 接收。
四、实战技巧:避免常见坑
技巧 1:循环缓冲 vs 普通模式
- 如果数据源是持续的(比如串口、ADC),用循环缓冲更稳。
- 如果只是一次性发送一段数据(比如 SPI 发命令),普通模式即可。
技巧 2:善用中断回调
DMA 虽然能自动搬数据,但你还是得知道“什么时候搬完”。
- 可以开传输完成中断,在回调函数里处理数据。
- 对于循环模式,可以用半传输中断,做到“边采集边处理”。
技巧 3:缓存对齐问题
有些 MCU 的 DMA 对地址有对齐要求,比如 4 字节对齐,否则性能下降甚至报错。写代码前要看手册。
技巧 4:注意总线带宽
DMA 不是“无限快”,它也占用内存总线。
- 多个 DMA 通道同时工作时,可能会互相抢占。
- 解决方法:错峰启动,或者降低非关键任务的优先级。
技巧 5:与 CPU 配合
DMA 搬数据的同时,CPU 可能要访问同一片内存。
- 要小心数据一致性问题,可以用“双缓冲”或者加锁机制。
五、案例分享
案例 1:ADC + DMA 实现波形采集
某项目需要 10kHz 的 ADC 采样,用中断方式 CPU 占用率高达 70%。
→ 换成 DMA 循环搬运到数组,CPU 占用率直接降到 5% 以下,系统反应流畅。
案例 2:UART 接收不丢包
串口调试工具长时间发送数据,CPU 用中断处理时经常丢字节。
→ 改用 DMA + 环形缓冲 + IDLE 中断检测帧间隔,接收稳定,再也没掉过包。
案例 3:SPI 高速传输
某 OLED 屏幕更新一帧图像需要传 8KB 数据,用循环写寄存器方式刷新率只有 20fps。
→ DMA 一次传输缓冲区,刷新率提高到 60fps,画面流畅无比。
六、总结
DMA 对嵌入式开发来说,是“必学技能”之一。很多人初学时嫌它复杂,继续让 CPU 自己“跑腿”,结果系统卡顿、性能不达标。其实只要掌握几个要点:
- 了解外设和 DMA 通道的映射关系;
- 正确配置源地址、目的地址和传输模式;
- 结合中断回调实现数据处理;
- 注意带宽和缓存一致性问题。
你就能真正实现 “零 CPU 占用的高速传输”,让系统既高效又稳定。
打开APP阅读更多精彩内容