2. DMA控制器硬件架构:内部组成与总线连接

DMA(Direct Memory Access)控制器是系统中负责在内存与外设之间、或内存与内存之间直接传输数据的硬件引擎。理解其内部组成和总线连接方式,是驱动开发者编写高效、稳定DMA驱动的基础。本章将深入剖析DMA控制器的核心模块及其与系统总线的交互机制。

2.1 DMA控制器内部组成

一个典型的DMA控制器由以下关键模块构成:通道(Channel)、请求仲裁(Arbiter)、地址发生器(Address Generator)、控制/状态寄存器组以及数据缓冲(FIFO)。下图展示了其内部架构。

DMA控制器内部组成架构图 DMA控制器内部组成架构 DMA控制器 通道阵列 通道 0 通道 1 通道 2 通道 3 ... 请求仲裁器 优先级调度 固定优先级 / 轮询 延迟保证 地址发生器 源地址 / 目的地址 递增 / 递减 / 固定 地址对齐检查 控制/状态寄存器组 控制寄存器 (CR) 状态寄存器 (SR) 中断状态寄存器 数据缓冲 (FIFO) 深度: 4/8/16 字 突发传输支持 水位线配置

2.1.1 通道(Channel)

每个DMA通道代表一条独立的传输路径。通道内部保存了当前传输所需的上下文信息,包括:

  • 源地址寄存器:数据读取的起始地址。
  • 目的地址寄存器:数据写入的起始地址。
  • 传输计数寄存器:待传输的数据量(字节、半字或字)。
  • 控制配置寄存器:传输方向、地址增减模式、数据宽度、突发长度等。

多通道设计允许DMA控制器同时处理多个独立的数据流,例如同时服务UART接收、SPI发送和定时器捕获。

2.1.2 请求仲裁(Arbiter)

当多个通道同时请求总线访问时,仲裁器决定哪个通道获得当前总线控制权。常见的仲裁策略包括:

仲裁策略 描述 适用场景
固定优先级 通道编号越小优先级越高,高优先级通道可抢占低优先级通道。 实时性要求严格的外设(如音频I2S)。
轮询(Round-Robin) 所有通道轮流获得总线使用权,保证公平性。 多个外设带宽需求相近的场景。
混合策略 高优先级通道使用固定优先级,其余通道使用轮询。 既有实时流又有批量数据传输的系统。
驱动开发提示: 在配置DMA通道优先级时,务必考虑外设的实时性需求。例如,音频数据流应分配高优先级,而低速传感器数据可分配低优先级,避免音频断流。

2.1.3 地址发生器(Address Generator)

地址发生器负责在每次传输后自动更新源地址和目的地址。其支持三种基本模式:

  • 递增模式:地址每次增加一个数据宽度(如4字节),适用于线性缓冲区。
  • 递减模式:地址每次减少一个数据宽度,适用于栈或反向填充。
  • 固定模式:地址保持不变,适用于外设数据寄存器(如UART DR)。

高级DMA控制器还支持地址偏移(Address Offset)和循环缓冲区(Circular Buffer),后者在地址到达边界时自动回绕,非常适合音频和通信协议处理。

2.1.4 数据缓冲(FIFO)

FIFO用于暂存数据,匹配不同总线时钟域或数据宽度。其关键参数包括:

  • 深度:通常为4、8或16个字(32位)。
  • 水位线(Threshold):触发传输请求的填充级别,如半满或全满。
  • 突发传输:当FIFO达到水位线时,DMA发起一次突发传输,提高总线利用率。

2.2 DMA与系统总线的连接方式

DMA控制器通过系统总线与CPU、内存和外设进行数据交换。根据系统架构的不同,常见的连接方式有以下几种。

DMA与系统总线连接架构 DMA与系统总线连接架构 CPU Cortex-A/M/R 内存 DDR / SRAM 系统总线 (AXI / AHB / OCP) 地址总线 + 数据总线 + 控制总线 DMA控制器 主接口 + 从接口 外设 UART / SPI / I2C / GPIO

2.2.1 主接口与从接口

