2. DMA控制器硬件架构:内部组成与总线连接
DMA(Direct Memory Access)控制器是系统中负责在内存与外设之间、或内存与内存之间直接传输数据的硬件引擎。理解其内部组成和总线连接方式,是驱动开发者编写高效、稳定DMA驱动的基础。本章将深入剖析DMA控制器的核心模块及其与系统总线的交互机制。
2.1 DMA控制器内部组成
一个典型的DMA控制器由以下关键模块构成:通道(Channel)、请求仲裁(Arbiter)、地址发生器(Address Generator)、控制/状态寄存器组以及数据缓冲(FIFO)。下图展示了其内部架构。
2.1.1 通道(Channel)
每个DMA通道代表一条独立的传输路径。通道内部保存了当前传输所需的上下文信息,包括:
- 源地址寄存器:数据读取的起始地址。
- 目的地址寄存器:数据写入的起始地址。
- 传输计数寄存器:待传输的数据量(字节、半字或字)。
- 控制配置寄存器:传输方向、地址增减模式、数据宽度、突发长度等。
多通道设计允许DMA控制器同时处理多个独立的数据流,例如同时服务UART接收、SPI发送和定时器捕获。
2.1.2 请求仲裁(Arbiter)
当多个通道同时请求总线访问时,仲裁器决定哪个通道获得当前总线控制权。常见的仲裁策略包括:
| 仲裁策略 | 描述 | 适用场景 |
|---|---|---|
| 固定优先级 | 通道编号越小优先级越高,高优先级通道可抢占低优先级通道。 | 实时性要求严格的外设(如音频I2S)。 |
| 轮询(Round-Robin) | 所有通道轮流获得总线使用权,保证公平性。 | 多个外设带宽需求相近的场景。 |
| 混合策略 | 高优先级通道使用固定优先级,其余通道使用轮询。 | 既有实时流又有批量数据传输的系统。 |
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、内存和外设进行数据交换。根据系统架构的不同,常见的连接方式有以下几种。
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刷新/无效化操作。
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);
}
2.4 本章小结
DMA控制器的硬件架构决定了驱动开发的底层操作方式。通道提供了并行传输能力,仲裁器管理总线竞争,地址发生器自动更新指针,FIFO平滑数据流。DMA通过主接口连接系统总线(AXI/AHB/OCP)访问内存和外设,通过从接口接收CPU配置。掌握这些硬件细节,是后续实现分散收集、内存映射优化等高级特性的前提。