DMA基础与工作原理归纳总结

大家好,我是老赵。做嵌入式系统优化有些年头了。今天咱们聊聊DMA——这个在中断延迟和吞吐率里绕不开的硬件模块。

说实话,我刚入行那会儿,对DMA的理解也就停留在"能搬数据"这个层面。后来吃了几次亏,才老老实实把它的工作原理摸透了。这节课,我把自己的经验掰开揉碎讲给你听。

1.1 什么是DMA?先从一个场景说起

DMA,全称直接存储器访问(Direct Memory Access)。说白了,它就是个专职的硬件搬运工。

你想想看,如果没有DMA,CPU要从外设读一批数据,就得一条条指令去搬。CPU一边搬数据,一边还得处理中断、跑任务,累得够呛。有了DMA,CPU只需要告诉它:"帮我把这1000个字节从UART搬到内存"。然后DMA自己搞定,搬完了发个中断通知CPU。CPU该干嘛干嘛。

核心观点:DMA的本质是让数据传输不再占用CPU的执行流水线。CPU只负责"发指令"和"收结果",具体的搬运工作由DMA硬件独立完成。

我整理了一张对比表,你看一眼就明白了:

对比维度 CPU直接搬运 DMA搬运
CPU占用 全程占用,无法执行其他任务 仅配置和中断阶段占用,传输过程完全释放
传输速度 受限于CPU指令执行速率 硬件专用通道,通常更快且稳定
并发能力 传输期间无法响应其他任务 CPU可与DMA并行工作
适用场景 小数据量、零星传输 大数据量、实时流、周期性搬运

1.2 DMA的核心工作流程

DMA干活儿,分四步走。我习惯把它叫做"配、请、搬、通":

  1. 配:CPU配置DMA的源地址、目标地址、数据长度、传输方向等参数。这一步必须做对,否则后面全白搭。
  2. 请:外设(比如UART、ADC、SPI)发出DMA请求。有些DMA也支持软件触发,但大部分场景靠硬件请求。
  3. 搬:DMA控制器拿到总线控制权,开始从源地址往目标地址搬数据。搬多少个字节、用什么宽度搬,取决于配置。
  4. 通:传输完成,DMA向CPU发中断。CPU收到中断后处理数据,或者启动下一轮传输。

为了帮你直观理解这四步的关系,我画了一张工作原理图:

DMA工作原理框架 CPU 配置 · 启动 · 处理中断 DMA 控制器 总线仲裁 · 地址生成 · 传输控制 外设(UART/SPI/ADC) 内存(SRAM/DDR) ① 配置启动 ② 请求传输 ③ 数据写入 ④ 完成中断 流程闭环:①CPU配置DMA → ②外设触发请求 → ③DMA搬运数据 → ④中断通知CPU
我的小习惯:调试DMA时,我通常会先确认"请求"这一步有没有到位。拿示波器或者逻辑分析仪抓一下外设的DMA请求引脚,能快速判断是外设没发请求,还是DMA没响应。

1.3 DMA的三种传输模式

不同场景用不同模式,选对了事半功倍。我总结了一张表:

模式 特点 一次请求传输量 适用场景
单次传输 每次DMA请求只传一个数据单元,传完释放总线 1 个数据单元(字节/半字/字) 低速外设(如GPIO、低速UART)
突发传输 一次请求连续传多个数据单元,占用总线直到完成 4、8、16 个数据单元(可配置) 高速外设(如ADC、高速SPI、SDIO)
链表传输 通过描述符链表管理多个传输任务,硬件自动切换 每个描述符可单独配置 复杂批量传输、多缓冲循环采集

我在项目中遇到过一个问题:用突发传输搬运UART数据,结果老丢包。后来发现UART速率太低,DMA一次突发抢总线太久,把CPU的响应给堵了。换成单次传输就好了。所以选模式一定要看外设的速率和总线的负载。

1.4 关键参数与配置要点

配置DMA时,有几个参数你必须盯紧。我一个个说:

  • 通道与优先级:多通道DMA支持同时处理多个外设请求。高优先级通道会抢占低优先级的传输。我习惯把实时性要求高的外设(比如音频I2S)配成高优先级。
  • 数据宽度:源和目标的宽度可以不相等,DMA会自动做对齐和拼接。但注意——宽度不匹配时,传输效率会打折扣。
  • 地址对齐:源地址和目标地址最好按数据宽度对齐。比如32位宽度,地址最好是4字节对齐。没对齐的话,有些DMA会报错,有些会默默降速。
  • 传输粒度:指一次DMA传输的最小数据单元。粒度越小,灵活性越高,但配置开销也越大。
  • 循环模式:传输完成后自动重载起始地址,适合不间断的数据流采集。用这个模式时,记得配合双缓冲或者环形缓冲,否则数据会被覆盖。
避坑指南:我曾经在一个音频项目里,用DMA循环模式采集麦克风数据,结果声音断断续续。查了两天才发现是循环模式的地址重载时机没搞对,导致每次回绕时丢了一个采样点。后来用手动链表模式才彻底解决。

1.5 实战避坑:我踩过的三个DMA坑

经验都是拿故障换来的。分享三个我亲身踩过的坑:

  • 地址没对齐,DMA静默失败:有一回调试SPI DMA传输,配置完死活不工作。查寄存器状态,DMA显示"闲置"。后来发现源地址是奇数,而数据宽度配的是半字(2字节)。DMA直接罢工。从那以后,我配置DMA第一件事就是检查地址对齐。
  • 中断服务里操作DMA,导致死锁:我在ISR里重新配置DMA描述符,结果DMA正在传输时改了描述符,总线仲裁乱掉,整个系统挂死。正确做法是:在传输完成中断里置一个标志位,等退出ISR后再在任务级去操作DMA。
  • 突发长度太大,CPU饿死:有一次我配了16字的突发传输,SDIO连续抢总线,导致CPU的Cache刷新被延迟,系统响应变得很慢。把突发长度降到4字,问题解决。

1.6 小结

DMA的工作原理说到底就是"CPU授权、硬件搬运"。理解这个本质,后面分析中断延迟和吞吐率瓶颈时,你才能抓到根因。

这一章,我们讲了DMA和CPU的分工、四步工作流程、三种传输模式、关键参数配置,以及我踩过的真实坑。这些基础是你排查DMA相关性能问题的底气。