STM32 DMA 模块入门

90 阅读6分钟

第一部分:核心原理

1. 什么是 DMA?

定义:DMA (Direct Memory Access,直接存储器访问) 是一个独立于 CPU 的硬件模块。 核心功能:协助 CPU 将数据在外设(如串口、ADC)和存储器(SRAM/Flash)之间,或者存储器存储器之间进行高速搬运。

2. 为什么需要 DMA?(通俗类比)

场景:有一堆快递(数据)到了前台(USART),要搬到仓库(SRAM)。

  • 方式1:轮询 (Polling)

    比喻:老板(CPU)一直盯着前台,来一个快递,老板亲自跑过去搬到仓库。

    缺点:老板完全被占用,没法干别的事(做算法、逻辑控制),效率极低。

  • 方式2:中断 (Interrupt)

    比喻:老板在办公室干活。前台来一个快递就打一次电话(触发中断)。老板停下手中的活,跑去搬一个,回来继续干。

    缺点:虽然老板可以干活了,但如果快递是一卡车一卡车地来(高速数据流,如1M波特率串口),老板电话会被打爆,频繁现场保护/恢复,系统会卡死。

  • 方式3:DMA

    比喻:老板雇了个搬运工(DMA) 。老板交代:“你守在前台,只要有快递,你就直接搬到仓库第X个货架,搬满100个再告诉我。

    结果:老板专心做复杂计算,DMA 默默在后台搬运。解放 CPU!

第二部分:DMA 配置七大要素

在 CubeMX 或代码配置时,必须确认这 7 个参数,错一个数据就跑不通

1. 传输方向 (Direction)

模式全称典型应用场景
P2MPeripheral to Memory (外设→内存)串口接收、ADC 采集数据存入数组
M2PMemory to Peripheral (内存→外设)串口发送、PWM 驱动 WS2812 灯珠
M2MMemory to Memory (内存→内存)数组拷贝 (memcpy 的硬件加速版)、Flash 到 SRAM

注意:Flash 只能读,不能写,所以不能作为目标地址。

2. 数据宽度 (Data Width) [易错点]

原则:源和目标的宽度通常需要匹配。

  • Byte (8-bit) :串口数据(uint8_t)。
  • Half Word (16-bit) :ADC 采集值(uint16_t)。
  • Word (32-bit) :定时器计数器、复杂结构体。
  • 坑点:如果源是 16位,目标是 8位,DMA 传输时可能会发生数据截断或丢失,导致数据错乱。

3. 地址自增 (Increment)

这是新手最容易搞混的地方:

  • 外设地址 (Peripheral) :通常不自增原因:串口的数据寄存器(DR)地址是固定的,是一个“洞”,我们要一直往这个洞里塞数据或拿数据。
  • 内存地址 (Memory) :通常自增原因:我们通常把数据存到数组里,存完 buffer[0],当然要自动移到 buffer[1]。

4. 传输模式 (Mode)

  • Normal (单次模式) :搬完指定数量(如100个)就停工。场景:串口发送一串指令。
  • Circular (循环模式) :搬完一圈自动回到开头覆盖旧数据,永不停歇。场景ADC 连续扫描、后台串口接收缓冲区、音频播放。

5. 优先级 (Priority)

当多个 DMA 通道(如 ADC 和 SPI 同时工作)竞争总线时,谁先传?

  • 等级:Low < Medium < High < Very High。
  • 经验:对时间敏感的(如音频、电机控制)设高一点。

6. FIFO 与 突发模式 (Burst)

  • F1 系列:无 FIFO,傻瓜式直传。
  • F4/F7 系列:有 FIFO(缓存区)。可以攒够 4 个字节再一次性发给内存,减少对总线的访问频次,提高效率。

7. 中断管理

  • TC (Transfer Complete) :全搬完了(最常用)。
  • HT (Half Transfer) :搬了一半(用于音频双缓冲,防止播放卡顿)。
  • TE (Transfer Error) :出错报警。

第三部分:硬件架构区别(F1 vs F4)

1. 总线矩阵

  • DMA1:挂载在 APB1 总线上(低速外设,如 I2C, USART2/3)。F4 的 DMA1 通常不支持 M2M。
  • DMA2:挂载在 APB2 总线上(高速外设,如 SPI1, ADC, USART1)。支持 M2M。

2. 映射方式的区别

  • STM32F1 (固定死板) 通道是固定的硬件连线。例子:ADC1 只能由 DMA1_Channel1 处理,没得选。
  • STM32F4/F7 (灵活映射) 引入了 Stream (数据流)Channel (通道选择) 的概念。一个 DMA 控制器有 8 个 Stream,每个 Stream 可以通过“通道选择”连接不同的外设。这就好比一个插座可以插不同的电器,更灵活。

第五部分:高阶坑点

1. 数据一致性问题 (Cache Coherence) —— F7/H7 系列必坑

  • 问题:F7/H7 带有 Cache(高速缓存)。CPU 读取数据时,可能读的是 Cache 里的旧数据,而 DMA 已经把新数据搬到了 SRAM 里。导致 CPU 读到的不是最新的。
  • 解决:方法一:在读取数据前,调用 SCB_InvalidateDCache_by_Addr() 强制刷新 Cache。方法二(推荐):配置 MPU,把 DMA 用到的那块内存设为 "Non-cacheable"(不使用缓存)。

2. 只有 DMA 就够了吗?(IDLE 中断)

  • 问题:DMA 接收通常需要指定长度(比如100)。但如果对方只发了 5 个字节怎么办?DMA 会一直傻等剩下的 95 个,不会通知 CPU。
  • 黄金搭档DMA + 串口空闲中断 (IDLE Interrupt)原理:DMA 负责搬运,"空闲中断"负责监控。一旦对方停止发送(线路空闲),CPU 触发中断,查看 DMA 搬了多少,立刻处理。这是处理不定长数据的标准解法。

DMA传输完成中断(TC)和半传输中断(HT)的应用

  • 面试题:如何实现无缝音频播放?
  • :使用DMA Circular模式 + 双缓冲机制(或Ping-Pong缓冲)。当DMA触发HT(搬了一半)中断时,CPU去填充前半段数据;当DMA触发TC(搬完了)中断时,DMA自动回到开头播放前半段,CPU去填充后半段数据。这样永远不会卡顿。

3. 只有DMA能减轻CPU负担吗?

  • 陷阱:如果不合理配置,频繁的DMA中断也会累死CPU。
  • 优化:合理设置缓冲区大小,利用FIFO,减少中断触发频率。

4. 什么是DMA的双缓冲(Double Buffer)模式?

  • F4/F7特定功能。DMA自带两个内存指针(M0AR和M1AR)。当DMA正在往Buffer 0搬运时,CPU可以安全地操作Buffer 1,互不干扰。这比手动在中断里切换数组更高效。

5. 假如DMA传输出错了怎么办?

  • 检查TE(Transfer Error)标志位。
  • 常见原因:访问了保留地址、源/目标宽度设置非法、总线冲突严重。