1. DMA 基础概念

1.1 DMA 定义

直接存储器访问(Direct Memory Access,DMA) 是一种允许硬件设备(如磁盘控制器、网卡、声卡、GPU)直接与系统内存进行数据交换,而无需 CPU 介入的硬件机制。DMA 控制器(DMAC)作为独立的总线主控设备,在系统总线上与 CPU 并行工作,负责管理数据传输的启动、执行和完成。

核心要点: DMA 的本质是“硬件代理数据搬运”,将 CPU 从繁重的数据拷贝任务中解放出来,使其专注于计算与控制逻辑。

1.2 DMA 与 CPU 数据搬运的区别

传统数据搬运由 CPU 通过加载(Load)和存储(Store)指令逐字节或逐字完成,而 DMA 则通过专用硬件通道批量传输。下表从多个维度对比两者的差异:

对比维度 CPU 数据搬运(PIO 模式) DMA 数据搬运
执行主体 CPU 核心(执行 Load/Store 指令) DMA 控制器(独立总线主控)
数据路径 外设 → CPU 寄存器 → 内存 外设 → 内存(或内存 ↔ 内存)
CPU 占用率 100%(搬运期间无法执行其他任务) 仅初始化时占用,传输过程 CPU 可并行工作
传输粒度 字节/字(逐次) 块(批量,可配置突发长度)
传输速率 受限于 CPU 时钟和指令吞吐 接近总线带宽上限
适用场景 小数据量、低频次、控制类交互 大数据量、高频次、实时流传输
软件开销 每字节/字均需指令开销 仅描述符链管理及中断处理
开发经验: 在嵌入式 Linux 驱动中,对于小于 64 字节的零星数据(如 GPIO 状态读取),PIO 模式反而更高效,因为 DMA 描述符链的建立和同步开销会超过直接搬运的收益。阈值通常需要根据实际总线延迟和 DMA 延迟实测确定。

1.3 DMA 传输的优势

DMA 机制为系统级数据搬运带来了三个核心优势:

  1. CPU 卸载: 传输期间 CPU 可执行调度、计算、中断响应等任务,系统吞吐量显著提升。实测表明,在 1 Gbps 网络环境下,使用 DMA 的网卡驱动可将 CPU 占用率从 95% 降至 15% 以下。
  2. 高带宽利用: DMA 控制器支持突发传输(Burst Transfer),一次总线仲裁后可连续传输多个数据字,减少总线仲裁开销,使有效带宽接近理论峰值。
  3. 低延迟与确定性: 硬件状态机直接驱动传输,无需指令取指、译码、执行等流水线延迟,传输延迟可预测,适合音频、视频等实时流应用。

1.4 典型应用场景

DMA 在嵌入式系统和 Linux 内核驱动中无处不在,以下是几个最具代表性的场景:

应用领域 典型设备 DMA 角色 带宽需求
网络通信 以太网 MAC / WiFi 将接收到的网络帧直接从 FIFO 搬入内存 Ring Buffer 100 Mbps ~ 100 Gbps
存储系统 eMMC / SD / NVMe 将块设备数据在内存与控制器之间批量传输 400 MB/s ~ 14 GB/s
多媒体处理 摄像头 ISP / 音频 Codec 将帧数据从传感器直接送入内存或 GPU 显存 1080p@60fps 约 3 Gbps
加速器协同 GPU / NPU / FPGA 在主机内存与设备显存/BRAM 之间搬运计算数据 PCIe Gen4 x16 约 32 GB/s
数据采集 ADC / SPI / I2S 将采样数据连续搬入循环缓冲区,避免 CPU 轮询 1 MSPS ~ 100 MSPS

1.5 DMA 系统架构示意

下图展示了一个典型的嵌入式 DMA 系统架构,包含 CPU、DMA 控制器、外设和内存之间的数据流与控制流关系:

DMA 系统架构框图 CPU 核心 (控制/中断处理) DMA 控制器 (描述符链引擎) 系统内存 (Buffer / Ring) 外设设备 (FIFO / 寄存器) 配置描述符 DMA 数据读/写 外设数据请求 DMA 请求 (DREQ) 中断通知 (IRQ) 控制/配置路径 DMA 引擎 数据存储 外设接口
驱动开发注意: 上图中的“DMA 请求 (DREQ)”信号线在硬件层面可能是边沿触发或电平触发。在驱动中配置 DMA 描述符时,必须根据外设手册正确设置请求类型和极性,否则会导致传输提前终止或数据错位。

1.6 DMA 传输的基本流程

一次完整的 DMA 传输在驱动层面通常遵循以下步骤:

  1. 描述符准备: 驱动在内存中分配描述符(Descriptor),填写源地址、目的地址、传输长度、控制标志(如中断使能、链式标记)。
  2. 描述符提交: 将描述符链的首地址写入 DMA 控制器的描述符基址寄存器,并设置启动位。
  3. 硬件自动搬运: DMA 控制器按描述符链顺序逐条执行传输,每完成一条自动加载下一条,直到链尾。
  4. 传输完成通知: 最后一条描述符若设置了中断标志,DMA 控制器向 CPU 发出中断,驱动在中断处理函数中回收描述符并通知上层。
关键设计原则: 描述符链管理是 DMA 驱动开发的核心复杂度所在。优秀的驱动会采用“双缓冲”或“环形队列”策略,在中断处理中预分配新的描述符,避免 CPU 等待描述符资源而阻塞数据流。

1.7 小结