文章目录
- 一、DMA简介
- 二、DMA模块详解
- 三、CudeMx配置DMA
- 四、DMA**编程模块**
- 五、总结
一、DMA简介
DMA = Direct Memory Access,直接存储器访问,是STM32核心外设之一,核心作用是「硬件自动完成数据搬运」,完全不占用CPU资源,解决CPU在大量数据传输(如ADC采集、UART收发、SPI通信)中被占用、导致效率低下的问题。
1、DMA工作原理图

2、核心功能:
- 实现三大方向数据传输:外设→内存、内存→外设、内存→内存(仅STM32F103大容量型号支持)。
- 支持单次传输、循环传输,适配不同场景需求。
- 可配合ADC、UART、SPI、TIM、DAC等外设,实现高速数据自动搬运。
- 传输过程无需CPU干预,解放CPU执行其他业务逻辑(如中断处理、算法运算)。
3、核心特点
- 传输速度快,依托硬件实现,比CPU软件搬运效率高10倍以上。
- 支持多种数据宽度(字节8bit、半字16bit、字32bit),适配不同外设数据格式。
- 具备传输完成、半传输、传输错误等中断,便于程序监控和处理。
- STM32F103 包含DMA1(全系列都有,7个通道)和DMA2(仅大容量型号有,5个通道)。
二、DMA模块详解
1、DMA框图

1.DMA请求
- 外设要想通过DMA来传输数据,必须先给DMA控制器发送DMA请求,DMA收到请求信号之后,控制器会给外设一个应答信号, 当外设应答后且DMA控制器收到应答信号之后,就会启动DMA的传输,直到传输完毕。
- DMA有DMA1和DMA2两个控制器,DMA1有7个通道,DMA2有5个通道,不同的DMA控制器的通道对应着不同的外设请求。
- DMA1请求映射

- DMA2请求映射

2.通道
- DMA具有12个独立可编程的通道,其中DMA1有7个通道,DMA2有5个通道,每个通道对应不同的外设的DMA请求。
- 虽然每个通道可以接收多个外设的请求,但是同一时间只能接收一个,不能同时接收多个。
3.仲载器
- 当发生多个DMA通道请求时,就意味着有先后响应处理的顺序问题,这个就由仲裁器也管理。仲裁器管理DMA通道请求分为两个阶段。
- 第一阶段
属于软件阶段,可以在DMA_CCRx寄存器中设置,有4个等级:非常高、高、中和低四个优先级。
1、软件阶段,DMA_CCRx:PL1:0。 - 第二阶段
属于硬件阶段, 如果两个或以上的DMA通道请求设置的优先级一样,则他们优先级取决于通道编号,编号越低优先权越高。
2、硬件阶段,通道编号小的优先级大,DM1的优先级高于DMA2的优先级。
2、核心概念
1.通道(Channel):
- 每个DMA有多个通道,每个通道对应一个外设(如DMA1_CH1对应ADC1,DMA1_CH4对应USART1_TX),同一时间一个通道只能处理一个传输任务。
2.传输方向:3种核心方向,是DMA配置的核心:
- 外设→内存(最常用):如ADC采集数据,自动搬运到内存数组 。
- 内存→外设:如UART发送数据,自动从内存数组搬运到串口发送寄存器 。
- 内存→内存:仅DMA2支持,实现硬件层面的memcpy,比软件 memcpy 快 。
3.传输模式:
- Normal(普通模式):传输完成后,DMA停止工作,需手动重启传输 。
- Circular(循环模式):传输完成后,自动重新开始传输,无需手动重启,适合连续采集/连续发送(如ADC循环采集、DAC波形输出) 。
4.地址自增:
- 内存地址自增(通常开启):传输时内存地址自动+1(按数据宽度),实现连续地址搬运 。
- 外设地址自增(通常关闭):外设寄存器地址固定,无需自增(如ADC数据寄存器、UART发送寄存器) 。
3、STM32F103 DMA 通道分配
DMA1(全系列支持,7个通道):
| DMA通道 | 对应外设 | 常用场景 |
|---|---|---|
| DMA1_CH1 | ADC1 | ADC采集数据→内存 |
| DMA1_CH2 | TIM1_CH1/TIM1_UP/TIM1_TRIG | TIM触发DMA传输 |
| DMA1_CH3 | TIM1_CH4/TIM2_UP | TIM相关数据传输 |
| DMA1_CH4 | USART1_TX | 内存→USART1发送 |
| DMA1_CH5 | USART1_RX | USART1接收→内存 |
| DMA1_CH6 | USART2_TX/SPI1_RX | USART2发送、SPI1接收 |
| DMA1_CH7 | USART2_RX/SPI1_TX | USART2接收、SPI1发送 |
DMA2(仅大容量型号支持,如STM32F103VET6):
- 支持内存→内存传输,通道对应高端外设(如ADC2/3、SPI2等)。
4、传输优先级
- 当多个DMA通道同时请求传输时,优先级决定传输顺序,STM32F103 DMA支持4级优先级:
Very High(最高)> High(高)> Medium(中)> Low(低) - 工程配置建议:
ADC、UART等关键外设的DMA通道设为High/Very High,非关键通道设为Medium/Low。
三、CudeMx配置DMA
内存至内存,适用于大量数据拷贝。
1、开启 DMA 的 Memory to Memory 模式

