一、DMA 简介
DMA (Direct Memory Access,直接存储器访问) 是 STM32F103 系列微控制器内置的一个独立外设,其核心功能是在不占用 CPU 资源的情况下,实现数据在存储器与外设之间、存储器与存储器之间的高速传输。
1.1 核心优势
传统的数据传输方式需要 CPU 主动参与,将数据从源地址读取到内核寄存器,再写入目标地址,整个过程 CPU 被完全占用。而 DMA 传输时,CPU 只需配置传输参数并启动 DMA,之后 DMA 控制器会自动完成数据搬运,CPU 可以并行执行其他任务,极大提高了系统效率。
1.2 支持的传输方向
DMA 支持三种数据传输模式:
-
存储器到存储器 (Memory-to-Memory, M2M):数据在内部 Flash、SRAM 之间传输
-
外设到存储器 (Peripheral-to-Memory, P2M):典型应用如 ADC 采集数据到 SRAM
-
存储器到外设 (Memory-to-Peripheral, M2P):典型应用如 SRAM 中的数据通过串口发送
1.3 DMA 控制器与通道
STM32F103 系列包含两个 DMA 控制器:
-
DMA1:拥有 7 个独立通道,支持所有三种传输模式
-
DMA2:拥有 5 个独立通道,支持所有三种传输模式
重要说明 :DMA2 仅存在于大容量产品 (Flash 容量 256KB~512KB)和互联型产品(STM32F105/F107 系列)中。指南者和霸道开发板使用的 STM32F103ZET6 属于大容量产品,因此同时具备 DMA1 和 DMA2。
二、DMA 功能框图详解
DMA 功能框图主要由三部分组成:DMA 请求 、通道 和仲裁器。
2.1 DMA 请求
DMA 传输必须由请求源触发。对于 P2M 和 M2P 模式,请求源只能是外设;对于 M2M 模式,由软件触发。
当外设需要进行 DMA 传输时,会向对应的 DMA 通道发送请求信号。DMA 控制器接收到请求后,若通道空闲,则启动数据传输。
2.2 DMA 通道
DMA 通道可以理解为独立的数据传输管道,每个通道都有自己的配置寄存器,可以独立配置传输方向、数据宽度、地址增量等参数。
2.2.1 DMA1 通道映射
| DMA1 通道 | 外设请求源 |
|---|---|
| 通道 1 | ADC1、TIM2_CH3、TIM4_CH1 |
| 通道 2 | SPI1_RX、TIM1_CH1、TIM2_UP、TIM3_CH1 |
| 通道 3 | SPI1_TX、TIM1_CH2、TIM2_CH2、TIM3_CH2 |
| 通道 4 | SPI2_RX、USART1_TX、TIM1_CH4、TIM1_TRIG、TIM3_CH3 |
| 通道 5 | SPI2_TX、USART1_RX、TIM1_UP、TIM3_CH4、TIM3_TRIG |
| 通道 6 | USART2_RX、TIM1_CH1、TIM2_CH4 |
| 通道 7 | USART2_TX、TIM1_CH2、TIM2_CH1、TIM4_CH2 |
2.2.2 DMA2 通道映射
| DMA2 通道 | 外设请求源 |
|---|---|
| 通道 1 | ADC3、TIM5_CH4、TIM8_CH3 |
| 通道 2 | SPI3_RX、TIM5_CH3、TIM8_CH4、TIM8_TRIG |
| 通道 3 | SPI3_TX、TIM5_CH2、TIM8_CH1 |
| 通道 4 | UART4_RX、SDIO、TIM5_CH1、TIM8_CH2 |
| 通道 5 | UART4_TX、TIM5_UP、TIM6_UP/DAC_CH1、TIM7_UP/DAC_CH2、TIM8_UP |
特殊说明 :存储器到存储器(M2M)模式不受上述通道映射限制,可以使用 DMA1 和 DMA2 的任意通道。
2.3 DMA 仲裁器
当多个 DMA 通道同时产生传输请求时,仲裁器负责决定哪个通道优先获得总线使用权。仲裁规则分为两个阶段:
-
软件优先级阶段:通过 DMA_CCRx 寄存器的 PL[1:0] 位配置,分为四个等级:
-
00:低优先级
-
01:中优先级
-
10:高优先级
-
11:最高优先级
-
-
硬件优先级阶段:当两个通道的软件优先级相同时,通道编号小的优先级更高。例如,DMA1 通道 4 的优先级高于 DMA1 通道 7。
跨控制器优先级:DMA1 的所有通道优先级均高于 DMA2 的通道。
三、DMA 初始化结构体详解
STM32 标准外设库使用 DMA_InitTypeDef结构体来配置 DMA 参数,该结构体定义在 stm32f10x_dma.h文件中。
3.1 数据从哪里来,要到哪里去
这部分由结构体的前三个成员决定:
typedef struct {
uint32_t DMA_PeripheralBaseAddr; // 外设基地址
uint32_t DMA_MemoryBaseAddr; // 存储器基地址
uint32_t DMA_DIR; // 数据传输方向
// ... 其他成员
} DMA_InitTypeDef;
-
DMA_PeripheralBaseAddr :配置 DMA_CPAR 寄存器,指定外设数据寄存器的地址。例如,串口发送时应设置为
(uint32_t)&USART1->DR。 -
DMA_MemoryBaseAddr:配置 DMA_CMAR 寄存器,指定存储器的起始地址。例如,发送数组时应设置为数组名(数组首地址)。
-
DMA_DIR:配置 DMA_CCR 寄存器的 DIR 位(位 4),指定数据传输方向:
-
DMA_DIR_PeripheralDST:外设作为目标地址(M2P 模式) -
DMA_DIR_PeripheralSRC:外设作为源地址(P2M 模式)
-
M2M 模式说明 :除了配置上述三个成员外,还需要单独配置 DMA_CCR 寄存器的 MEM2MEM 位(位 14)为 1,即设置结构体成员 DMA_M2M = DMA_M2M_Enable。
3.2 数据要传多少,传的单位是什么
这部分由以下五个成员决定:
uint32_t DMA_BufferSize; // 传输数据数目
uint32_t DMA_PeripheralInc; // 外设地址增量模式
uint32_t DMA_MemoryInc; // 存储器地址增量模式
uint32_t DMA_PeripheralDataSize; // 外设数据宽度
uint32_t DMA_MemoryDataSize; // 存储器数据宽度
-
DMA_BufferSize :配置 DMA_CNDTR 寄存器,指定一次传输的数据单元数目。该寄存器为 16 位,因此最大传输数目为65535。
-
DMA_PeripheralInc:配置 DMA_CCR 寄存器的 PINC 位(位 6),指定外设地址是否自动递增:
-
DMA_PeripheralInc_Enable:每次传输后外设地址自动加 1 -
DMA_PeripheralInc_Disable:外设地址保持不变(适用于单个数据寄存器的情况)
-
-
DMA_MemoryInc:配置 DMA_CCR 寄存器的 MINC 位(位 7),指定存储器地址是否自动递增:
-
DMA_MemoryInc_Enable:每次传输后存储器地址自动加 1(适用于数组传输) -
DMA_MemoryInc_Disable:存储器地址保持不变
-
-
DMA_PeripheralDataSize 和 DMA_MemoryDataSize:分别配置 DMA_CCR 寄存器的 PSIZE[1:0] 位(位 8-9)和 MSIZE[1:0] 位(位 10-11),指定数据宽度:
-
DMA_PeripheralDataSize_Byte:8 位字节 -
DMA_PeripheralDataSize_HalfWord:16 位半字 -
DMA_PeripheralDataSize_Word:32 位字
-
数据宽度不匹配说明:
-
当源数据宽度小于目标数据宽度时,源数据会被零扩展到目标宽度
-
当源数据宽度大于目标数据宽度时,源数据的高位会被丢弃,只保留低位
3.3 什么时候传输结束
这部分由以下两个成员决定:
uint32_t DMA_Mode; // 传输模式
uint32_t DMA_Priority; // 通道优先级
-
DMA_Mode:配置 DMA_CCR 寄存器的 CIRC 位(位 5),指定传输模式:
-
DMA_Mode_Normal:正常模式,传输完成后通道自动停止 -
DMA_Mode_Circular:循环模式,传输完成后自动重新加载传输数目,开始新一轮传输
-
-
DMA_Priority:配置 DMA_CCR 寄存器的 PL[1:0] 位(位 12-13),指定通道的软件优先级,取值如 2.3 节所述。
四、常用 DMA 固件库函数
4.1 DMA 初始化函数
void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);
-
功能:根据
DMA_InitStruct中的参数初始化 DMA 通道 -
参数:
-
DMAy_Channelx:指定要初始化的 DMA 通道,如DMA1_Channel4 -
DMA_InitStruct:指向 DMA 初始化结构体的指针
-
4.2 DMA 使能函数
void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState);
-
功能:使能或禁用指定的 DMA 通道
-
参数:
-
DMAy_Channelx:指定要操作的 DMA 通道 -
NewState:ENABLE使能通道,DISABLE禁用通道
-
4.3 状态查询函数
FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG);
void DMA_ClearFlag(uint32_t DMAy_FLAG);
-
功能:查询或清除 DMA 通道的状态标志
-
常用标志:
-
DMA1_FLAG_TC4:DMA1 通道 4 传输完成标志 -
DMA1_FLAG_HT4:DMA1 通道 4 传输过半标志 -
DMA1_FLAG_TE4:DMA1 通道 4 传输出错标志
-
4.4 中断配置函数
void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState);
-
功能:使能或禁用 DMA 通道的中断
-
参数:
DMA_IT:指定要配置的中断类型,如DMA_IT_TC(传输完成中断)、DMA_IT_HT(传输过半中断)、DMA_IT_TE(传输出错中断)
五、注意事项
-
通道选择限制:P2M 和 M2P 模式必须严格按照通道映射表选择通道,不能随意使用
-
数据宽度匹配:建议源和目标的数据宽度保持一致,避免数据丢失或不必要的扩展
-
地址增量配置:对于单个外设数据寄存器(如 USART_DR、ADC_DR),外设地址增量应设置为禁用
-
循环模式使用:循环模式适用于需要持续传输数据的场景,如串口打印、ADC 连续采集
-
传输完成判断:在 Normal 模式下,可以通过查询传输完成标志位来判断传输是否结束
参考出处
-
视频讲解:STM32F103 DMA 直接存储器访问(理论篇)
-
《零死角玩转 STM32F103-指南者》第 22 章 DMA 直接存储器访问