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 机制为系统级数据搬运带来了三个核心优势:
- CPU 卸载: 传输期间 CPU 可执行调度、计算、中断响应等任务,系统吞吐量显著提升。实测表明,在 1 Gbps 网络环境下,使用 DMA 的网卡驱动可将 CPU 占用率从 95% 降至 15% 以下。
- 高带宽利用: DMA 控制器支持突发传输(Burst Transfer),一次总线仲裁后可连续传输多个数据字,减少总线仲裁开销,使有效带宽接近理论峰值。
- 低延迟与确定性: 硬件状态机直接驱动传输,无需指令取指、译码、执行等流水线延迟,传输延迟可预测,适合音频、视频等实时流应用。
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 请求 (DREQ)”信号线在硬件层面可能是边沿触发或电平触发。在驱动中配置 DMA 描述符时,必须根据外设手册正确设置请求类型和极性,否则会导致传输提前终止或数据错位。
1.6 DMA 传输的基本流程
一次完整的 DMA 传输在驱动层面通常遵循以下步骤:
- 描述符准备: 驱动在内存中分配描述符(Descriptor),填写源地址、目的地址、传输长度、控制标志(如中断使能、链式标记)。
- 描述符提交: 将描述符链的首地址写入 DMA 控制器的描述符基址寄存器,并设置启动位。
- 硬件自动搬运: DMA 控制器按描述符链顺序逐条执行传输,每完成一条自动加载下一条,直到链尾。
- 传输完成通知: 最后一条描述符若设置了中断标志,DMA 控制器向 CPU 发出中断,驱动在中断处理函数中回收描述符并通知上层。
关键设计原则: 描述符链管理是 DMA 驱动开发的核心复杂度所在。优秀的驱动会采用“双缓冲”或“环形队列”策略,在中断处理中预分配新的描述符,避免 CPU 等待描述符资源而阻塞数据流。