- 进入 DMA Settings
Add → 选择 DMA1 通道(随便一个可用 DMA)
方向:Memory To Memory
优先级:Low / Medium 都行
源数据自增:Memory Increment → Enable
目标数据自增:Memory Increment → Enable
数据宽度:Byte(8 位)
模式:Normal(正常模式)
内存到内存一般不用循环,复制完就结束
2、代码
c
#include "main.h"
#include "stm32f1xx_hal.h" // 根据你的芯片修改
// extern DMA 句柄(CubeMX 生成)
extern DMA_HandleTypeDef hdma_memtomem_dma1_channel1;
// ==================== 内存数据 ====================
#define BUF_SIZE 100 // 数据长度
uint8_t src_buf[BUF_SIZE] = {0}; // 源数据
uint8_t dest_buf[BUF_SIZE] = {0}; // 目标数据
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
//初始化源数据
// 给源数据赋值
for(int i=0; i<BUF_SIZE; i++)
{
src_buf[i] = i; // 0,1,2,3...99
}
// ========================
// DMA 内存 → 内存 复制
// ========================
HAL_DMA_Start(
&hdma_memtomem_dma1_channel1, // DMA句柄
(uint32_t)src_buf, // 源地址
(uint32_t)dest_buf, // 目标地址
BUF_SIZE // 数据长度
);
// 等待传输完成(可选)
HAL_DMA_PollForTransfer(
&hdma_memtomem_dma1_channel1,
HAL_DMA_FULL_TRANSFER,
1000
);
while (1)
{
// dest_buf[] 已经被 DMA 自动复制完成!
// 这里可以直接使用
}
}
3、中断版代码参考
c
// 启动中断方式
HAL_DMA_Start_IT(
&hdma_memtomem_dma1_channel1,
(uint32_t)src_buf,
(uint32_t)dest_buf,
BUF_SIZE
);
// DMA 传输完成回调
void HAL_DMA_XferCpltCallback(DMA_HandleTypeDef *hdma)
{
if(hdma == &hdma_memtomem_dma1_channel1)
{
// 内存拷贝完成!
// 在这里处理数据
}
}
四、DMA编程模块
1、初始化结构体
用于配置DMA的初始化参数,如传输方向、数据宽度、是否使能FIFO、突发传输模式等。
c
typedef struct
{
uint32_t Direction; /* 传输方向 */
uint32_t PeriphInc; /* 外设地址增量 */
uint32_t MemInc; /* 内存地址增量 */
uint32_t PeriphDataAlignment; /* 外设数据对齐 */
uint32_t MemDataAlignment; /* 内存数据对齐 */
uint32_t Mode; /* 工作模式 */
uint32_t Priority; /* 优先级 */
uint32_t FIFOMode; /* FIFO模式 */
uint32_t FIFOThreshold; /* FIFO阈值 */
uint32_t MemBurst; /* 内存突发传输 */
uint32_t PeriphBurst; /* 外设突发传输 */
} DMA_InitTypeDef;
2、句柄
- DMA的句柄结构体,它包含了DMA_InitTypeDef实例、DMA实例的寄存器基地址、传输状态、错误码以及各种回调函数指针。
- 它是所有HAL_DMA API操作的第一个参数。
c
typedef struct __DMA_HandleTypeDef
{
DMA_Stream_TypeDef *Instance; /* DMA流/通道寄存器基地址 */
DMA_InitTypeDef Init; /* DMA初始化参数 */
HAL_LockTypeDef Lock; /* 锁定对象 */
__IO HAL_DMA_StateTypeDef State; /* DMA状态 */
void *Parent; /* 关联的外设句柄 */
void (* XferCpltCallback)(struct __DMA_HandleTypeDef *hdma);
void (* XferHalfCpltCallback)(struct __DMA_HandleTypeDef *hdma);
void (* XferErrorCallback)(struct __DMA_HandleTypeDef *hdma);
__IO uint32_t ErrorCode; /* 错误代码 */
uint32_t StreamBaseAddress; /* 流基地址 */
uint32_t StreamIndex; /* 流索引 */
} DMA_HandleTypeDef;
3、API
1.初始化与反初始化
c
HAL_StatusTypeDef HAL_DMA_Init(DMA_HandleTypeDef *hdma);
HAL_StatusTypeDef HAL_DMA_DeInit(DMA_HandleTypeDef *hdma);
2.启动传输
c
HAL_StatusTypeDef HAL_DMA_Start(
DMA_HandleTypeDef *hdma,
uint32_t SrcAddress,
uint32_t DstAddress,
uint32_t DataLength
);
HAL_StatusTypeDef HAL_DMA_Start_IT(
DMA_HandleTypeDef *hdma,
uint32_t SrcAddress,
uint32_t DstAddress,
uint32_t DataLength
);
3.传输控制
c
HAL_StatusTypeDef HAL_DMA_Abort(DMA_HandleTypeDef *hdma);
HAL_StatusTypeDef HAL_DMA_PollForTransfer(
DMA_HandleTypeDef *hdma,
uint32_t CompleteLevel,
uint32_t Timeout
);
4.状态与回调
c
HAL_DMA_StateTypeDef HAL_DMA_GetState(DMA_HandleTypeDef *hdma);
uint32_t HAL_DMA_GetError(DMA_HandleTypeDef *hdma);
void HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma);
4、状态/错误
c
typedef enum
{
HAL_DMA_STATE_RESET = 0x00U, /* 未初始化/复位 */
HAL_DMA_STATE_READY = 0x01U, /* 初始化完成就绪 */
HAL_DMA_STATE_BUSY = 0x02U, /* 传输进行中 */
HAL_DMA_STATE_TIMEOUT = 0x03U, /* 超时状态 */
HAL_DMA_STATE_ERROR = 0x04U, /* 错误状态 */
HAL_DMA_STATE_ABORT = 0x05U, /* 中止状态 */
} HAL_DMA_StateTypeDef;
五、总结
1、工作原理
- CPU 只需配置一次参数(源地址、目标地址、数据长度、模式),后续所有数据搬运全部由 DMA 硬件自动完成,搬运完成后触发中断通知CPU。
- 整个过程 CPU 无需干预,可同时运行其他代码。
2、两大工作模式
1)Normal 普通模式
- 搬运完设定长度数据后,自动停止,需要代码重新开启传输。
- 适用:单次发送、一次性数据传输。
2)Circular 循环模式
- 搬运完成后自动重置计数器、重新开始搬运,永不停止。
- 适用:ADC连续采集、串口持续接收、实时数据流。
3、地址递增规则
- 内存地址:默认开启自增(每搬一个字节地址+1)。
- 外设地址:默认关闭自增(寄存器地址固定不变)。
4、数据宽度
- Byte 8位、HalfWord 16位、Word 32位。
- ADC多用 HalfWord,串口多用 Byte。
5、中断类型
- 传输完成中断 TC:一整批数据搬运完毕。
- 半传输中断 HT:搬运一半数据(乒乓缓冲核心)。
- 错误中断 TE:传输异常、地址错误。