STMCU小助手
发布时间:2025-11-17 09:44
|
有人使用STM32G4系列芯片的ADC,通过定时器定时触发ADC,并开启ADC数据的DMA传输。DMA工作在Normal模式。可他发现,每当他在DMA完成中断里完成相关数据处理后,准备重启ADC的DMA传输时,发现必须先关闭ADC,否则ADC的DMA传输根本不起作用。补充下,他基于STM32的HAL库组织代码。 下图是它提供的部分代码信息:
他的疑惑是,为什么在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闪存中的摆放情形。
他认为,既然STM32 微处理器都使用小端存储模式,按照小端模式特点,这条32位的指令不应该被解释为0800f04f吗?为什么是f04f0800? 先对大小端存储模式稍作解释: 小端模式下,多字节数据的低字节存储在内存的低地址处,高字节存储在内存的高地址处。 大端模式下,多字节数据的高字节存储在内存的低地址处,低字节存储在内存的高地址处。 其实,对于Thumb指令,既有16位编码方式,也有基于双半字指令的32位编码方式。此时我们在汇编窗口看到的这个32位宽指令 并非真正的ARM指令,它依然是THUMB指令,只是使用了32位宽的指令编码,它由前后两个半字指令编码组成。这两个半字指令码只是前后关系,没有大小关系或高低关系。 我们不妨看看下面MUL乘法指令的编码。有3种编码,其中前2种都是THUMB指令编码,第3种是ARM指令编码。
ARM指令编码是由bit0~bit31依序按照高低顺序组成的4字节32位编码。 我们再看图中第2个指令编码,虽然也是32位,但它实质是由前、后2个半字指令拼起来的,仍然是Thumb指令,而不是ARM指令,只是另一种Thumb指令编码方式。【在STM32微处理里的指令编码都是Thumb指令,没有ARM指令。】 我顺便也把MOV指令可能的Thumb指令编码方式拿过来一起看看。我从ARM相关手册截图过来放在下面。
从上图我们可以知晓,MOV的Thumb指令编码可以有三种。 根据前面给出的当前指令编码信息F04F0800来看,可以推断出目前用户的IDE使用的是图中第2种双半字编码方式。怎么不是第3种编码方式有兴趣的可以细看下。 既然这里的32位Thumb指令编码,是由前后2个半字指令组合起来的。那么,前面的指令码放在低位地址先执行,后面指令码放在高位地址后执行,就好理解了。 而对于每个半字指令码来说,的确由高、低字节组成。依据小端模式,低位字节放低位地址,高位字节放高位地址。按照这样分析,就不难理解当前指令编码在内存中的存放顺序了。
这个问题主要涉及STM32芯片内核的东西,即 ARM Cortex-M内核相关知,了解下无妨。这里算是抛砖引玉吧。 OK,上面两个话题都来自ST中文社区,稍作整理分享于此,以供参考。下次再聊。 文章出处:茶话MCU |
经验分享 | 使用GPIO+DMA+TIM模拟SPI通信演示
经验分享 | STM32 ADC过采样话题
经验分享 | 多个SPI的DMA传输为何仅1个有效?
经验分享 | STM32 DMAMUX应用示例
经验分享 | STM32双定时器+ADC+DMA实战案例
经验分享 | STM32U5系列TIMER+DMA+DAC应用演示
经验分享 | 基于STM32片内信号的ADC应用演示
经验分享 | STM32F0 ADC结果挪位的问题分析及解决
经验分享 | 基于STM32H7 UART 空闲事件及DMA传输示例
经验分享 | 关于STM32 DMA传输的两个问题释疑
微信公众号
手机版