4. DMA传输模式
STM32 的 DMA 控制器并不是“只会搬数据”的黑盒,它真正灵活的地方在于传输方向与工作模式可以自由组合。方向决定数据从哪来、到哪去;模式决定这次搬运是一次性完成,还是自动循环、持续不断。理解这两组概念,是配置 DMA 时最容易出错、也最值得先弄清楚的基础。
从方向上看,DMA 支持三种基本传输类型:外设到存储器(Peripheral-to-Memory)、存储器到外设(Memory-to-Peripheral)、存储器到存储器(Memory-to-Memory)。从工作模式上看,又分为单次模式(Normal)和循环模式(Circular)。方向与模式是正交的,也就是说,外设到存储器既可以是单次,也可以是循环,这一点在配置寄存器时体现得非常直接。
一、三种传输方向的核心原理
外设到存储器是最常见的采集路径。以 ADC 连续采样为例,ADC 每次转换完成会把结果写入 ADC_DR,DMA 检测到外设请求后,自动把 ADC_DR 的内容搬到 SRAM 数组里。此时外设地址固定为 ADC_DR,存储器地址递增,传输数量等于采样点数。USART 接收、SPI 接收、I2S 接收都属于这一类。
存储器到外设则是发送路径。比如 USART 发送一段字符串,DMA 从 SRAM 缓冲区逐个读取字节,写入 USART_DR,硬件自动完成发送。外设地址固定为 USART_DR,存储器地址递增。SPI 发送、DAC 输出、定时器 PWM 占空比更新也常用这种方式。
存储器到存储器比较特殊,它不依赖外设请求,而是由 DMA 控制器自己产生触发,把一块 SRAM 或 Flash 区域搬到另一块 SRAM。它常用于数据搬移、缓冲区填充、图像数据复制等场景。需要注意的是,只有 DMA1 和 DMA2 的特定通道支持存储器到存储器,且不能与循环模式随意组合使用。
二、单次模式与循环模式的工作流程
单次模式下,DMA 传输完 NDTR 指定的数据量后,硬件自动清除 EN 位,传输完成标志 TC 置位。如果还需要继续传输,必须由软件重新配置 NDTR 并使能通道。它适合“采集一批、处理一批”的间歇式场景,比如按键触发一次 ADC 采集 100 个点。
循环模式下,NDTR 减到 0 后不会停止,而是自动重装为初始值,源地址和目的地址也回到起始位置,DMA 继续下一轮搬运。整个过程无需 CPU 干预,TC 标志每轮都会置位,可以配合中断做“半传输/全传输”双缓冲处理。它适合 ADC 连续扫描、音频流播放、串口不定长接收等持续数据流场景。
// 外设到存储器 + 循环模式(ADC1 + DMA1_Channel1)
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)adc_buffer;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 外设→存储器
DMA_InitStructure.DMA_BufferSize = 256;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 循环模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel1, ENABLE);
三、典型场景与配置对照
| 场景 | 传输方向 | 工作模式 | 关键配置 |
|---|---|---|---|
| ADC 连续采样 256 点 | 外设 → 存储器 | 循环 | PINC 禁止,MINC 使能,半字对齐 |
| USART 发送字符串 | 存储器 → 外设 | 单次 | PINC 禁止,MINC 使能,字节对齐 |
| SRAM 缓冲区搬移 | 存储器 → 存储器 | 单次 | PINC/MINC 均使能,仅特定通道支持 |
| 音频 I2S 播放 | 存储器 → 外设 | 循环 | 半传输中断 + 双缓冲 |
| 串口不定长接收 | 外设 → 存储器 | 循环 | 配合 IDLE 中断读取 NDTR 差值 |
四、常见误区与复盘
总结来说,传输方向决定“数据流向”,工作模式决定“搬完是否继续”。外设到存储器、存储器到外设、存储器到存储器是三条不同的数据通路,单次与循环则是两种生命周期管理方式。把它们组合起来,就能覆盖从单次采集到连续流处理的绝大多数应用场景。