3、DMA基础与STM32H7 DMA控制器:DMA传输原理、通道配置、循环模式与中断机制
在STM32H7系列中,ADC连续采样产生的高速数据流如果全部依赖CPU搬运,不仅会大量占用中断处理时间,还会因Cache一致性维护和总线仲裁带来不可控的延迟抖动。DMA(Direct Memory Access)正是为解决这一矛盾而设计的硬件搬运引擎。本章将深入剖析STM32H7 DMA控制器的传输原理、通道选择策略、循环模式配置以及中断同步机制,为后续ADC与AI推理之间的Buffer同步打下坚实的底层基础。
3.1 DMA传输核心原理:从外设到存储器的零拷贝搬运
DMA的本质是替代CPU完成外设与存储器之间的数据复制。在STM32H7中,DMA控制器作为AHB总线上的主设备,可以发起总线传输请求。当ADC完成一次转换并将结果写入其数据寄存器(ADCx_DR)时,会产生一个DMA请求信号。DMA控制器收到该请求后,根据预先配置的源地址、目的地址、传输宽度和传输计数,自动完成一次数据搬运,整个过程无需CPU干预。
STM32H7的DMA控制器分为DMA1和DMA2两个实例,每个实例包含8个独立的可配置数据流(Stream)。每个数据流可以关联多个外设请求,但同一时刻只能服务一个外设。与F1/F4系列不同,H7的DMA采用双AHB端口设计,可以同时访问不同存储器区域,这为ADC采样与AI推理数据并行处理提供了硬件基础。
- NDTR(Number of Data Transfer Register):指定剩余传输次数,每次传输后自动递减,当减至0时触发传输完成事件。
- 数据宽度(PSIZE/MSIZE):外设侧与存储器侧的数据宽度可独立配置,支持Byte(8位)、HalfWord(16位)、Word(32位)。若两侧宽度不一致,DMA会自动进行数据拼接或拆分。
- 突发模式(Burst):支持单次传输或4/8/16次突发传输,突发模式可提高总线利用率,但要求存储器地址对齐。
3.2 通道配置与选择策略:匹配ADC采样需求
STM32H7的DMA通道映射并非固定不变,而是通过DMA_SxCR寄存器中的CHSEL位段进行动态选择。以ADC1为例,其DMA请求可以映射到DMA1的Stream0/1/2/3或DMA2的Stream0/1/2/3,具体取决于系统设计中的总线负载均衡需求。
| DMA实例 | 可用Stream | ADC1映射选项 | 适用场景 |
|---|---|---|---|
| DMA1 | Stream0~7 | Stream0/1/2/3 | 轻负载场景,ADC采样率较低(< 1Msps) |
| DMA2 | Stream0~7 | Stream0/1/2/3 | 高采样率或同时使用多个外设DMA的场景 |
配置DMA通道时,需要遵循以下操作流程:
- 确定DMA实例与Stream:查看参考手册的DMA请求映射表,选择未被占用的Stream。
- 配置外设地址:将外设地址寄存器设置为ADC1->DR的地址(0x40022040),并设置地址递增模式为固定(外设地址不递增)。
- 配置存储器地址:指向ADC采样Buffer的首地址,使能存储器地址递增模式。
- 设置传输方向:选择外设到存储器(Peripheral-to-Memory)。
- 配置数据宽度:若ADC分辨率为12位或16位,建议外设侧与存储器侧均使用HalfWord(16位),避免数据错位。
- 选择优先级:高优先级Stream会优先获得总线访问权,但需注意避免低优先级Stream饿死。
3.3 循环模式与中断机制:实现无间隙采样
在AI推理场景中,通常需要连续采集一段时间的ADC数据(例如256点或512点FFT窗口)。如果使用单次传输模式,每次传输完成后需要CPU重新配置NDTR并启动下一次传输,这会引入不可忽略的间隙。循环模式(Circular Mode)正是为解决这一问题而设计:当NDTR递减至0时,硬件自动将NDTR重载为初始值,并将存储器地址指针回绕到Buffer起始地址,从而形成无限循环的数据流。
循环模式配合中断机制,可以实现双缓冲(Ping-Pong)策略:
- 半传输中断(HT):当NDTR递减到初始值的一半时触发,此时Buffer的前半部分已填满,CPU可以处理前半部分数据。
- 传输完成中断(TC):当NDTR递减至0时触发,此时Buffer的后半部分已填满,CPU可以处理后半部分数据。
通过交替使用HT和TC中断,CPU可以在DMA持续写入Buffer的同时,处理已填满的半区数据,实现采样与计算的重叠执行。这种机制对于AI推理至关重要——当推理引擎处理当前数据块时,DMA已经在填充下一块数据,从而最大化系统吞吐量。
__ALIGNED(32)属性声明Buffer即可避免该问题。
3.4 实战案例:双缓冲ADC采样与AI推理数据同步
假设我们需要设计一个基于STM32H743的振动信号分析系统,ADC以1Msps采样率连续采集加速度传感器信号,AI模型需要每256个采样点执行一次推理。系统约束如下:
- ADC1配置为12位分辨率,由TIM1_TRGO事件触发采样,采样率1Msps。
- DMA2_Stream0配置为循环模式,外设地址为ADC1->DR,存储器地址为
adc_buffer[512](双缓冲,每半区256点)。 - AI推理引擎运行在Cortex-M7内核,需要从
adc_buffer中读取数据并进行FFT和分类。
初始现象:直接使用单缓冲模式时,CPU在TC中断中处理数据,但处理期间DMA停止采样,导致采样率下降至约500Ksps,且数据出现周期性丢失。
分析过程:通过逻辑分析仪观察DMA请求信号,发现TC中断服务函数执行时间约30μs(包含FFT计算),而DMA在中断期间无法继续传输,导致采样间隙。进一步检查发现,CPU在中断中访问adc_buffer时,由于Cache未失效,读取到的是旧数据。
解决方案:
- 将
adc_buffer声明为__ALIGNED(32) uint16_t adc_buffer[512],并放置在DTCM RAM区域(地址0x20000000),该区域不经过Cache,避免一致性问题。 - 启用DMA2_Stream0的半传输中断和传输完成中断,在HT中断中处理
adc_buffer[0]~[255],在TC中断中处理adc_buffer[256]~[511]。 - 将AI推理任务放在主循环中执行,通过标志位判断当前可用的数据半区,避免在中断中执行耗时计算。
结果对比:优化后,采样率稳定在1Msps,无数据丢失。CPU在HT中断中仅需复制数据指针并置位标志位(约2μs),AI推理在主循环中完成,整体系统吞吐量提升约40%。
3.5 常见误区与总结复盘
| 误区 | 后果 | 正确做法 |
|---|---|---|
| 未配置存储器地址递增 | 所有数据写入同一地址,Buffer内容被覆盖 | 使能MSIZE递增,确保数据顺序写入 |
| 外设与存储器数据宽度不一致 | 数据错位,AI推理结果异常 | 统一使用HalfWord或Word宽度 |
| 忽略Cache一致性 | CPU读取到陈旧数据 | 使用DTCM或执行Cache清理/失效操作 |
| 中断服务函数执行过长 | DMA传输被阻塞,采样丢失 | 中断中仅做标志位操作,重计算移至主循环 |