1. DMA控制器概述

1.1 DMA工作原理

直接存储器访问(Direct Memory Access, DMA)是一种允许外设或存储器之间直接传输数据而无需CPU干预的硬件机制。DMA控制器作为系统总线上的独立主设备,在获得总线控制权后,可以自主完成数据搬运任务。

核心思想:CPU只需初始化传输参数(源地址、目的地址、传输长度),DMA控制器即可独立完成后续所有数据传输操作,传输完成后通过中断通知CPU。
DMA基本工作原理流程图 CPU DMA控制器 存储器 外设 ① 配置参数 ② 请求总线 ③ 读数据 ④ 写数据 ⑤ 完成中断 说明: CPU仅在步骤①和步骤⑤参与,步骤②~④的数据搬运完全由DMA控制器自主完成,实现CPU计算与数据传输的并行。

1.2 DMA在嵌入式系统中的作用

在嵌入式系统中,DMA控制器扮演着数据搬运引擎的角色,其核心价值体现在以下几个方面:

应用场景 DMA作用 典型示例
高速数据采集 ADC采样数据直接存入内存,不占用CPU 音频采集、传感器数据流
显示刷新 帧缓冲区数据自动传输到显示控制器 LCD/OLED屏幕刷新
存储设备访问 SD卡/eMMC数据块搬运 文件系统读写
网络数据包处理 以太网MAC与内存之间的数据帧传输 TCP/IP协议栈
存储器间拷贝 内存到内存的大块数据复制 图像处理、数据缓冲
关键指标:DMA传输速率通常以字节/秒或传输次数/秒衡量。在嵌入式Linux系统中,DMA带宽可达数百MB/s至数GB/s,具体取决于总线架构(如AXI、AHB、PCIe)和DMA引擎设计。

1.3 DMA与CPU的数据搬运对比

理解DMA与CPU在数据搬运上的差异,是驱动开发的基础。以下从多个维度进行对比:

对比维度 CPU搬运 DMA搬运
执行主体 CPU核心(如ARM Cortex-A7) DMA控制器硬件状态机
并行能力 搬运期间CPU无法执行其他任务 CPU可并行执行计算任务
传输速率 受限于CPU指令执行速度 接近总线理论带宽
适用场景 小数据量(< 64字节)、频繁随机访问 大数据块(≥ 64字节)、流式传输
编程复杂度 简单,直接使用memcpy/循环 需配置描述符、处理中断、管理缓冲区
功耗 较高(CPU持续活跃) 较低(专用硬件,CPU可休眠)
CPU搬运 vs DMA搬运 时序对比 CPU搬运模式: CPU搬运数据 CPU处理数据 CPU搬运数据 CPU处理数据 → CPU在搬运期间无法处理数据,总耗时 = 搬运时间 + 处理时间 DMA搬运模式: DMA搬运数据 DMA搬运数据 DMA搬运数据 CPU并行处理数据 CPU并行处理数据 CPU并行处理数据 → DMA搬运与CPU处理完全并行,总耗时 ≈ max(搬运时间, 处理时间) 结论:对于大数据量、流式传输场景,DMA搬运可节省50%以上的CPU时间,显著提升系统吞吐量。

1.4 DMA传输的基本要素

一个完整的DMA传输涉及以下核心要素:

  1. 传输方向:内存→外设(写)、外设→内存(读)、内存→内存(拷贝)
  2. 源地址与目的地址:物理地址,支持递增/固定模式
  3. 传输宽度:字节(8-bit)、半字(16-bit)、字(32-bit)或双字(64-bit)
  4. 传输计数:一次DMA请求传输的数据单元数量
  5. 触发方式:软件触发、硬件外设请求触发、链式描述符触发
  6. 中断条件:传输完成、传输错误、半传输完成等
驱动开发注意:DMA操作涉及物理地址,用户空间虚拟地址必须经过内核API(如dma_map_single)转换为总线地址后才能使用。错误的地址映射会导致数据损坏或系统崩溃。

1.5 典型DMA控制器架构

以ARM PrimeCell DMA控制器(PL080/PL081)为例,其内部结构包含以下关键模块:

典型DMA控制器内部架构 AHB/AXI总线接口 DMA控制逻辑 通道仲裁器 中断控制 通道0(描述符) 通道1(描述符) 通道2(描述符)

各模块功能说明:

  • 总线接口:负责与系统总线(AHB/AXI)交互,发起读写传输
  • 控制逻辑:解析描述符、管理传输状态、处理错误
  • 通道仲裁器:多通道并发时决定优先级,支持轮询或固定优先级
  • 中断控制:根据传输状态产生中断信号给中断控制器(GIC)
  • 描述符通道:每个通道维护一个描述符链表,支持链式传输

1.6 描述符接口简介

现代DMA控制器普遍采用描述符(Descriptor)接口,替代传统的寄存器直接编程方式。描述符是一个内存中的数据结构,包含传输所需的所有参数:

struct dma_descriptor {
    uint32_t src_addr;      // 源物理地址
    uint32_t dst_addr;      // 目的物理地址
    uint32_t transfer_size; // 传输字节数
    uint32_t ctrl;          // 控制标志(中断使能、传输类型等)
    uint32_t next;          // 下一个描述符指针(链表)
};
描述符接口优势:
  • 支持链式传输:多个描述符组成链表,DMA自动依次执行
  • 支持循环缓冲:描述符链表首尾相连,适用于连续数据流
  • 支持分散-聚集:不连续的内存块可以合并传输
  • 减少CPU干预:一次配置可完成大量传输任务