DMA控制器架构:通道、信号与寄存器

DMA控制器,说白了就是CPU的「数据搬运工」。CPU告诉它「从哪搬、搬到哪、搬多少」,它就能自己干完,不用CPU一次次打断。我刚开始接触DMA时,总觉得它很神秘,后来拆开一看,核心就那么几个部件。

核心要点:DMA控制器的骨架是「通道 + 请求/应答握手 + 三组核心寄存器」。理解这三样,你就掌握了80%的DMA工作原理。

2.1 DMA通道——独立的数据搬运线

每个DMA通道,就像一条独立的数据流水线。不同外设可以占用不同通道,互不干扰。比如UART用通道0,SPI用通道1,ADC用通道2——它们可以同时工作。

我见过一个项目,工程师把所有外设都挤在同一个通道上,结果数据冲突,调试了三天。嗯,这里要注意:通道是独立资源,不是共享总线。

通道特性 说明 我见过的坑
通道数量 通常4~16个,取决于芯片型号 别以为通道多就能随便用,优先级要规划好
通道优先级 固定优先级或轮询模式 高优先级通道会「饿死」低优先级通道
通道绑定 每个通道可绑定特定外设请求 我曾经绑错通道,数据全乱套了

2.2 请求与应答信号——DMA的「门铃」

DMA不会自己主动干活。它需要外设「按门铃」——也就是发送请求信号。外设说「我有数据了,快来拿」,DMA收到请求后,回复一个应答信号「收到,我来了」。

这个握手过程,我习惯把它比作两个人打电话:

  • DMA请求(DREQ):外设打给DMA,「我有数据要传输」
  • DMA应答(DACK):DMA回给外设,「收到,总线我接管了」
  • 传输结束(TC):DMA告诉CPU,「活干完了,你继续」

实战经验:我曾经遇到一个ADC采集丢数据的问题。查了半天,发现是DMA请求信号宽度太短,DMA没来得及响应。后来把请求信号拉长了一个时钟周期,问题解决。信号时序,真的不能马虎。

2.3 源地址与目的地址寄存器——DMA的「导航」

DMA要搬数据,总得知道从哪搬、搬到哪。这两个寄存器就是干这个的。

  • 源地址寄存器(SAR):存放数据来源的地址。可以是外设数据寄存器地址,也可以是内存地址。
  • 目的地址寄存器(DAR):存放数据要去的地址。通常是内存缓冲区地址。

你想想看,如果每次传输后地址都不变,那DMA只能反复读写同一个位置,这有什么用?所以这两个寄存器还有一个重要特性——地址更新模式。

地址模式 说明 典型场景
固定地址 传输后地址不变 外设数据寄存器(固定地址)
递增地址 传输后地址+1/+2/+4 内存缓冲区(连续地址)
递减地址 传输后地址-1/-2/-4 栈操作、FIFO读取

避坑指南:我曾经在配置SPI DMA传输时,把源地址设成了递增模式。结果每次传输后,DMA都去读下一个地址,而不是SPI的数据寄存器。数据全读错了。外设地址一定要用固定模式,这个错误我犯过一次就再也没忘。

2.4 传输计数器——DMA的「计步器」

传输计数器(CNDTR),记录还剩多少数据没搬完。每传输一次,计数器减1。减到0时,DMA就知道活干完了,可以触发中断告诉CPU。

我个人习惯在调试时,先检查这个计数器的值。如果它没按预期递减,说明DMA根本没在工作。有一次我排查一个UART DMA接收问题,发现计数器始终是初始值——原来是我忘了使能DMA通道。

关键参数:传输计数器的初始值 = 你要传输的数据单元个数。注意是「单元个数」,不是字节数。如果配置的是16位传输,计数器=100表示传输100个半字(200字节)。

2.5 DMA控制器架构总览

下面这张图,把上面讲的几个核心部件串起来。我建议你多看几遍,理解数据是怎么从外设流到内存的。

DMA控制器架构图 CPU DMA控制器 通道0 | 通道1 | 通道2 ... 内存 外设 请求与应答 DREQ → DACK → TC 核心寄存器 SAR | DAR | CNDTR 配置/启动 数据搬运 DREQ 触发传输 配置参数 工作流程 1. CPU配置寄存器 2. 外设发起请求 3. DMA搬运数据

2.6 寄存器配置实战要点

配置DMA寄存器时,我建议按这个顺序来,不容易出错:

  1. 先关通道:修改配置前,确保通道是禁用的。否则配置可能被正在进行的传输干扰。
  2. 配源地址:外设地址用固定模式,内存地址用递增模式。
  3. 配目的地址:和源地址模式对应好,别搞反了。
  4. 设传输计数器:确定要传多少个数据单元。
  5. 设传输宽度:8位、16位还是32位?必须和外设寄存器宽度一致。
  6. 使能通道:最后一步,打开通道,等待外设触发。

小技巧:调试时,我习惯在使能通道前,先读一遍所有配置寄存器的值,确认无误再开启。这个习惯帮我省了不少排查时间。

2.7 常见配置错误

错误类型 现象 我曾经的处理方式
地址模式配反 数据只传了第一个字节 检查SAR/DAR的地址更新位
传输宽度不匹配 数据错位或丢失 确保外设和DMA宽度一致
计数器初始值=0 DMA不工作 计数器=0时,DMA认为传输已完成
通道优先级冲突 低优先级通道卡死 合理分配优先级,必要时用轮询模式