3. DMA控制器硬件原理:内部结构、通道、请求线与传输粒度

DMA(Direct Memory Access)控制器是系统中负责在内存与外设之间、或内存与内存之间直接搬运数据的硬件引擎。理解其内部结构、通道分配、请求线机制以及传输粒度,是编写高效DMA驱动的理论基础。本章从硬件微架构出发,逐一拆解这些核心概念。

3.1 DMA控制器内部结构

一个典型的DMA控制器内部由多个功能模块组成,它们协同完成一次完整的DMA传输。下图展示了DMA控制器的核心架构:

DMA控制器内部结构框图 DMA控制器内部结构框图 主控状态机 (FSM) 地址生成单元 (AGU) 传输计数单元 (TCU) 数据缓冲FIFO (FIFO) 通道寄存器组 (CH_REGS) 通道仲裁器 (ARBITER) 系统总线接口 (AHB/AXI/OCP) 说明: 主控状态机协调各单元工作;AGU生成源/目的地址;TCU管理剩余字节数;FIFO缓冲数据;通道寄存器组保存每个通道的配置;仲裁器决定多通道优先级。

各模块功能说明:

模块功能描述驱动关注点
主控状态机 (FSM)控制DMA传输的完整生命周期:空闲→请求→读→写→计数更新→完成/中断状态寄存器读取、超时处理
地址生成单元 (AGU)根据源/目的地址、增量模式、地址宽度,自动生成下一次访问地址地址对齐、增量/固定模式配置
传输计数单元 (TCU)记录剩余待传输字节数,传输完成后触发中断或链式传输计数寄存器初始化和读取
数据缓冲FIFO暂存从源端读取的数据,等待写入目的端;深度决定突发能力FIFO阈值、水线配置
通道寄存器组每个通道独立保存源地址、目的地址、传输计数、控制配置通道描述符的编程接口
通道仲裁器多通道同时请求时,按固定优先级或轮询策略选择下一个服务通道优先级分配、避免低优先级饿死
系统总线接口与系统总线(AHB/AXI/OCP)握手,发起读/写传输事务总线协议适配、突发类型设置
驱动提示: 在初始化DMA控制器时,务必先复位状态机,再配置通道寄存器。部分控制器在状态机处于忙状态时,写通道寄存器会导致未定义行为。

3.2 DMA通道:独立的数据搬运路径

DMA通道(Channel)是控制器内部一条独立的、可编程的数据搬运路径。每个通道拥有自己的一组寄存器,可以独立配置源地址、目的地址、传输方向和触发方式。多通道的存在使得DMA控制器能够同时服务多个外设或内存区域。

通道的典型生命周期如下:

  1. 空闲(Idle):通道未配置或已完成传输,等待软件或硬件触发。
  2. 配置(Configured):软件写入通道描述符,设置源/目的地址、传输计数、控制标志。
  3. 请求(Requested):外设发出DMA请求,或软件手动启动通道。
  4. 传输中(Active):控制器执行读→写循环,AGU和TCU持续更新。
  5. 完成(Completed):TCU计数归零,触发中断或链式跳转到下一个描述符。
DMA通道状态机 DMA通道状态机 空闲 配置 请求 传输中 完成 注:从“完成”状态可自动跳回“空闲”(单次模式)或跳转到下一个描述符(链式模式)。
通道数量与系统设计: 嵌入式SoC中DMA通道数通常为4~32个。驱动开发时需注意:
• 通道是稀缺资源,使用前需申请,使用后及时释放。
• 部分控制器支持通道复用(多个外设共享一个通道),需通过请求线映射配置。

3.3 DMA请求线:外设与DMA的握手信号

DMA请求线(DMA Request Line)是外设向DMA控制器发起数据传输请求的硬件信号线。每个外设(如UART、SPI、I2S、ADC)在准备好发送或接收数据时,会通过专用的请求线通知DMA控制器。

请求线的典型工作流程:

  • 硬件请求(Hardware Request):外设的RX FIFO非空或TX FIFO空时,拉高DMA请求信号。
  • DMA响应:DMA控制器检测到请求后,通过仲裁器选择通道,发起总线读/写事务。
  • 请求清除:DMA完成一次传输后,外设自动清除请求信号(或由DMA控制器回读清除)。
  • 软件请求(Software Request):驱动通过写寄存器手动触发DMA传输,用于内存到内存的拷贝。
请求类型触发源典型应用驱动配置
硬件请求外设硬件信号UART RX/TX、SPI、I2S、ADC设置通道与外设请求线映射
软件请求CPU写寄存器内存拷贝、数据搬移设置通道为软件触发模式
外部中断触发GPIO中断低速传感器数据采集中断服务程序中启动DMA
定时器触发定时器PWM/比较输出周期性数据采样定时器输出连接DMA请求线
DMA请求线连接示意图 DMA请求线连接示意图 外设 (UART/SPI/I2S) DMA_REQ DMA控制器 (请求检测+仲裁) 总线事务 内存 (SRAM/DDR) DMA_ACK DMA_REQ由外设驱动,DMA_ACK由DMA控制器输出。握手完成后,DMA通过总线直接读写外设数据寄存器或内存。
常见陷阱: 外设的DMA请求信号可能是电平触发或边沿触发。电平触发模式下,若DMA响应不及时,外设可能覆盖数据;边沿触发则需确保请求脉冲宽度满足DMA采样时序。驱动开发时务必查阅外设和DMA控制器的数据手册,确认请求信号类型。

3.4 传输粒度:字节、字、突发与对齐

