2. DMA 硬件架构:控制器、通道与请求机制
DMA(Direct Memory Access)硬件架构是驱动开发与内存管理优化的物理基础。理解 DMA 控制器内部结构、通道(Channel)与请求(Request)机制、以及源地址与目的地址寄存器的运作原理,是编写高效、稳定 DMA 驱动的第一步。本章将从硬件寄存器级视角,拆解 DMA 引擎的核心组件。
2.1 DMA 控制器内部结构
一个典型的 DMA 控制器内部由多个功能单元组成,它们协同完成从请求仲裁到数据传输的全流程。下图展示了标准 DMA 控制器的内部模块划分与数据通路。
DMA 控制器内部主要包含以下关键模块:
| 模块 | 功能描述 | 驱动关注点 |
|---|---|---|
| 控制与状态寄存器组 | 管理全局使能、中断状态、错误标志、传输类型(内存-内存/内存-外设) | 初始化时配置传输模式;中断处理时读取状态位清除错误 |
| 通道仲裁器 | 在多个活跃通道间仲裁总线使用权,支持固定优先级或轮询调度 | 高优先级通道用于实时外设(如音频);避免低优先级通道饿死 |
| 通道阵列 | 每个通道独立拥有源地址寄存器(SAR)、目的地址寄存器(DAR)、传输计数寄存器(CBR) | 驱动为每个传输任务分配独立通道;通道复用需保存/恢复上下文 |
| 总线主控接口 | 作为总线主设备发起读写事务,支持突发传输(Burst)和地址递增模式 | 配置突发长度以匹配系统缓存行大小;地址对齐影响传输效率 |
| 外设请求接口 | 接收外设的 DMA 请求信号(DREQ),返回应答信号(DACK) | 外设驱动需正确断言 DREQ;DMA 驱动需配置请求极性及握手协议 |
2.2 通道(Channel)与请求(Request)机制
通道是 DMA 控制器内部独立的硬件执行单元,每个通道可以独立配置并执行一次数据传输任务。请求机制则定义了外设如何触发 DMA 传输。
2.2.1 通道的生命周期与状态机
一个 DMA 通道从配置到完成传输,经历以下状态转换:
- 空闲(Idle):通道未配置,寄存器为默认值。
- 配置(Configured):驱动写入 SAR、DAR、CBR 及控制字,通道就绪。
- 等待请求(Waiting for Request):使能通道后,等待外设 DREQ 或软件触发。
- 传输中(Transferring):获得总线控制权,逐字节或逐突发传输数据。
- 完成(Completed):CBR 递减至零,触发中断或设置完成标志。
- 错误(Error):总线错误、地址对齐异常或超时,进入错误状态。
2.2.2 请求类型与触发方式
DMA 请求分为硬件请求和软件请求两大类,具体差异如下表:
| 请求类型 | 触发源 | 典型应用场景 | 驱动配置要点 |
|---|---|---|---|
| 硬件请求(Hardware DMA Request) | 外设引脚 DREQ 电平/边沿 | UART RX/TX、SPI、I2S 音频、ADC 采样 | 配置请求极性(高电平/上升沿)、请求屏蔽、外设编号映射 |
| 软件请求(Software DMA Request) | 写触发寄存器(SWT) | 内存-内存拷贝、校验和计算、加密加速 | 无需外设参与;注意软件触发后需轮询完成标志 |
| 链式请求(Linked List / Descriptor) | 前一个传输完成自动触发下一个 | 高速数据流(以太网、视频帧)、环形缓冲区 | 配置描述符链表;注意内存一致性(Cache Coherency) |
2.2.3 多通道仲裁与优先级
当多个通道同时请求传输时,仲裁器决定总线使用权。常见仲裁策略:
- 固定优先级(Fixed Priority):通道编号越小优先级越高。适用于实时性要求严格的外设(如音频播放)。
- 轮询(Round-Robin):所有通道平等共享总线带宽。适用于多个非实时外设同时工作。
- 混合模式(Hybrid):高优先级通道使用固定优先级,其余通道使用轮询。
2.3 源地址与目的地址寄存器
源地址寄存器(SAR)和目的地址寄存器(DAR)是每个 DMA 通道最核心的配置字段。它们决定了数据从哪里来、到哪里去,以及地址如何更新。
2.3.1 地址寄存器结构
典型的 32 位 DMA 控制器中,SAR 和 DAR 为 32 位宽,支持 8/16/32 位数据宽度。部分高端控制器(如 ARM PL330)支持 64 位地址。寄存器位域定义如下:
// 以 32 位 DMA 控制器为例
struct dma_channel_regs {
uint32_t sar; // 源地址寄存器 (Source Address Register)
uint32_t dar; // 目的地址寄存器 (Destination Address Register)
uint32_t cbr; // 传输计数寄存器 (Count Byte Register)
uint32_t cr; // 控制寄存器 (Control Register)
uint32_t sr; // 状态寄存器 (Status Register)
};
// 控制寄存器关键位域
#define DMA_CR_SRC_INC (1 << 0) // 源地址递增
#define DMA_CR_DST_INC (1 << 1) // 目的地址递增
#define DMA_CR_SRC_WIDTH (1 << 2) // 源数据宽度: 0=8bit, 1=32bit
#define DMA_CR_DST_WIDTH (1 << 3) // 目的数据宽度
#define DMA_CR_BURST_LEN (0x7 << 4) // 突发长度 (0=1, 1=4, 2=8, 3=16)
#define DMA_CR_CH_EN (1 << 31) // 通道使能
2.3.2 地址更新模式
每次传输后,SAR 和 DAR 的更新行为由控制寄存器中的递增/递减标志决定。常见模式:
| 模式 | 源地址更新 | 目的地址更新 | 典型场景 |
|---|---|---|---|
| 内存到内存 | 递增(+数据宽度) | 递增(+数据宽度) | memcpy、数据搬移 |
| 外设到内存 | 固定(外设 FIFO 地址不变) | 递增 | UART 接收、ADC 采样 |
| 内存到外设 | 递增 | 固定(外设 FIFO 地址不变) | SPI 发送、DAC 输出 |
| 外设到外设 | 固定 | 固定 | 数字信号处理(DSP)链路 |
| 循环模式(Ring Buffer) | 递增,到达边界回绕 | 递增,到达边界回绕 | 音频环形缓冲区、网络描述符 |
2.3.3 地址对齐与性能
地址对齐直接影响 DMA 传输效率。大多数 DMA 控制器要求源地址和目的地址对齐到数据宽度:
- 8 位宽度:无对齐要求。
- 16 位宽度:地址必须 2 字节对齐。
- 32 位宽度:地址必须 4 字节对齐。
- 64 位宽度:地址必须 8 字节对齐。
dma_set_addr_alignment() 或手动检查地址低位。
2.3.4 传输计数寄存器(CBR)与传输完成
CBR 记录剩余待传输的字节数。每次传输后,CBR 递减实际传输的字节数。当 CBR 减至 0 时,通道自动停止并触发完成中断。驱动需注意:
- 初始值:必须等于实际传输字节数,而非数据项个数。
- 重载:在循环模式下,CBR 到达 0 后自动重载初始值。
- 暂停与恢复:读取 CBR 当前值可获取传输进度,用于暂停后恢复。
// 配置 DMA 通道传输 1024 字节,32 位宽度
#define BUF_SIZE 1024
#define DATA_WIDTH 4 // 32-bit
dma_channel_regs->sar = (uint32_t)src_buf;
dma_channel_regs->dar = (uint32_t)dst_buf;
dma_channel_regs->cbr = BUF_SIZE; // 字节数
dma_channel_regs->cr = DMA_CR_SRC_INC | DMA_CR_DST_INC |
DMA_CR_SRC_WIDTH | DMA_CR_DST_WIDTH |
(0x2 << 4) | // 突发长度 4
DMA_CR_CH_EN;
2.4 本章小结
DMA 硬件架构是驱动开发与内存管理优化的基石。理解控制器内部模块划分、通道状态机、请求触发方式以及地址寄存器的更新模式,能够帮助开发者:
- 正确初始化 DMA 通道,避免地址对齐和配置错误。
- 合理分配通道优先级,满足实时外设的延迟要求。
- 利用地址递增/固定模式,适配不同外设的传输需求。
- 通过 CBR 监控传输进度,实现暂停、恢复和错误恢复。