DMA控制器通常具备两种总线接口:

  • 主接口(Master Interface):DMA作为总线主设备,主动发起读写操作。该接口连接到系统总线,用于访问内存和外设地址空间。
  • 从接口(Slave Interface):CPU通过该接口配置DMA控制器的寄存器(如通道参数、启动传输)。该接口通常连接到APB(Advanced Peripheral Bus)或类似的低速外设总线。

2.2.2 总线协议与数据宽度

不同总线协议对DMA传输的支持程度不同:

总线协议 典型位宽 特点 常见应用
AXI 32/64/128位 支持突发传输、乱序传输、多通道并行 高性能SoC(手机、网络处理器)
AHB 32/64位 流水线操作、单周期总线切换 中高端MCU(STM32H7、i.MX RT)
OCP 32/64位 可配置接口、支持多种传输类型 定制SoC、FPGA内部互联
APB 32位 低功耗、简单接口、非流水线 外设寄存器配置(DMA从接口)

2.2.3 内存映射与地址空间

DMA控制器通过主接口直接访问系统地址空间。在驱动开发中,需要关注以下地址映射关系:

  • 内存区域:通常映射到DDR或SRAM的物理地址范围,DMA可读写。
  • 外设区域:外设的寄存器或数据缓冲区映射到特定地址,DMA可直接访问。
  • 一致性/非一致性内存:对于非一致性内存(如DMA使用Cache),驱动需在传输前后执行Cache刷新/无效化操作。
常见陷阱: 某些低端DMA控制器只能访问特定的内存区域(如仅限SRAM,不能访问DDR)。在移植驱动时,务必查阅芯片参考手册中的DMA地址映射范围,否则可能导致传输失败或数据损坏。

2.3 关键寄存器与编程模型

驱动开发者需要操作的核心寄存器包括:

寄存器名称 功能描述 典型位宽
DMA_CR 控制寄存器:使能通道、选择传输方向、数据宽度、突发长度 32位
DMA_SAR 源地址寄存器:存放源数据起始地址 32/64位
DMA_DAR 目的地址寄存器:存放目的数据起始地址 32/64位
DMA_NDTR 传输计数寄存器:剩余待传输数据量(单位:数据宽度) 16/32位
DMA_SR 状态寄存器:传输完成、传输错误、FIFO状态等标志 32位

一个典型的DMA传输初始化流程如下:

/* 伪代码:DMA通道初始化 */
void dma_channel_init(struct dma_channel *ch) {
    // 1. 关闭通道
    writel(0, ch->base + DMA_CR);

    // 2. 设置源地址和目的地址
    writel(ch->src_phys, ch->base + DMA_SAR);
    writel(ch->dst_phys, ch->base + DMA_DAR);

    // 3. 设置传输计数
    writel(ch->transfer_size, ch->base + DMA_NDTR);

    // 4. 配置控制寄存器:方向、数据宽度、突发长度
    uint32_t cr = 0;
    cr |= (ch->dir & 0x3) << DMA_CR_DIR_SHIFT;
    cr |= (ch->data_width & 0x3) << DMA_CR_MSIZE_SHIFT;
    cr |= (ch->burst_len & 0x7) << DMA_CR_BURST_SHIFT;
    writel(cr, ch->base + DMA_CR);

    // 5. 使能通道
    writel(cr | DMA_CR_EN, ch->base + DMA_CR);
}
驱动开发提示: 在配置DMA寄存器时,务必遵循芯片手册中规定的寄存器访问顺序。例如,某些控制器要求先配置地址和计数,最后使能通道;而另一些则要求先使能通道再配置参数。错误的顺序可能导致未定义行为。

2.4 本章小结

DMA控制器的硬件架构决定了驱动开发的底层操作方式。通道提供了并行传输能力,仲裁器管理总线竞争,地址发生器自动更新指针,FIFO平滑数据流。DMA通过主接口连接系统总线(AXI/AHB/OCP)访问内存和外设,通过从接口接收CPU配置。掌握这些硬件细节,是后续实现分散收集、内存映射优化等高级特性的前提。