STM32的DMA(Direct Memory Access,直接存储器访问)是一种硬件模块,用于在外设与存储器之间或存储器与存储器之间直接传输数据,无需CPU干预,从而显著提升系统效率和实时性。
一、DMA 核心概念与工作原理
DMA的核心思想是将数据搬运任务从CPU中剥离。传统方式下,CPU需要亲自读取外设数据再写入内存,这会占用大量计算资源。而DMA控制器作为独立的硬件模块,在配置好后,能在外设产生请求时,直接通过系统总线完成数据的读取和写入,整个过程CPU可以处理其他任务。
一次完整的DMA传输包含三个基本操作:1)从源地址(外设寄存器或存储器)取数据;2)将数据存放到目标地址(存储器或外设寄存器);3)递减传输数量计数器。只要传输计数器不为零且DMA通道已使能,传输就会持续进行。
二、STM32 DMA 的主要特性
- 多通道与控制器:STM32(如F1系列)通常有1到2个DMA控制器(DMA1和DMA2)。DMA1有7个通道,DMA2有5个通道,每个通道可连接到特定外设(如ADC、USART、SPI等)。
- 传输方向:支持外设到存储器、存储器到外设以及存储器到存储器(部分模式限制)三种方向。
- 可编程数据宽度:传输的数据单元可以是字节(8位)、半字(16位)或字(32位),源和目标的数据宽度可以独立设置。
- 地址递增模式:可以设置外设地址和存储器地址在每次传输后是否自动递增。通常,外设(如数据寄存器)地址固定,而存储器(如数组)地址需要递增以存放连续数据。
- 传输模式 :
- 单次模式 (Normal):传输指定数量的数据后停止,需要重新配置才能再次启动。
- 循环模式 (Circular):传输完成后自动重装计数器,从初始地址开始新一轮传输,适用于ADC连续采样等场景。
- 优先级管理:每个通道的优先级可通过软件设置(非常高、高、中、低)。当多个通道同时请求时,先比较软件优先级;若相同,则通道编号小的拥有更高的硬件优先级。
- 中断与事件:每个通道可以产生三种事件标志:半传输完成、传输完成和传输错误。这些标志可以触发中断,方便CPU在传输关键节点进行处理。
三、DMA 配置关键结构体成员(以标准库为例)
配置DMA时,需要初始化一个结构体(DMA_InitTypeDef),其核心成员与功能如下:
| 结构体成员 | 功能描述 | 对应寄存器/常见设置 |
|---|---|---|
DMA_PeripheralBaseAddr |
外设数据寄存器地址。例如,串口传输设为 &USART1->DR;ADC传输设为 &ADC1->DR。 |
DMA_CPARx |
DMA_Memory0BaseAddr |
存储器基地址,通常是自定义数组的首地址。 | DMA_CMARx |
DMA_DIR |
传输方向:外设到存储器、存储器到外设等。 | DMA_CCRx 的 DIR 位 |
DMA_BufferSize |
要传输的数据数量。 | DMA_CNDTRx |
DMA_PeripheralInc |
外设地址是否递增。通常设为 Disable(外设寄存器固定)。 |
DMA_CCRx 的 PINC 位 |
DMA_MemoryInc |
存储器地址是否递增。通常设为 Enable(用于存储数据数组)。 |
DMA_CCRx 的 MINC 位 |
DMA_PeripheralDataSize |
外设数据宽度:字节、半字或字。 | DMA_CCRx 的 PSIZE 位 |
DMA_MemoryDataSize |
存储器数据宽度:字节、半字或字。 | DMA_CCRx 的 MSIZE 位 |
DMA_Mode |
传输模式:单次模式 (Normal) 或循环模式 (Circular)。 |
DMA_CCRx 的 CIRC 位 |
DMA_Priority |
通道优先级:低、中、高、非常高。 | DMA_CCRx 的 PL 位 |
DMA_M2M |
是否使能存储器到存储器模式。 | DMA_CCRx 的 MEM2MEM 位 |
四、DMA 配置与使用的一般步骤
- 使能时钟:首先开启DMA控制器的时钟(通常在AHB总线上)。
- 初始化DMA通道:使用上述结构体参数配置DMA通道,包括地址、方向、数据量等。
- 使能外设的DMA功能:在对应外设(如ADC、USART)的配置中,开启其DMA请求输出。
- 配置中断(可选):如果需要,使能DMA传输完成等中断,并配置NVIC。
- 使能DMA通道:最后启动DMA通道,使其等待外设请求或软件触发。
- 触发传输:对于外设触发模式(如ADC),启动外设即可;对于存储器到存储器模式,使能通道即开始传输。
- 查询状态或处理中断:通过查询标志位或在中段服务函数中,判断传输是否完成并进行后续处理。
五、典型应用示例:ADC 使用 DMA 搬运数据
这是一个非常常见的应用,用于高效地连续采集模拟信号。关键步骤如下:
- 初始化ADC :配置ADC为定时器触发等连续转换模式,并关键一步 :调用
ADC_DMACmd(ADC1, ENABLE);使能ADC的DMA输出。 - 初始化DMA :以ADC1(对应DMA1通道1)为例进行配置。
- 源地址 (
PeripheralBaseAddr):(u32)(&ADC1->DR)(ADC数据寄存器地址)。 - 目标地址 (
MemoryBaseAddr):自定义数组(如u16 adcValue[128])的首地址。 - 方向:外设到存储器 (
DMA_DIR_PeripheralSRC)。 - 存储器地址递增使能。
- 数据宽度:半字(16位,匹配ADC的12位结果)。
- 模式:循环模式 (
Circular),实现连续采集。 - 使能传输完成中断,以便在数组填满时进行处理。
- 源地址 (
- 启动:启动ADC转换,随后ADC每完成一次转换就会触发DMA请求,DMA自动将数据搬运到指定数组中。CPU只需在DMA传输完成中断中处理这批数据即可,期间完全自由。
六、DMA 与 CPU 的关系
在STM32的Cortex-M架构中,DMA和CPU通过总线矩阵共享系统总线。当DMA和CPU同时访问同一目标(如SRAM)时,总线仲裁器会协调访问,通常采用轮转调度以保证双方都能获得带宽,因此DMA的使用不会完全阻塞CPU,但可能会在总线争用时轻微影响CPU的访问速度。这与一些其他架构(如x86)不同,在STM32上合理使用DMA能显著降低CPU负载,提高系统整体性能。
总之,STM32的DMA是提升数据吞吐量和系统实时性的强大工具,熟练掌握其原理和配置方法对于开发高性能嵌入式应用至关重要。