2. DMA基础:DMA控制器工作原理、DMA传输模式与请求响应

DMA(Direct Memory Access,直接存储器访问)是嵌入式系统中实现高速数据传输的核心技术。在UART驱动开发中,DMA能够在不占用CPU的情况下完成串口数据的批量收发,显著降低CPU负载并提升吞吐量。本节将深入剖析DMA控制器的工作原理、三种主流传输模式以及DMA请求与响应的完整流程。

学习目标:理解DMA控制器内部架构与工作流程;掌握单次、循环、散聚三种传输模式的适用场景与配置差异;理清DMA请求从外设到控制器的信号路径与响应机制。

2.1 DMA控制器工作原理

DMA控制器是独立于CPU的总线主控设备,负责在外设与存储器之间、或存储器与存储器之间搬运数据。其核心组件包括:

  • 通道(Channel):每个DMA控制器包含多个独立通道,每个通道可服务于一个外设请求。
  • 源地址寄存器(SAR):存储数据源地址,支持递增、递减或固定模式。
  • 目的地址寄存器(DAR):存储数据目的地址,同样支持地址模式配置。
  • 传输计数寄存器(CTR):记录剩余待传输的数据量,每完成一次传输自动递减。
  • 控制寄存器(CR):配置传输方向、数据宽度、突发大小、中断使能等参数。
  • 状态寄存器(SR):反映通道忙闲状态、传输完成标志、错误标志等。
关键概念:DMA控制器作为总线主控,在传输期间会占用系统总线。当DMA与CPU同时请求总线时,由总线仲裁器决定优先级。在UART应用中,通常将DMA优先级设置为低于CPU,避免影响关键中断响应。

下图展示了DMA控制器内部架构及其与系统总线的连接关系:

DMA控制器内部架构与系统连接 DMA 控制器 通道 0 (UART1_RX) SAR | DAR | CTR 通道 1 (UART1_TX) SAR | DAR | CTR 通道 2 (SPI1_RX) SAR | DAR | CTR 通道 3 (ADC1) 寄存器组 CR (控制) SR (状态) SAR (源地址) DAR (目的地址) CTR (计数) FIFO (数据缓存) 仲裁器 系统总线 UART 外设 TX/RX FIFO SPI 外设 TX/RX FIFO ADC 外设 数据寄存器 存储器 UART1_RX_BUF UART1_TX_BUF SPI1_RX_BUF ADC1_BUF ... DMA控制器通过系统总线直接访问外设FIFO和存储器,无需CPU逐字节搬运

2.2 DMA传输模式

根据应用场景的不同,DMA控制器支持三种基本传输模式。下表对比了各模式的核心差异:

传输模式 传输终止条件 地址更新方式 中断触发时机 典型UART应用
单次传输(Single/Basic) 传输计数CTR减至0 源/目的地址按数据宽度递增 传输完成中断(单次) 发送固定长度数据帧
循环传输(Circular) 永不停止,CTR溢出后自动重载 地址回绕至缓冲区起始 半传输完成 + 传输完成(循环) 连续数据流接收(如GPS模块)
散聚传输(Scatter-Gather) 链表中的描述符全部完成 由链表描述符指定,支持非连续内存 每个描述符完成或全部完成 大数据包收发、协议栈零拷贝

2.2.1 单次传输模式

单次传输是最基础的DMA模式。配置完成后,DMA控制器从源地址搬运指定数量的数据到目的地址,传输完成后自动停止并产生中断。该模式适用于已知数据长度的场景,如发送一个固定大小的UART数据包。

注意事项:单次传输完成后,必须重新配置传输计数寄存器(CTR)才能启动下一次传输。在UART接收中,如果数据长度不确定,单次模式可能导致接收不完整或缓冲区溢出。

2.2.2 循环传输模式

循环传输模式下,DMA控制器在传输计数归零后自动将地址和计数值重载为初始值,形成环形缓冲区。该模式特别适合UART接收连续数据流,配合半传输完成中断和传输完成中断,可以实现双缓冲机制。

循环传输的关键配置参数:

  • 缓冲区大小:必须为2的幂次方,便于地址回绕计算。
  • 半传输中断:当传输计数达到初始值的一半时触发,用于处理前半缓冲区数据。
  • 传输完成中断:当传输计数回绕到初始值时触发,用于处理后半缓冲区数据。

2.2.3 散聚传输模式

散聚传输(也称为链表传输)通过内存中的描述符链表管理多个不连续的传输块。每个描述符包含源地址、目的地址、传输计数和下一个描述符指针。DMA控制器自动遍历链表,完成所有描述符指定的传输任务。

散聚传输描述符结构示例:

struct dma_descriptor {
    uint32_t src_addr;      // 源地址
    uint32_t dst_addr;      // 目的地址
    uint32_t transfer_size; // 传输字节数
    uint32_t next_desc;     // 下一个描述符地址
    uint32_t ctrl;          // 控制标志(中断使能、完成标志等)
};

下图展示了散聚传输的链表执行流程:

散聚传输(Scatter-Gather)链表执行流程 描述符 1 SRC: BUF_A DST: UART_TX SIZE: 64 字节 NEXT: &Desc2 描述符 2 SRC: BUF_B DST: UART_TX SIZE: 128 字节 NEXT: &Desc3 描述符 3 SRC: BUF_C DST: UART_TX SIZE: 32 字节 NEXT: NULL (结束) DMA控制器自动遍历链表:Desc1 → Desc2 → Desc3 → 传输完成中断 优势:支持非连续内存块传输,无需CPU参与链表遍历,适合大数据包零拷贝场景

2.3 DMA请求与响应

DMA传输的启动依赖于外设发出的DMA请求信号。完整的请求与响应流程涉及外设、DMA控制器和总线仲裁器三方协作。

2.3.1 DMA请求类型

请求类型 触发源 信号特征 典型应用
硬件请求(HW Request) 外设硬件信号(如UART RXNE标志) 电平触发或脉冲触发,可配置极性 UART接收/发送、SPI传输、ADC转换
软件请求(SW Request) CPU写DMA软件触发寄存器 一次性触发,无需外设信号 存储器到存储器拷贝、测试模式
外设事件请求(Event Request) 定时器事件、外部中断等 与定时器PWM或比较事件同步 定时触发ADC采样、PWM同步传输

2.3.2 请求响应流程

以UART接收为例,DMA请求与响应的完整时序如下:

  1. 外设就绪:UART接收FIFO中数据达到阈值(如1字节),硬件自动置位DMA请求信号(DMA_REQ)。
  2. DMA仲裁:DMA控制器检测到请求信号,根据通道优先级进行仲裁。若多个通道同时请求,高优先级通道优先获得总线控制权。
  3. 总线请求:DMA控制器向总线仲裁器发出总线请求信号(HOLD/BREQ)。
  4. 总线授权:CPU完成当前总线周期后,释放总线控制权。总线仲裁器向DMA控制器发送总线授权信号(HLDA/BGNT)。
  5. 数据传输:DMA控制器获得总线控制权,执行一次或多次突发传输,将UART FIFO中的数据搬运至内存缓冲区。
  6. 请求释放:传输完成后,DMA控制器释放总线,外设DMA请求信号自动清除。若传输计数未归零,DMA控制器继续等待下一次请求。
性能要点:突发传输(Burst Transfer)允许DMA在一次总线仲裁后连续传输多个数据单元,减少总线仲裁开销。在UART应用中,建议将突发大小设置为与FIFO深度匹配(如4字节或8字节),避免FIFO溢出或空置。

下图展示了UART DMA请求与响应的完整时序流程:

UART DMA请求与响应时序流程 时间轴 ① 外设就绪 UART RXNE=1 ② DMA请求 DMA_REQ 置位 ③ 总线请求 HOLD 置位 ④ 总线授权 HLDA 响应 ⑤ 数据传输(突发模式) DMA从UART FIFO读取4字节 → 写入内存缓冲区 → 传输计数CTR递减 ⑥ 请求释放 DMA释放总线(HOLD撤销)→ 外设DMA_REQ自动清除 → 等待下一次请求 若CTR未归零:返回步骤①等待下一次外设就绪;若CTR归零:触发传输完成中断

2.4 关键配置参数总结

在UART驱动开发中配置DMA时,以下参数需要根据具体硬件和应用场景仔细设定:

参数 可选值 UART推荐配置 说明
数据宽度 8位 / 16位 / 32位 8位(与UART数据位匹配) 必须与外设数据寄存器宽度一致
突发大小 1 / 4 / 8 / 16 次传输 4 或 8(匹配UART FIFO深度) 过大可能导致CPU响应延迟
地址增量 递增 / 递减 / 固定 外设地址固定,内存地址递增 UART数据寄存器地址固定不变
传输方向 外设→内存 / 内存→外设 接收:外设→内存;发送:内存→外设 由DMA控制寄存器DIR位决定
中断使能 传输完成 / 半传输 / 错误 传输完成 + 错误中断必须使能 错误中断用于检测总线错误或FIFO溢出
通道优先级 低 / 中 / 高 / 最高 UART接收优先级高于发送 避免接收FIFO溢出导致数据丢失
实践建议:在初始化DMA时,建议先配置通道参数,再使能DMA控制器,最后使能外设的DMA请求。关闭顺序相反:先禁能外设DMA请求,再禁能DMA通道。这种顺序可以避免在配置过程中产生意外的DMA请求。