传输粒度(Transfer Granularity)定义了DMA每次总线事务搬运的数据量。粒度的选择直接影响总线带宽利用率和外设FIFO的匹配程度。

常见的传输粒度包括:

  • 字节(8-bit):每次传输1字节,适用于串行通信外设(如UART)。
  • 半字(16-bit):每次传输2字节,适用于16位外设(如I2S)。
  • 字(32-bit):每次传输4字节,适用于32位外设和内存。
  • 双字(64-bit):每次传输8字节,适用于64位总线系统。
  • 突发(Burst):连续传输多个数据单元(如4字、8字、16字突发),最大化总线利用率。
粒度数据宽度总线事务数适用场景对齐要求
字节8-bitN次UART、低速传感器无
半字16-bitN/2次I2S、16位ADC2字节对齐
字32-bitN/4次SPI、内存拷贝4字节对齐
双字64-bitN/8次DDR、高速数据流8字节对齐
突发44×32-bitN/16次AXI总线、图像处理16字节对齐
突发88×32-bitN/32次高性能DMA32字节对齐
传输粒度对比:单次传输 vs 突发传输 传输粒度对比:单次传输 vs 突发传输 单次传输(字粒度) 字0 字1 字2 字3 4次总线事务,每次1字 突发传输(4字突发) 字0 | 字1 | 字2 | 字3 1次总线事务,4字连续 对齐规则: • 源地址和目的地址必须与传输粒度对齐(如32位传输要求4字节对齐)。 • 突发传输要求起始地址对齐到突发长度×数据宽度(如4字突发要求16字节对齐)。 • 不对齐的地址会导致DMA降级为单次传输,或触发总线错误。
驱动开发最佳实践:
• 优先使用与外设FIFO深度匹配的突发粒度,减少总线占用。
• 内存到内存的DMA传输,使用最大支持的突发长度以获得最高吞吐。
• 如果源和目的地址对齐要求不同,以更严格的一方为准。
• 在设备树或平台数据中声明DMA的粒度能力,避免运行时动态计算。

3.5 关键寄存器与编程模型

DMA控制器的编程接口通常包含以下几类寄存器,驱动通过读写这些寄存器来配置和控制DMA传输:

寄存器类别典型寄存器位宽驱动操作
控制寄存器DMA_CR32-bit使能/复位控制器、设置优先级策略
状态寄存器DMA_SR32-bit读取通道忙状态、错误标志
中断状态寄存器DMA_ISR32-bit判断哪个通道传输完成或出错
中断清除寄存器DMA_ICR32-bit写1清除对应中断标志
通道源地址寄存器CHx_SAR32/64-bit设置源起始地址
通道目的地址寄存器CHx_DAR32/64-bit设置目的起始地址
通道传输计数寄存器CHx_TCNT16/32-bit设置待传输字节数
通道控制寄存器CHx_CR32-bit设置粒度、方向、增量模式、中断使能
通道请求映射寄存器CHx_REQMAP8/16-bit将外设请求线映射到本通道

一个典型的DMA通道初始化代码片段(伪代码):

/* 假设DMA控制器基地址为 DMA_BASE,通道0寄存器偏移已知 */
#define DMA_CH0_SAR   (DMA_BASE + 0x100)
#define DMA_CH0_DAR   (DMA_BASE + 0x104)
#define DMA_CH0_TCNT  (DMA_BASE + 0x108)
#define DMA_CH0_CR    (DMA_BASE + 0x10C)

/* 配置通道0:从外设数据寄存器到内存缓冲区 */
void dma_channel0_init(uint32_t src_periph, uint32_t dst_mem, uint32_t size)
{
    /* 1. 确保通道处于空闲状态 */
    while (readl(DMA_CH0_CR) & DMA_CR_CH_ENABLE)
        writel(DMA_CH0_CR, readl(DMA_CH0_CR) & ~DMA_CR_CH_ENABLE);

    /* 2. 设置源地址(外设寄存器地址,固定不变) */
    writel(DMA_CH0_SAR, src_periph);

    /* 3. 设置目的地址(内存缓冲区,每次传输后递增) */
    writel(DMA_CH0_DAR, dst_mem);

    /* 4. 设置传输字节数 */
    writel(DMA_CH0_TCNT, size);

    /* 5. 配置控制寄存器:
         - 源地址固定(外设FIFO)
         - 目的地址递增
         - 字粒度(32-bit)
         - 硬件请求触发
         - 传输完成使能中断 */
    uint32_t cr = DMA_CR_SRC_FIXED | DMA_CR_DST_INC |
                  DMA_CR_WIDTH_WORD | DMA_CR_REQ_HW |
                  DMA_CR_IE_COMPLETE;
    writel(DMA_CH0_CR, cr);

    /* 6. 使能通道 */
    writel(DMA_CH0_CR, readl(DMA_CH0_CR) | DMA_CR_CH_ENABLE);
}
注意: 在使能通道之前,必须确保所有配置寄存器已写入正确的值。部分DMA控制器在使能后锁定通道寄存器,此时修改无效。另外,传输计数寄存器通常以字节为单位,但有些控制器以传输次数为单位(需除以粒度宽度),务必查阅数据手册。

3.6 本章小结

DMA控制器的硬件原理是驱动开发的基础。本章涵盖了:

  • 内部结构:FSM、AGU、TCU、FIFO、通道寄存器组、仲裁器、总线接口的协同工作。
  • 通道机制:每个通道独立的状态机生命周期,从空闲到完成的完整路径。
  • 请求线:外设与DMA之间的硬件握手信号,包括硬件请求和软件触发两种模式。
  • 传输粒度 ← 上一章 📖 返回目录 下一章 →