33.DMA.md 7.5 KB

DMA 数据传输

判别规则(核心,唯一要记的)

  1. 该不该用 DMA:大量/连续数据 CPU 要同时干别的 → DMA;数据少/低频 → 中断/轮询(配置开销不划算)
  2. 普通 vs 循环:传完一次就结束(一次性任务/固定采样)→ 普通(NORMAL);需要"永不停"的流(音频/连续采样/不定长串口接收)→ 循环(CIRCULAR),CNDTR 到 0 自动重装
  3. 方向看"谁流向谁":内存→外设 = M2P(发送);外设→内存 = P2M(接收/采样);内存→内存 = M2M(搬运,免外设请求,配置完置 EN 立即启动

一句话:"量大且 CPU 要干别的才用 DMA;传完就停用普通、永不停用循环;方向看数据从哪流向哪,M2M 免请求。"

抽象描述(一句话本质)

把 DMA 想成专职工人搬货:CPU 只"下单"(配置)不"搬货",DMA 把外设和内存之间的数据直接搬好,搬完发 1 次完成中断喊一声。搬数据有三种干法:轮询 = CPU 站在那儿干等中断 = CPU 每搬一字节被打断一次DMA = CPU 全程不用管

三种搬运方式对比

方式 CPU 参与 100 字节代价 适用
轮询 死等 CPU 全程被绑住,啥也干不了 极简单/调试
中断 每字节打断一次 进 100 次中断,每次现场保存/恢复 数据少/低频/需即时处理
DMA 零参与 配置一次,搬完只进 1 次完成中断 大量/连续 + CPU 要干别的

传输方向三选一

方向 谁流向谁 典型场景 谁启动
M2P 内存 → 外设寄存器(如 USART1->DR) 串口发一批数据 等外设请求(如开 `USART1->CR3
P2M 外设寄存器 → 内存 串口接收 / ADC 连续采样 等外设请求(RXNE)
M2M 内存 → 内存 Flash→SRAM、拷数组 免请求,置 EN 立即搬完(MEM2MEM 位)

普通 vs 循环(核心)

普通 NORMAL 循环 CIRCULAR
CNDTR 到 0 停止 + 完成中断 自动重装回初始值,继续搬
适用 一次性任务(发一批字符串、固定 1000 次采样) 持续流(音频、连续采样、不定长串口接收)
生活类比 送完这趟就下班 送完一趟接下一单,永远不停
配错的后果 该循环配普通 → 传完一批就断流 该普通配循环 → 数据反复重发/覆盖

配置要点与坑

  • 顺序:参数全配好(CPAR/CMAR/CNDTR/CCR)→ 最后才置 EN
  • CNDTR:16 位,上限 65535;超过分段或循环
  • 地址递增:外设寄存器地址固定 → PINC 关;内存缓冲区连续 → MINC 开
  • 通道冲突:同一通道同一时刻只能服务一个外设
  • 外设请求:M2P/P2M 必须开外设的 DMA 请求位,否则通道配了也不动
  • Cache 一致性:Cortex-M7 需注意;F103 无 Cache 不用担心
  • M2M 方向反直觉:MEM2MEM 模式下 CPAR 放目的、CMAR 放源

正反例(建立直觉)

  • 正例1:串口一次发 1KB,CPU 同时跑业务 → 用 DMA(大量 + CPU 要干别的)
  • 正例2:ADC 连续采样 1000 次存内存 → 用 DMA(P2M,量大持续)
  • 反例1:每秒收 1~2 个命令字节 → 中断就够(数据太少,DMA 配置开销 > 收益)
  • 反例2:每次搬完都要立刻处理该字节 → 用中断(DMA 攒一批才通知,实时响应反而慢)

易混对比

DMA vs 中断

DMA 中断
搬数据 DMA 控制器搬,CPU 零参与 CPU 每字节进 ISR 搬
中断次数 搬完只 1 次 每字节 1 次
适用 量大/连续 量少/低频/需即时处理

外设请求 vs 启动(M2P/P2M vs M2M)

M2P/P2M M2M
要不要外设请求 要(TXE/RXNE 决定每步何时搬) 不要,置 EN 立即搬完
生活类比 货现产现送,货到了才搬 货全在仓库,直接搬

变体验证(3 题,全过=学会)

  1. 串口每秒只收 1~2 字节命令,主循环跑 UI → 用中断(数据少,DMA 配置开销远大于收益)
  2. 陷阱题:ADC 连续采样固定 1000 次采完一次性处理 → 普通模式(固定次数、采完就停;循环模式用于永不停流,会不断覆盖缓冲)
  3. 陷阱题:"内存→内存 DMA 和内存→外设一样,都要等外设请求才启动" → ,M2M 免请求立即启动,只有 M2P/P2M 等外设请求

口述要点(面试怎么讲)

  • 结论先行:量大且 CPU 要干别的 → DMA;传完就停用普通、永不停用循环;方向看谁流向谁
  • DMA 省在哪:中断搬 100 字节 = 100 次现场保存/恢复、CPU 每字节被打断;DMA = 配置一次零参与,只进 1 次完成中断
  • 为什么不能全用 DMA:启动有配置开销,数据少/低频收益低;"攒一批才通知"在需即时处理场景反而实时性差
  • 为什么方向/模式要在启动前想清楚:方向决定"要不要外设请求(TXE/RXNE)、谁的地址递增(外设固定/内存递增)";普通/循环决定"CNDTR 到 0 停不停(自动重装)"。三者构成传输闭环。类比:方向 = 取货送货路线,普通/循环 = 送完下班还是等下一单,外设请求 = 货现产现送,M2M = 货全在仓库不用等
  • 易错点:忘开外设 DMA 请求;方向配错;该循环配普通断流;忘配 NVIC(完成中断不来);CNDTR 超 65535

关系网络

相邻概念 关系 孤立理解会犯的错
中断 DMA 每字节不打断 CPU,搬完才发 1 次完成中断 以为 DMA 不产生中断
NVIC DMA 完成中断同样要配优先级/使能 只配 DMA 不配 NVIC,中断永远不来
串口/ADC 典型应用 HAL_UART_Transmit_DMA / Receive_DMA;开 CR3.DMAT 忘开外设 DMA 请求,通道配了也不动
内存(Cache) M7 需 Cache 一致性;F103 无 Cache 移植 M7 忽略 Cache,搬完读到旧值
中断优先级(主题 32) DMA 完成中断走 NVIC 优先级体系 优先级方向与 FreeRTOS 混淆

学习日期

2026-08-18


每主题一页,复习时只翻本目录。