第1章 DMA基础概念与工作原理

大家好,我是你们的讲师。做嵌入式这么多年,我见过太多因为DMA中断响应慢导致的性能瓶颈。说实话,很多人一开始觉得DMA就是“自动搬数据”,没啥好研究的——直到项目翻车才开始认真琢磨。今天咱们就把DMA的底裤扒干净,从最基础的概念讲起。

1.1 DMA传输流程

DMA的全称是Direct Memory Access,说白了就是让外设和内存之间直接交换数据,不需要CPU一字节一字节地搬运。CPU只需要告诉DMA控制器“从哪搬、搬到哪、搬多少”,然后就可以去干别的事了。

一个完整的DMA传输流程大概分这几步:

  1. CPU配置DMA控制器:设置源地址、目的地址、传输长度、传输模式、中断使能等。
  2. CPU使能DMA通道:启动传输请求。
  3. DMA控制器获取总线控制权:向总线仲裁器申请,拿到总线后开始工作。
  4. DMA搬运数据:从源地址读,写到目的地址,每传一次就更新计数器。
  5. 传输完成,触发中断:计数器减到0时,DMA控制器向CPU拉中断信号。
  6. CPU响应中断,处理数据:进入ISR,检查状态,收尾工作。

看上去很清晰对吧?但实际跑起来,每一步都可能埋坑。我曾经遇到过一个问题:CPU配置完DMA后立即进入了低功耗模式,结果DMA启动时总线仲裁延迟太大,导致第一次传输就超时了……后来我加了个小延迟等待DMA就绪标志,问题才解决。

关键点:DMA传输过程中,CPU几乎不参与数据搬运,但中断响应阶段CPU会被打断。中断响应延迟就是我们课程要优化的核心。

为了让你更直观地理解,我画了一张DMA传输的流程图:

DMA传输流程(简化) ① CPU配置DMA 源/目的/长度/模式 ② 使能DMA通道 发起传输请求 ③ 获取总线控制权 仲裁等待,可能延迟 ④ 数据搬运 源 → 目的,计数器递减 ⑤ 传输完成 → 中断 知识点 CPU配置后即可空闲 中断响应延迟在此之后

提示:流程图中第③步“获取总线控制权”是很多延迟的起点。如果你发现DMA传输总是慢半拍,先检查总线优先级设置。

1.2 DMA通道与请求

DMA控制器通常有多个通道,每个通道可以独立配置,服务于不同的外设。举个例子,一个芯片可能有8个DMA通道,你可以把通道0分配给UART接收,通道1给ADC转换结果,通道2给SPI发送……它们可以并行工作,但不是真正的“同时”——因为总线只有一条,所以通道之间要仲裁。

通道 关联外设 传输方向 典型触发源
CH0 UART1 RX 外设→内存 UART接收就绪
CH1 ADC1 外设→内存 ADC转换完成
CH2 SPI2 TX 内存→外设 SPI发送缓冲区空
CH3 定时器触发 内存→内存 定时器溢出

你想想看,如果多个通道同时请求,谁先谁后就靠优先级来排。大部分DMA控制器支持固定优先级和轮询优先级。我个人习惯把中断敏感的通道(比如实时音频流)设高优先级,而批量数据搬运(比如大文件拷贝)设低优先级。

还有一种特殊情况叫连锁传输(DMA chaining),就是一个DMA通道做完一件事后自动启动下一个DMA传输,连CPU都不需要来管。我在某个视频采集项目里用过这个特性:用两个DMA描述符链在一起,一个采集一帧数据,另一个拷贝到显示缓冲区,连续循环,CPU几乎零干预。

注意:DMA请求信号可能来自硬件外设,也可能由软件触发。如果软件触发时忘了清除请求标志,DMA会重复传输,你可能会看到意想不到的数据覆盖。

1.3 传输模式:单次/突发/循环

模式这东西,说白了就是一次传多少、怎么传、传完怎么办。咱们来一个个说。

  • 单次传输(Single Transfer):每次DMA请求只传1个数据单元(1字节/半字/字),传完释放总线。适合低速外设或者数据量很小的场景。优点是总线占用时间短,缺点是一次请求开销不小(锁总线要开销,发起请求也要开销),频繁触发反而效率低。
  • 突发传输(Burst Transfer):一次请求传多个数据单元(比如16个字节)。批量搬,效率高,适合大块数据,比如USB、以太网。但突发期间总线一直被占用,其他高优先级传输就得等着。
  • 循环传输(Circular / Auto-Reload Transfer):计数到0后自动重载初始值,继续传输。不需要CPU重新配置。典型应用是环形缓冲区(ping-pong buffer)、连续ADC采样、定时刷新的显示缓冲。采集音频时我经常用这个模式——DMA不停地把ADC数据往环形缓冲区里塞,CPU只管取走处理就好。

三种模式对中断响应延迟的影响完全不同。单次模式每个单元都要中断,中断频率高,CPU大部分时间都在进进出出;突发模式密集搬完一包后中断一次,CPU压力小很多;循环模式则根本不主动中断(除非配置了半满中断或错误中断),靠CPU轮询或者硬触发同步。

核心结论:中断次数越少,CPU被打断的次数就越少,但单次中断的响应延迟要求更高(因为要处理的数据更多)。熟悉四种模式(其实还有第4种“数据块传输”)的优缺点,是优化DMA中断延迟的第一步。

我记得到有一个小项目,用单次模式传SPI数据,每传1个字节就中断一次,CPU跑在40MHz结果还是掉数据。后来改成突发模式一次传64字节,再优化了中断处理,问题一下就解决了。嗯,选对模式比调优先级管用多了。