你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

经验分享 | 为什么重启ADC的DMA传输要先停掉ADC?

[复制链接]
STMCU小助手 发布时间:2025-11-17 09:44

有人使用STM32G4系列芯片的ADC,通过定时器定时触发ADC,并开启ADC数据的DMA传输。DMA工作在Normal模式。可他发现,每当他在DMA完成中断里完成相关数据处理后,准备重启ADC的DMA传输时,发现必须先关闭ADC,否则ADC的DMA传输根本不起作用。补充下,他基于STM32的HAL库组织代码。

下图是它提供的部分代码信息:

image.png

他的疑惑是,为什么在DMA完成中断里的要加上ADC_Stop()和ADC_Start_DMA ()才能继续后续ADC的DMA传输?如果没有这两句话,就无法正常进入该DMA完成中断。按理说他已经配置了TIMER周期性地触发ADC,ADC就应该以同频率被触发采样,最后自动再次进DMA中断。

应该说该用户是找到解决方法了,但还是想寻觅一下问题原因。

我模拟他的应用场景做了验证测试。可以重现它的现象及问题。一起来看看。

首先,他现在的DMA工作在Normal模式,每次传输一轮数据后DMA会自动停下来,所以重启DMA是必须的。如果他对DMA的这个特性了解,也该不会对此存疑了。

当然,他更大的疑惑可能在于为什么启动ADC的DMA传输要先停止ADC模块。

经阅读相关代码,这里有个很重要的直接原因,那就是跟他现在调用的API库函数ADC_Start_DMA ()有关。

在该API函数代码里有对ADC工作状态的检查。见下面代码【我稍作了整理】:

if (LL_ADC_REG_IsConversionOngoing(hadc->Instance) != 0UL) { tmp_hal_status = HAL_BUSY;return tmp_hal_status; }

如果检查到ADC还在工作状态,程序则不会做相应准备及启动而是直接基于busy状态返回退出,即ADC相关的DMA传输就根本没有进行配置及使能,后续的ADC数据的DMA传输就无从谈起,更别说产生DMA完成中断了。

换言之,这里想让ADC_Start_DMA ()正常运行、完成相应的ADC及DMA配置,就必须事先关闭ADC。这样做的话,保障每次开启ADC及DMA传输时尽可能是从头开始,便于数据的同步及管理,避免产生混乱。

另外,我在测试时,进入DMA完成中断后,还先做了TIMER的停止操作,直到ADC及DMA配置完成后我才再次启动TIMER计数。

鉴于当前应用,如果我们自行组织代码可能就不一定要做ADC的停止操作。在重启ADC的DMA传输前,保证没有ADC的EOC事件或溢出事件存在即可。

由于这里的ADC是被TIMER触发的,建议在进DMA完成中断后先把TIMER停掉,然后将ADC的转换完成标志和溢出标志都清一遍,至于是否停止ADC就无所谓了,之后再做ADC的DMA配置及使能,一切就绪后重新启动TIMER,开始下一轮数据的产生及传输。这样设计,逻辑和时序也都比较清晰。

本话题就聊到这里。总之,要了解问题的真实原因可能离不开实际测试及相关代码的研读。

顺便再聊聊另一个话题来结尾,为什么IDE中Memory窗口和汇编窗口看到的32位指令不一致?

情况是这样的,有STM32用户无意中发现调试环境下的汇编窗口的32位指令编码跟Memory窗口的存放效果不一致,或说看起来有点异样。下图为用户提供的信息,就是一条MOV汇编代码的指令编码及该指令码在Flash闪存中的摆放情形。

image.png

他认为,既然STM32 微处理器都使用小端存储模式,按照小端模式特点,这条32位的指令不应该被解释为0800f04f吗?为什么是f04f0800?

先对大小端存储模式稍作解释:

小端模式下,多字节数据的低字节存储在内存的低地址处,高字节存储在内存的高地址处。

大端模式下,多字节数据的高字节存储在内存的低地址处,低字节存储在内存的高地址处。

其实,对于Thumb指令,既有16位编码方式,也有基于双半字指令的32位编码方式。此时我们在汇编窗口看到的这个32位宽指令 并非真正的ARM指令,它依然是THUMB指令,只是使用了32位宽的指令编码,它由前后两个半字指令编码组成。这两个半字指令码只是前后关系,没有大小关系或高低关系。

我们不妨看看下面MUL乘法指令的编码。有3种编码,其中前2种都是THUMB指令编码,第3种是ARM指令编码。

image.png

ARM指令编码是由bit0~bit31依序按照高低顺序组成的4字节32位编码。

我们再看图中第2个指令编码,虽然也是32位,但它实质是由前、后2个半字指令拼起来的,仍然是Thumb指令,而不是ARM指令,只是另一种Thumb指令编码方式。【在STM32微处理里的指令编码都是Thumb指令,没有ARM指令。】

我顺便也把MOV指令可能的Thumb指令编码方式拿过来一起看看。我从ARM相关手册截图过来放在下面。

image.png

从上图我们可以知晓,MOV的Thumb指令编码可以有三种。

根据前面给出的当前指令编码信息F04F0800来看,可以推断出目前用户的IDE使用的是图中第2种双半字编码方式。怎么不是第3种编码方式有兴趣的可以细看下。

既然这里的32位Thumb指令编码,是由前后2个半字指令组合起来的。那么,前面的指令码放在低位地址先执行,后面指令码放在高位地址后执行,就好理解了。

而对于每个半字指令码来说,的确由高、低字节组成。依据小端模式,低位字节放低位地址,高位字节放高位地址。按照这样分析,就不难理解当前指令编码在内存中的存放顺序了。

image.png

这个问题主要涉及STM32芯片内核的东西,即 ARM Cortex-M内核相关知,了解下无妨。这里算是抛砖引玉吧。

OK,上面两个话题都来自ST中文社区,稍作整理分享于此,以供参考。下次再聊。

文章出处:茶话MCU

收藏 评论0 发布时间:2025-11-17 09:44

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版