【嵌入式面试】DMA 高频面试题
【嵌入式面试】DMA 高频面试题
DMA(直接存储器访问)是嵌入式面试中必考的高频外设,考察点集中在"为什么省 CPU"、通道与请求映射、循环模式/双缓冲,以及串口不定长接收等实战坑上。本文整理了 STM32 DMA 的高频面试题与参考答案,帮助你在面试中把原理、配置与踩坑经验一次说透。
一、基础概念
1. 什么是 DMA?它解决什么问题?
DMA(Direct Memory Access,直接存储器访问)是一个独立于 CPU 的硬件搬运引擎,能在外设与内存、内存与内存之间直接搬移数据,全程不需要 CPU 逐字节参与。CPU 只需配置源地址、目的地址、长度与方向并启动,之后由 DMA 控制器自动完成搬运,解决"CPU 被大量数据拷贝占用"的问题。
2. 为什么 DMA 能减轻 CPU 负担?
数据搬运过程中 CPU 不需要执行任何读写指令,可同时去跑其他任务,只有传输完成(或半传输)时才产生一次中断通知 CPU。例如串口 1Mbps 接收:逐字节中断方式下 CPU 每秒要进约 10 万次中断;用 DMA 后 CPU 只在整包数据收完时被唤醒一次。
3. DMA 与中断有什么本质区别?
中断是由 CPU 执行 ISR 处理数据:每来一个字节,CPU 都要暂停当前任务、压栈、执行搬运代码再出栈;DMA 则由硬件在总线层面直接搬运,CPU 不执行任何搬运指令,只负责配置和事后处理。一句话总结:中断是"CPU 亲自搬",DMA 是"硬件替你搬,搬完再叫你"。
4. DMA 支持哪些传输方向?
共三种:外设 → 内存(如串口/ADC/SPI 接收)、内存 → 外设(如串口/SPI/DAC 发送)、内存 → 内存(M2M,缓冲区拷贝)。前两种由外设硬件请求触发,第三种没有外设请求,需要软件启动。
5. 什么是"外设到内存"传输?典型应用是什么?
配置 DMA 源地址为外设数据寄存器(如 USART_DR)、目的地址为内存缓冲区、长度 N,外设每产生一次数据,DMA 自动搬运一个单位。典型应用:串口接收、ADC 多通道扫描搬运、SPI 接收等,收满 N 个字节触发传输完成中断。
6. 什么是"内存到内存"传输?有什么注意事项?
M2M 模式把一块内存的数据搬到另一块,常用于缓冲区复制、数据结构整理,搬运不占用 CPU 执行周期。注意事项:M2M 没有外设请求,需软件启动;搬运期间 DMA 与 CPU 争用总线,CPU 访问速度可能变慢;按 F103 参考手册(RM0008),内存到内存模式由 DMA2 支持。
二、通道、宽度与模式
7. 什么是 DMA 通道?什么是请求映射?
通道是 DMA 控制器内部独立的搬运引擎(F1 的 DMA1 有 7 个通道、DMA2 有 5 个),每个通道可服务一个外设。请求映射指每个通道能响应的外设请求是固定的,例如 F103 的 DMA1 通道 5 可服务 USART1_RX、通道 4 可服务 USART1_TX。使用前必须查数据手册的 DMA 请求映射表选对通道;同一时刻一个通道只能服务一个外设。
8. F103 的 DMA1/DMA2 如何分工?
F103 有 DMA1(7 通道)+ DMA2(5 通道)。DMA1 服务常规外设:ADC1(通道 1)、USART1_TX(通道 4)、USART1_RX(通道 5)以及 SPI、I2C、TIM 等;DMA2 主要服务 ADC2/ADC3、SDIO、TIM1 等。通道与外设的对应关系固定,配置前务必查映射表;F4 系列改为 DMA 流(Stream)+ 可配置请求,更灵活。
9. 什么是数据宽度(PSIZE/MSIZE)?两侧不一致怎么办?
DMA 传输宽度分字节(8 位)、半字(16 位)、字(32 位),外设侧(PSIZE)与内存侧(MSIZE)可分别配置。两侧宽度不一致时,DMA 会自动打包/解包(如外设 8 位、内存 16 位时,两个字节拼成一个半字)。宽度应与数据实际类型匹配(ADC 12 位结果建议用半字),并注意内存地址对齐到对应宽度。
10. 什么是循环模式(Circular)?典型应用是什么?
循环模式下 DMA 搬完设定长度后自动把地址指针重置回缓冲区起始,继续下一轮传输,无需重新配置。典型应用:ADC 连续采样 + DMA 循环、串口 DMA 循环接收。配合半传输/传输完成中断,CPU 可在 DMA 写前半段时处理后半段数据,实现无缝流水。
11. 什么是双缓冲?如何实现"乒乓"?
双缓冲准备两个等长缓冲区:DMA 正在填充 A 时 CPU 处理 B,DMA 切到 B 时 CPU 处理 A,交替进行(乒乓操作)。F4 的 DMA 流有硬件双缓冲(DBM 位);F1 没有硬件支持,可用两个缓冲区 + 半传输中断模拟。好处是 CPU 与 DMA 互不等待,避免处理期间数据被覆盖。
12. 半传输中断(HT)与传输完成中断(TC)分别是什么?
传输完成中断(TC)在设定长度数据全部搬完时触发;半传输中断(HT)在搬完一半时触发。HT 的意义在于:循环模式下 DMA 写满前半段时先通知 CPU,CPU 处理前半段数据,同时 DMA 继续写后半段,等 TC 再处理后半段——把缓冲区一分为二流水处理,防止数据覆盖和丢包。
13. DMA 单次最多能传输多少数据?
F1/F4 的传输长度寄存器 NDTR 为 16 位,单次最多 65535 个单位(单位 = 数据宽度:字节/半字/字)。超过该长度必须分多次配置,或在循环模式下分段搬运。这也说明 DMA 适合"批量搬运",单次搬运量有上限。
三、实战与常见坑
14. 使用 DMA 的常见坑有哪些?
① 传输未完成就修改源/目的缓冲区,数据被破坏;② Cache 一致性问题(Cortex-M7 如 H7 系列);③ 缓冲区地址未对齐;④ 循环模式下数据未及时取走被覆盖;⑤ 误以为串口发送的 TC 等于"发完了"(TC 只代表数据进了 DR,最后一字节还在移位寄存器中);⑥ 内存到内存时与 CPU 争用总线。
15. 为什么 DMA 传输期间不能修改缓冲区?如何避免?
DMA 按配置的源地址连续读、目的地址连续写,若传输未结束就修改源缓冲区会搬出错误数据,修改目的缓冲区会被 DMA 覆盖。正确做法:等待传输完成标志(TC)或传输完成中断后再读写缓冲区;循环模式下配合 HT/TC 中断,保证正在被 DMA 写入的半区不被 CPU 触碰。
16. 什么是 Cache 一致性问题?为什么 DMA 会踩坑?
Cortex-M7(如 STM32H7)有 D-Cache:CPU 通过 Cache 读数据,而 DMA 直接访问 RAM。DMA 写入 RAM 后,Cache 中可能还是旧数据,CPU 会读到脏数据;反之 CPU 写完未回写(Clean),DMA 可能搬走旧数据。解决:DMA 前后做 Cache 维护(Clean/Invalidate),或把缓冲区放到非 Cache 区(MPU 配置)。F1/F4 无 D-Cache,不存在此问题。
17. 为什么 DMA 缓冲区要注意内存对齐?
DMA 按传输宽度(字节/半字/字)和突发(burst)方式访问内存,缓冲区起始地址应按数据宽度对齐(如字传输要求 4 字节对齐)。地址未对齐可能导致总线错误(Bus Fault)或传输异常,F4 流模式配置突发传输时尤其严格。C 语言大数组通常天然对齐,但要避免在结构体中间取缓冲区。
18. 如何用串口空闲中断 + DMA 接收不定长数据?
核心是 DMA 循环模式 + 串口空闲(IDLE)中断:DMA 把收到的字节连续写入缓冲区,当串口总线出现空闲(无数据)时触发 IDLE 中断,在中断里读取 DMA 当前计数(NDTR)反推本次收到的字节数,即一帧不定长数据结束。相比逐字节中断,CPU 几乎不被打扰,适合高波特率、帧长不固定的场景(如 AT 指令、MODBUS)。
19. 串口 DMA 循环接收为什么要配环形缓冲区?半传输中断起什么作用?
循环模式下缓冲区写满会回绕覆盖,CPU 处理不及时就会丢数据。用环形缓冲区管理读写指针,并通过 HT(半传输)+ TC(传输完成)中断分段处理:DMA 写前半段时 CPU 处理上一轮后半段,写后半段时处理前半段,保证处理速度跟得上接收速度。处理时先根据指针计算本次有效长度,再拷贝或原地解析。

