3. DMA控制器硬件原理

DMA(Direct Memory Access)控制器是系统中负责在外设与内存、内存与内存之间直接传输数据的硬件引擎。理解其内部组成与寄存器模型,是进行驱动开发和性能调优的基础。本章将深入剖析DMA控制器的核心硬件结构。

3.1 DMA控制器内部组成

一个典型的DMA控制器由以下功能单元构成,它们协同工作以完成一次完整的传输事务。

核心组成单元:
  • 控制逻辑单元(Control Logic): 解析CPU写入的控制寄存器,生成状态机,协调各模块工作。
  • 地址生成单元(Address Generation Unit, AGU): 管理源地址寄存器和目的地址寄存器,支持递增、递减或固定模式。
  • 传输计数单元(Transfer Counter): 维护传输计数寄存器,每次传输后递减,计数归零时触发中断或链式传输。
  • 数据缓冲单元(Data Buffer / FIFO): 暂存数据以匹配不同总线宽度,支持突发传输(Burst Transfer)。
  • 总线接口单元(Bus Interface Unit, BIU): 负责与系统总线(AHB/AXI/OCP)握手,发起读/写事务。
  • 通道仲裁器(Channel Arbiter): 多通道DMA中,根据优先级策略选择下一个服务的通道。
DMA控制器内部组成框图 DMA控制器内部组成框图 DMA控制器 控制逻辑单元 状态机 / 配置解析 地址生成单元 源/目的地址管理 传输计数单元 计数递减 / 完成判断 数据缓冲单元 FIFO / 宽度匹配 总线接口单元 AHB/AXI 握手 通道仲裁器 优先级 / 轮询调度 说明:各单元通过内部总线连接,控制逻辑单元作为主控协调其他单元的工作时序。 多通道DMA中,每个通道拥有独立的地址和计数寄存器,共享仲裁器与总线接口。

3.2 源/目的地址寄存器

地址寄存器决定了DMA传输的数据从何处读取、写入何处。根据硬件设计,地址寄存器支持多种寻址模式。

寄存器 功能 典型位宽 寻址模式
源地址寄存器(SAR) 存储数据源地址(内存或外设FIFO地址) 32位 / 64位 递增、递减、固定
目的地址寄存器(DAR) 存储数据目的地址(内存或外设FIFO地址) 32位 / 64位 递增、递减、固定
实战要点: 外设到内存传输时,源地址通常固定(指向外设数据寄存器),目的地址递增(写入内存缓冲区)。内存到外设传输则相反。地址对齐(Alignment)对性能影响显著,建议源和目的地址均按传输宽度对齐。

3.3 传输计数寄存器

传输计数寄存器(Transfer Count Register, TCR)记录待传输的数据单元数量。每次传输完成后,硬件自动递减该寄存器值。

  • 初始值设置: 由驱动程序在启动DMA前写入,表示本次传输的总数据量(以字节、半字或字为单位)。
  • 递减机制: 每完成一次数据单元传输,TCR减1。当TCR减至0时,触发传输完成中断或启动链式描述符中的下一段传输。
  • 链式传输支持: 高级DMA控制器支持多个描述符链表,每个描述符包含独立的TCR,实现连续大块数据的分段传输。
传输计数寄存器工作流程 传输计数寄存器工作流程 CPU写入TCR初始值 例如:TCR = 1024 启动DMA传输 硬件开始搬运数据 每次传输后TCR-- TCR = 1023, 1022, ... TCR == 0 ? 判断是否完成 触发完成中断 通知CPU传输结束 TCR > 0 继续传输

3.4 控制寄存器

控制寄存器(Control Register, CR)是DMA引擎的“大脑”,驱动通过写入该寄存器来配置传输模式、触发启动、查询状态。

位域 名称 功能描述
[0] ENABLE 通道使能位,置1启动传输,传输完成后硬件自动清零
[1] INT_EN 中断使能,置1允许传输完成或错误时触发中断
[3:2] TRANSFER_TYPE 00: 内存到内存;01: 内存到外设;10: 外设到内存;11: 外设到外设
[5:4] BURST_SIZE 突发传输大小:00: 1字节;01: 4字节;10: 8字节;11: 16字节
[7:6] ADDR_MODE 地址模式:00: 递增;01: 递减;10: 固定;11: 保留
[8] CHAIN_EN 链式描述符使能,置1启用链表传输模式
[31:16] STATUS 状态位(只读):传输完成、总线错误、描述符错误等
常见陷阱: 在修改控制寄存器前,必须先确保ENABLE位为0(通道已停止)。在传输进行中写入控制寄存器可能导致状态机紊乱。正确的操作序列为:读状态 → 确认空闲 → 写配置 → 写地址/计数 → 置位ENABLE。

3.5 寄存器编程示例

以下是一个简化的DMA初始化代码片段,展示如何配置寄存器以完成一次外设到内存的传输。

/* 伪代码:DMA控制器寄存器编程示例 */
#define DMA_BASE_ADDR  0x1C000000
#define DMA_SAR        (DMA_BASE_ADDR + 0x00)  /* 源地址寄存器 */
#define DMA_DAR        (DMA_BASE_ADDR + 0x04)  /* 目的地址寄存器 */
#define DMA_TCR        (DMA_BASE_ADDR + 0x08)  /* 传输计数寄存器 */
#define DMA_CR         (DMA_BASE_ADDR + 0x0C)  /* 控制寄存器 */

void dma_start_periph_to_mem(uint32_t periph_addr, uint32_t mem_addr, uint32_t count)
{
    /* 1. 确保DMA通道已停止 */
    while (readl(DMA_CR) & 0x1);

    /* 2. 配置源地址(外设地址,固定模式) */
    writel(periph_addr, DMA_SAR);

    /* 3. 配置目的地址(内存地址,递增模式) */
    writel(mem_addr, DMA_DAR);

    /* 4. 设置传输计数(以字为单位) */
    writel(count, DMA_TCR);

    /* 5. 配置控制寄存器:
     *    - 传输类型: 外设到内存 (0x04)
     *    - 突发大小: 4字节 (0x10)
     *    - 地址模式: 源固定 + 目的递增 (0x00)
     *    - 中断使能: 开启 (0x02)
     *    - 通道使能: 开启 (0x01)
     */
    uint32_t cr = (0x04 << 2) | (0x01 << 4) | (0x00 << 6) | (0x01 << 1) | 0x01;
    writel(cr, DMA_CR);
}
性能提示: 突发传输大小(BURST_SIZE)的选择直接影响总线利用率。对于高速外设(如以太网MAC、USB控制器),建议使用8字节或16字节突发以降低总线仲裁开销。但突发过大可能阻塞其他低延迟外设的访问,需根据系统负载权衡。

3.6 寄存器配置与性能关系

寄存器的配置不仅决定传输的正确性,更直接影响DMA的吞吐量和延迟。下表总结了关键配置项对性能的影响。

配置项 推荐值 性能影响
突发大小 8 ~ 16字节 增大突发可减少总线事务开销,提升吞吐量
地址对齐 按传输宽度对齐 未对齐地址会导致硬件拆分事务,性能下降30%~50%
中断使能 批量传输时关闭 频繁中断增加CPU负载,建议使用轮询或链式传输
传输计数 尽量大(不超过硬件限制) 单次传输数据量越大,DMA启动/停止开销占比越低