DMA 实战指南:零 CPU 占用玩转高速数据传输

描述

 

做嵌入式开发时,大家是不是都有过这种崩溃场景:

  • 采集一个传感器数据,本来以为只是简单的 ADC → 内存,结果发现 CPU 忙得要死;
  • 想收点串口数据,CPU 每次被中断打断,延迟累积到系统卡顿;
  • 数据传输量一上来,系统直接掉帧甚至死机。

很多初学者遇到这种情况,第一反应是“是不是代码写得不够高效”。但事实是:你再怎么优化循环,CPU 亲自搬数据就是效率低。

解决方案其实很明确——用 DMA(Direct Memory Access,直接存储器访问)。如果你会合理使用 DMA,很多“看似不可避免的性能瓶颈”都能迎刃而解。今天我们就来聊聊 DMA 的工作原理、常见应用和实战技巧。

 


一、DMA 究竟是什么?

DMA 的核心思路很简单:把数据搬运工作交给硬件去做。

在没有 DMA 的情况下,数据传输的流程大概是:

  1. 外设产生数据;
  2. CPU 中断响应;
  3. CPU 把数据读出来放到内存。

而有了 DMA:

  1. 外设和 DMA 控制器直接“勾搭”;
  2. 数据绕过 CPU,直接搬到内存。

这样一来,CPU 不用再做“快递员”,可以专心处理逻辑,系统响应速度和并发能力都能上一个台阶。


二、DMA 的常见应用场景

1. 串口数据接收(UART DMA)

如果你做过大数据量的串口通信,就会发现中断方式很容易丢数据。

  • DMA 可以配置成循环缓冲区,数据一来就自动写入 RAM;
  • CPU 只需要在合适的时候检查缓冲区,不用每个字节都处理中断。

2. ADC 连续采样

很多传感器需要高速采样,比如电机控制中的电流检测。

  • 普通方式下,CPU 每次采样要响应 ADC 中断,很快就“累趴”;
  • 用 DMA,可以把采样结果自动存到数组里,形成数据流,CPU 后续再批量处理。

3. 内存到外设数据传输

比如 SPI 发送、DAC 输出波形:

  • 传统方式要一个字节一个字节写寄存器;
  • DMA 可以直接把内存中的一段缓冲区刷到外设寄存器,效率极高。

4. 内存到内存传输

一些芯片的 DMA 支持 内存块搬运,可以用来快速清零数组、搬运数据结构,CPU 不用一个循环一个循环写。


三、DMA 配置的关键要点

很多同学第一次用 DMA,发现配置比想象中复杂。其实总结起来,主要是以下几个步骤:

  1. 确定通道/流
  • 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 自己“跑腿”,结果系统卡顿、性能不达标。其实只要掌握几个要点:

  1. 了解外设和 DMA 通道的映射关系;
  2. 正确配置源地址、目的地址和传输模式;
  3. 结合中断回调实现数据处理;
  4. 注意带宽和缓存一致性问题。

你就能真正实现 “零 CPU 占用的高速传输”,让系统既高效又稳定。

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分