STM32 DMA配置与数据流
本文概述:DMA(直接存储器访问)是STM32开发的核心技能,面试常考。核心结论是:DMA配置分为通道选择、数据方向与宽度、传输模式与数量、中断配置四个步骤,按顺序一步步来基本不会错。回答时要讲清楚每个步骤做什么、为什么这么做、常见的坑在哪里,还要能排查传输失败、数据错位、中断不触发等常见问题。

核心要点速览

  • 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和CPU同时访问内存会冲突吗?
不会冲突。STM32的总线矩阵支持DMA和CPU同时访问不同的内存区域或外设。当两者访问同一区域时,总线仲裁器会根据优先级调度,DMA优先级可以配置。一般情况下DMA传输不会明显影响CPU执行,除非连续大量数据传输占用总线带宽。
DMA传输完成后怎么通知CPU?
主要有三种方式:一是DMA传输完成中断,传输结束后触发中断让CPU处理;二是查询DMA传输完成标志位,CPU轮询检查状态;三是用外设的握手信号,比如DMA传完一帧数据后触发定时器或其他外设。最常用的是中断方式,效率最高。
DMA的循环模式和正常模式有什么区别?
正常模式下,DMA传输完设定的数据量后就停止,需要重新配置才能再次传输。循环模式下,传输完成后自动重装计数值,重新开始下一轮传输,不需要CPU干预。循环模式适合连续采集数据的场景,比如ADC连续采样、串口环形缓冲区等。

核心关键词

DMA配置、通道选择、数据宽度、循环模式、传输完成中断、半传输中断、NDTR寄存器、FIFO模式、总线矩阵、双缓冲