STM32F30x 禁止ADC 已关闭情况下再次关闭ADC 1 c3 |8 Z$ f4 V1 O' {8 \ 前言 STM32F30x 系列的12 位SAR ADC 有很多鲜明的特色性能,比如采样率可以达到5 MSPS,可支持差分输入,等等。但是,由于设计的不同,在使用上也有不少不太一样的地方,我们在使用STM32F30x 的ADC 外设的时候,还是要仔细了解一些使用的细节。2 `; b% k9 ^9 j' M. T, p$ ? 0 d5 S3 ~1 w# a/ x; X% T 问题 某客户在其产品的设计中,使用了STM32F302CCT6。客户在使用过程发现ADC 在工作情况下会有各种各样奇奇怪怪的问题。' ~0 R0 d$ d1 U0 z% ^1 \ 调研 1.了解问题1 [8 C1 w, {1 S; _) \; l 客户在开发中使用了STM32F30x 的标准外设库STM32F30x_DSP_StdPeriph_Lib_V1.2.3,在其程序设计中,ADC1 是在使用的时候才打开的,在不使用的时候将ADC1 关闭。通过调用void ADC_DisableCmd(ADC_TypeDef* ADCx)子程序,执行ADC_DisableCmd(ADC1)将ADC1 关闭。* P2 q1 }$ ]7 o5 f) \ 5 h+ f, |6 o0 {! w% R: O$ a 仔细察看程序,发现程序中在ADC1 的“打开→关闭→打开→关闭→…”循环的关闭中,执行了两次ADC_DisableCmd(ADC1)。. e/ M- n/ X" {/ u8 F d( z! H 1 G+ S# o6 ^: a7 ` g 2.问题分析2 O: K' H B3 f7 \1 | 通过学习STM32F30x 的参考手册,可以知道STM32F30x 在对ADC 进行关闭的操作与其他系列是不一样的;其他系列只要将ADON 位清零就可以停止转换并使ADC 进入掉电模式,而STM32F30x 则不一样,它是通过置位ADDIS 位来关闭ADC的。在void ADC_DisableCmd(ADC_TypeDef* ADCx)程序中也可以看到这一点。9 ]" j2 c, g. H6 s8 v. K 但是,问题来了,ADDIS 位是在什么情况下都可以置位的吗?7 |2 j0 F3 ^1 D; h/ { 我们来看一下参考手册中对关闭ADC 的软件流程的描述: 从描述中,我们可以知道:在置位ADDIS 之前,必须先检测ADSTART 位和JADSTART 位,确保他们为零,也就是说没有正在进行的A/D 转换。在ADC Control register - ADCx_CR 寄存器中对ADDIS 的描述也注明了:; h) g) T3 N: S0 g! V! D) Q 关于这一点,大多数人都是会注意到的。但是,注意这个就够了吗?关于ADC 的控制位,在参考手册特别使用一个小节对向控制位写访问的限制进行详细描述,此小节为“Contraints when writing the ADC control bits”,在这一小节中,有一句话值得注意: 注意这里的用词only if,它的意思是“只有在ADC 是打开状态,而且没有正在等待的关闭ADC 的请求的情况下,也就是在ADEN=1 且ADDIS=0 的情况下,才允许软件对ADCx_CR 寄存器中的ADSTART,JADSTART 和ADDIS 位进行操作。在底下的“Note”注意中写道: 这个注意说,这些禁止的ADC 写访问行为是没有硬件保护去禁止的,错误的操作行为将导致ADC 进入一个未知的状态。要恢复这种状态,必须将ADC 彻底关闭(将ADCx_CR 中的所有位全清零)。 % ^+ b+ O2 ?. }! {% {4 P; r9 j 所以,现在可以知道,ADC1 工作不正常的原因正是因为连续执行了两次ADC_DisableCmd(ADC1)。第一次执行ADC_DisableCmd(ADC1)时,当ADC1 已经有效关闭时,ADEN 和ADDIS 都被硬件清零,这个时候第二次再去写ADDIS 位就是个错误的行为了,将会导致ADC1 进入未知状态。3 F6 @- `7 n! w- d 3.问题解决 在解决问题之前,先来看一下STM32Cube_FW_F3_V1.2.0 库中对ADC 进行关闭的操作。打开stm32f3xx_hal_adc_ex.c 文件,找到static HAL_StatusTypeDef ADC_Disable(ADC_HandleTypeDef* hadc)函数,其程序内容为: 在这个函数注释中有个“Note: forbidden to disable ADC (set bit ADC_CR_ADDIS) if ADC is already disabled.”,再次告诉我们“禁止在ADC 已经被关闭的情况下再次关闭ADC”。然后,程序在运行中先对ADC 是否已经被关闭进行了判断,如果已经被关闭,则不进行关闭操作;未被关闭情况下才会执行关闭操作。/ s+ j+ f) B6 ]5 d4 H2 ? 所以,在使用标准外设库的时候,我们也可以参考Cube 库中的这种操作来进行改善。4 |( @% |' Y) M( O2 e! Y7 P3 L" b3 g 可以考虑对void ADC_DisableCmd(ADC_TypeDef* ADCx)程序进行修改:) ?9 e* l: P; X9 Z5 b3 Z9 J* d 当然,不动void ADC_DisableCmd(ADC_TypeDef* ADCx)程序也可以,只需在用户程序中对这些限制进行判断即可。上面的 while 循环中,也可以加入超时退出机制。( F- w. {' c1 y) J 6 K g; J6 [6 N& J$ R. G 结论 连续两次对ADDIS 控制位进行写1,是错误的操作行为,将会导致ADC 进入未知状态,工作不正常。; C: P: A. K% a 0 d, x, i9 e. b% V' m4 \ 处理6 E1 Z+ ?0 n% u6 z0 C! u% K4 V 修改程序,避免错误的操作行为。7 e" {: y2 Q4 B, [$ X A# B 建议 在使用STM32F30x 系列的ADC 外设时,必须要对控制位的操作限制有明确的了解。在STM32F30x 的“快速ADC 模块”培训资料中,也有对此进行描述,如下:# m6 i7 [5 Z: u6 l% O4 J 最重要还是要看参考手册,多注意一些小细节。 ' A8 v0 m: x0 D: F$ v, _4 \4 X( e 2 P% J# M2 |6 u + _2 O( E' y0 s# \* E9 J9 o & x* |5 {" |: ^% i x |
沙发 沙发 管理员也在学习吗 可以作为一个系列了 |
谢谢 |
基于STM32F334的数字电源
STM32F3DISCOVERY + UCGUI3.90A的移植(源码+视频)
基于STM32F303双电机FOC驱动: 无感原理图/BOM表/代码等开源...
【基于STM32F3的电机控制】_给力外围之 OPAMP
在 STM32 F0、 F2、 F3、 F4 和 L1 系列MCU 中使用硬件实时时钟 (RTC)
基于STM32F334的BUCK同步降压数字电源设计
ST FOC4.3 库关于 STM32F30x 系列 ICS采样代码的修改
STM32F334 上的 ADC 管脚和 DAC 管脚复用问题
如何使用USART或LPUART将STM32F0/F3/L0/L4微控制器从低功耗模式唤醒
在 STM32 F0、 F2、 F3、 F4 和 L1 系列 MCU 中使用硬件实时时钟 (RTC)