1. DMA 概述:历史与作用

各位同学,今天咱们聊聊 DMA——直接存储器访问。这名字听起来有点硬核,其实说白了,就是给 CPU 找了个“跑腿小弟”。让 CPU 从繁琐的数据搬运活儿里解放出来,去做它更擅长的运算和调度。

我入行那会儿,还在用 8051 单片机做数据采集。那时候没有 DMA,CPU 得亲自把每个字节从外设读到寄存器,再存到内存里。一次 ADC 采集循环,CPU 有 90% 的时间都在“搬砖”。后来我第一次用上带 DMA 的 ARM 芯片,感觉就像从手推车换成了传送带——效率提升是质变的。

1.1 DMA 诞生:从“轮询噩梦”到“解放 CPU”

计算机早期,CPU 是的中心。所有 I/O 操作都得它亲手操办。

  • 程序查询方式(Polling):CPU 反复检查外设状态寄存器,数据准备好就读走。简单,但 CPU 被死死“焊”在查询循环里,做不了别的。
  • 中断方式(Interrupt):外设就绪后主动通知 CPU,CPU 暂停当前任务去处理。比查询好,但每个字节中断一次,上下文切换开销不小。高频 I/O 场景(比如千兆网卡)下,中断风暴照样能把 CPU 打趴。

为什么需要 DMA?看一组数字你就明白了。

传输方式 CPU 占用率(1 MB/s 传输) 典型延迟
程序查询 ≈ 100% 微秒级
中断驱动(每字节中断) 30% – 50% 微秒级 + 中断开销
DMA 模式 < 5% 纳秒级(硬件传输)

我在一个高速数据采集项目里,用 100 kHz 采样率、16 位精度,如果是中断方式,CPU 几乎全部用来处理中断,还老丢数据。换成 DMA 后,CPU 跑算法、刷屏幕,一切流畅。嗯,这就是 DMA 的价值。

1.2 DMA 核心作用:把 CPU 从“数据搬运工”变成“指挥官”

DMA 控制器是一个独立硬件模块。它负责在外设和内存之间,或者内存和内存之间,直接传输数据。整个过程 CPU 只需设置一次“任务描述符”,然后去睡觉,传输完成后 DMA 发一个中断通知 CPU:“活儿干完了”。

具体来说,它的核心价值体现在三个方面:

  1. 释放 CPU 算力:CPU 不必再逐字节搬运。一个典型的大型数据拷贝,CPU 指令周期可能成千上万;DMA 在总线周期内完成,CPU 可以并行做其他事。
  2. 降低传输延迟:DMA 用硬件状态机做数据搬移,延迟远低于软件循环。尤其在高速外设(如 camera、以太网、SSD)中,DMA 几乎不可或缺。
  3. 支持后台批量操作:DMA 可以一次配置传输整块数据(比如 4KB、16KB),甚至通过描述符链连续传输无限长度的数据流。真正实现“零干预”后台 I/O。

一句话总结:DMA 机制的本质是 “任务委托 + 硬件并行”。CPU 定义数据流向,DMA 控制器执行,双方独立跑。

1.3 DMA 发展简史:从“独立芯片”到“片上系统标配”

  • 1960s – 1970s:大型机时代,DMA 作为独立控制器芯片出现。IBM System/360 率先使用通道方式实现 I/O 与 CPU 并行。
  • 1980s:Intel 8237 DMA 控制器成为 PC 标准。我记得当年玩 DOS 下的声卡 DMA,得手动设置 DREQ/DACK 线,一不留神就冲突死机。
  • 1990s – 2000s:嵌入式 SoC 将 DMA 控制器集成到片内。ARM PrimeCell DMA 成为经典。
  • 2010s 至今:描述符链、分散-聚集(Scatter-Gather)、多通道、QoS(服务质量)成为标配。DMA 不再只是“搬砖工”,而是智能数据通路引擎。

我在做视频编码芯片驱动时,用过带链接描述符的 DMA。传统循环传输需要频繁重新配置;描述符链允许你预先写好几组传输任务,DMA 自动依次执行。这种模式对高吞吐、低抖动的场景非常关键。

1.4 一张图看懂 DMA 在系统中的位置

DMA 系统架构与数据流示意 CPU DMA 控制器 内存(SRAM/DRAM) 外设 (ADC) 外设 (UART) 外设 (以太网) 配置/描述符 数据写入 请求信号 请求信号 请求信号 数据流方向:外设 → DMA → 内存(或内存 → 外设) CPU 只负责初始化 DMA 描述符,传输过程完全由 DMA 控制。

1.5 为什么嵌入式系统里的 DMA 尤为重要?

嵌入式芯片资源有限,CPU 主频不高,内存带宽吃紧。这时候 DMA 的价值就更大了。我举个例子:

  • 音频编解码:I2S 接口连续传输数据,如果走中断,CPU 被拖得死死;DMA 双缓冲可以做到无感播放。
  • 电机控制:用 DMA 定时更新 PWM 比较值,省去中断延迟对控制精度的干扰。
  • 显示驱动:DMA 直接从帧缓冲区搬运数据到 LCD 接口,CPU 只管画图。

你想想看,没有 DMA 的嵌入式系统就像一个人既当司机又当搬运工,效率能高才怪。

注意:DMA 并非万能药。传输数据量很小(比如几个字节)时,DMA 初始化的开销可能比 CPU 直接搬还大。我曾经在某个项目里错把每次 4 字节的 SPI 传输也配成 DMA,结果延迟反而增大。要判断阈值:通常 ≥ 64 字节用 DMA 才划算。

1.6 从“传统 DMA”到“描述符链循环”

传统 DMA 的工作方式是:每次传输前,CPU 设置源地址、目的地址、长度,启动;传输完成触发中断,CPU 再重新配置下一轮。这种“单次传输”模式在批量连续数据流下效率不高,因为每次都要 CPU 重新参与配置。

描述符链(Descriptor Chain)解决了这个问题。它的核心思路是:

  1. CPU 预先在内存中构建一个描述符链表,每个描述符包含本次传输的参数(源、目的、长度、控制标志)。
  2. DMA 控制器自动从链表头部取描述符,执行传输;完成后自动加载下一个描述符。
  3. 链表可以配置为“循环模式”(Circular Mode),即最后一个描述符指向链表头部,形成无限循环。

这里要特别说一句:描述符链循环模式就是本课程的核心。我当年在优化一个 4K 视频采集驱动时,就靠它把帧间隔抖动从 30 μs 降到了 2 μs 以内。嗯,后面我们会花大篇幅来拆解它的实现细节。

1.7 本章总结(核心知识卡片)

概念 一句话理解
DMA 是什么 硬件数据搬运工,解放 CPU
核心作用 释放算力、降低延迟、支持后台批操作
发展历程 独立芯片 → SoC 集成 → 智能描述符链
嵌入式优势 节约 CPU 资源,提高实时性与吞吐
描述符链循环 预配置传输任务列表,硬件自动串行执行,循环无中断

如果你刚接触 DMA,别急着看寄存器细节。先理解 谁(CPU)委托谁(DMA)做什么(搬数据),脑子里有这个框架,后面所有细节都顺了。

好了,这就是 DMA 从历史到作用的全景。我个人习惯把“描述符链”想象成一条自动化流水线:CPU 是产品经理,DMA 是机器人,描述符就是工序卡片。下一阶段咱们会深入这张卡片的具体结构。