
核心要点速览
DMA配置四步走:选通道和请求、设数据参数、配传输模式、开中断
通道选择要看外设对应的DMA请求映射,不能随便选
循环模式适合连续采集,正常模式适合单次传输
数据宽度要源和目的匹配,否则会出现数据错位
传输完成一半也可以触发中断(半传输中断),用于双缓冲
面试题
STM32的DMA怎么配置?传输失败常见原因有哪些,怎么排查?
面试官考察点
面试官问DMA,主要看三个方面:一是你有没有实际用过DMA,还是只停留在概念层面;二是你对STM32的总线结构和外设映射有没有概念;三是你解决问题的思路清不清晰,遇到DMA传输异常时能不能系统性排查。
回答思路
第一步:选择DMA通道和请求
DMA不是想接哪个外设就接哪个的,每个外设对应固定的DMA请求通道,要查参考手册里的DMA请求映射表。
比如STM32F1系列,USART1_TX对应DMA1通道4,ADC对应DMA1通道1。F4系列更复杂,有DMA1和DMA2两个控制器,每个流(Stream)有多个通道可选,需要配置通道选择位。
注意:同一个DMA通道同时只能服务一个外设。如果两个外设都要用DMA,要选不同的通道,否则会冲突。高优先级的可以抢占低优先级的,但实际用的时候尽量避免同一通道多个外设竞争。
第二步:配置数据传输方向和宽度
确定数据从哪里来、到哪里去、每次传多少。
传输方向有三种:外设到内存(比如ADC采样、串口接收)、内存到外设(比如串口发送、DAC输出)、内存到内存(比如内存拷贝,部分系列支持)。
数据宽度要源端和目的端匹配:字节(8位)、半字(16位)、字(32位)。如果源是8位外设、目的是32位内存,要注意数据对齐方式和位宽转换设置,否则读出来的数据可能错位。
地址增量模式也是在这里设的:外设地址一般不增量(因为固定在同一个数据寄存器),内存地址一般要增量(每次传完移到下一个位置)。
第三步:设置传输模式和数据量
选择传输模式,设置要传多少个数据。
传输模式主要有两种:正常模式(Normal)传完就停,需要重新配置才能再传;循环模式(Circular)传完自动重装计数,连续不断地传。ADC连续采样、串口环形缓冲区这种场景就适合用循环模式。
数据量(NDTR寄存器)是要传输的数据项数,不是字节数。比如配置的是字传输,NDTR设100就是传100个字(400字节)。传输过程中NDTR会递减,传完后变成0。
第四步:配置中断并启动传输
设置好中断,使能DMA,让传输跑起来。
DMA有三种中断:传输完成中断(TC)、半传输中断(HT)、传输错误中断(TE)。传输完成中断用得最多,传完了通知CPU。半传输中断在双缓冲场景很有用,传一半时CPU可以处理前半段数据,DMA继续传后半段,实现流水线式处理。
启动顺序:先配置好DMA的所有参数,再使能DMA通道,最后使能外设的DMA请求。顺序不能反,否则可能导致第一次传输的数据不对。
常见问题排查
问题一:DMA完全不工作,一个字节都不传
排查顺序:第一,检查DMA时钟有没有开(RCC_AHBENR寄存器);第二,检查通道和请求是否匹配,有没有选错通道;第三,检查DMA使能位有没有置1;第四,检查外设的DMA请求位有没有打开(比如USART的DMAT位);第五,检查NDTR是不是设成0了。
问题二:数据错位或只有第一个字节正确
多半是数据宽度设置不对。比如外设是8位的,DMA配置成了16位传输,每次就读两个字节,但外设只有一个字节有效,另一个是无效数据。检查源端和目的端的数据宽度是否和实际外设位宽匹配。另外还要注意内存地址对齐,32位传输要保证内存地址是4字节对齐。
问题三:传输完成中断不触发
首先检查传输完成中断使能位(TCIE)有没有开;其次检查NVIC里DMA通道对应的中断有没有使能,优先级有没有配置;最后确认中断函数名对不对,是不是写错了函数名导致没进中断。STM32的中断函数名是固定的,写错了不会报错但进不去中断。
问题四:循环模式下数据覆盖了还没处理
这是典型的生产者-消费者速率不匹配问题。如果CPU处理速度跟不上DMA传输速度,循环模式下新数据会覆盖旧数据。解决方法:一是用双缓冲模式(F4系列支持),两个缓冲区交替使用;二是用半传输中断,在传一半时就开始处理前半段;三是提高CPU处理优先级或者优化处理算法。
追问方向
追问一:DMA传输期间CPU能访问内存吗?
可以。STM32的总线矩阵支持多个主机(CPU、DMA、USB等)同时访问不同的从机(内存、外设)。只有当DMA和CPU同时访问同一个内存区域时,才会发生总线仲裁,谁优先级高谁先访问。一般情况下DMA传输对CPU执行的影响很小,除非是连续大量的数据传输持续占用总线带宽。
追问二:FIFO模式和直接模式有什么区别?
这是STM32 F4及以上系列才有的功能。直接模式下,DMA收到一个数据就立刻传走,没有缓存。FIFO模式下,数据先存到内部的FIFO(先进先出缓冲区)里,攒到一定数量再一起传输。FIFO模式的好处是可以减少总线访问次数,提高传输效率,还支持数据打包(比如把4个字节打包成一个字传输)。缺点是配置稍复杂,还有一定的延迟。
追问三:DMA和中断方式传输数据,哪种更好?
要看场景。DMA适合大量数据的连续传输,比如ADC采样、图片数据、音频流,这时候用DMA可以解放CPU,让CPU同时干别的事。中断方式适合少量、不定时的数据传输,比如几个字节的串口命令。少量数据用DMA反而可能因为配置和启动开销,效率不如直接中断。而且DMA本身也会用中断来通知传输完成,两者不是互斥的,经常配合使用。
追问四:内存到内存的DMA传输需要注意什么?
首先不是所有STM32系列都支持内存到内存传输,要看具体型号。其次内存到内存传输只能用特定的DMA控制器(F1系列是DMA1还是DMA2要看手册)。第三是数据宽度要一致,源和目的都要是8位、16位或32位。最后是传输过程中NDTR会递减,可以读这个寄存器来判断传输进度。
失分表达
常见失分点一:"DMA通道随便选一个就行"
DMA通道和外设请求是有映射关系的,不是随便选。选错了通道DMA根本不会工作。面试时要说明需要查参考手册的DMA请求映射表,根据所用的外设来选对应的通道。
常见失分点二:"NDTR设的是字节数"
NDTR是数据项数,不是字节数。数据宽度是字节就是字节数,是字就是字数。很多人在这里搞混,导致传输的数据量不对或者数组越界。回答时要明确说清楚NDTR的含义。
常见失分点三:"DMA比中断快"
这个说法不准确。DMA的优势是不需要CPU干预,可以连续传输数据,但单字节的传输速度不一定比中断快。DMA的价值在于解放CPU,让CPU在传输期间可以做其他事情,而不是传输速度本身更快。
准备动作
实操准备
找一块STM32开发板,动手做三个实验:一是用DMA方式实现串口发送字符串;二是用DMA+ADC实现连续采样,把结果存到数组里;三是实现内存到内存的DMA拷贝,和memcpy对比一下效率。把三个实验的代码整理好,面试时可以直接说自己做过哪些DMA相关的项目。
知识点巩固
对照参考手册,把你常用的STM32型号的DMA请求映射表过一遍,记住几个常用外设对应的DMA通道。复习一下DMA的各个寄存器:CCR、CNDTR、CPAR、CMAR,知道每个寄存器管什么。
常见问题补充
核心关键词
DMA配置、通道选择、数据宽度、循环模式、传输完成中断、半传输中断、NDTR寄存器、FIFO模式、总线矩阵、双缓冲

扫码关注





























