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干活儿,分四步走。我习惯把它叫做"配、请、搬、通":
- 配:CPU配置DMA的源地址、目标地址、数据长度、传输方向等参数。这一步必须做对,否则后面全白搭。
- 请:外设(比如UART、ADC、SPI)发出DMA请求。有些DMA也支持软件触发,但大部分场景靠硬件请求。
- 搬:DMA控制器拿到总线控制权,开始从源地址往目标地址搬数据。搬多少个字节、用什么宽度搬,取决于配置。
- 通:传输完成,DMA向CPU发中断。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相关性能问题的底气。