
有人在使用STM32G0芯片的ADC模块时,往往因为扫描模式的理解不到位或选择不当导致些问题。这里就该话题做点简单分享介绍,不妨以一个实例展开。. L1 B3 \$ b! q$ _ 4 Y, C! Y% ]. x, h+ Z7 M 现在共用到ADC1模块的4个ADC通道,即1个片内Vrefint通道和其它三个外部通道CH8,CH10,CH17。下面测试代码中使用DMA传输,定时器触发ADC.; S- ?0 j4 C4 k9 a3 _' N3 v / [! R1 G" N: `% h: e/ c ![]() 它们的硬件连接情况如下,其中VRefint为内部参考电压,其电压值大概1.2V样子。1 d, D$ @+ `5 q0 m ![]() 对于STM32G0系列,ADC扫描模式可以有两种,分别是不完全配置序列模式和完全配置序列模式。我们先看看不完全配置序列模式。 % Z q0 o) b- ], ~ 不完全配置序列模式# i& p+ v3 O2 o! m5 I, S 在该模式下,ADC_CFGR1寄存器中的CHESELRMOD位必须被清零。2 Z3 H+ t7 A* m6 X3 R0 N 被转换通道的扫描顺序按照ADC通道固有序号的大小顺序依次进行,扫描方向可以软件配置为向前【forward】或后退【backward】。任何ADC通道都可以配置进该序列中,总的序列长度由寄存器ADC_CHSELR中被置位的CHSELx个数决定,最多可配置18个通道。0 i; t9 z% F5 G7 @ 8 J0 Q' k& f& I4 W8 W7 I1 ] 我们以上面提到的CH8、CH10、CH17和VRefint通道【它对应ADC通道CH13】为例,若将上述4个通道配置为不完全序列模式,只需将ADC_CHSELR寄存器中的CHSELx相应位进行置1即可。如下图所示: u5 ?9 V' w0 Z* j8 ^ ![]() 若选择forward扫描模式,则按通道号从小到大的顺序依次实施转换,生成对应于CH8、CH10、CH13、CH17的结果。使用STM32CubeMx的配置如下:( q1 u1 \& d7 w" m9 b' }9 K ![]() # G& u" I* H+ _1 e; K 既然扫描按默认通道号大小顺序进行,自然就无须RANK顺序的配置了。 编译运行后可以看到结果,我在内存里放了两组数据以便比较观察。3 j4 X' H" ]9 j 9 v X7 |- D9 _% d( F4 a ![]() 0 [8 s8 M: @( b" f& R$ L! X; Z6 \ 从结果来看跟实际情况是一致的,转换结果依次来自CH8/CH10/CH13/CH17。其中那个149x数值来自对内部Vrefint的转换结果。 那么,对于同样的ADC通道及硬件连接,若采用完全配置序列模式会怎么样呢? 完全配置序列模式$ e" x6 _$ y* z) f# @/ `5 S/ b' @ 在该模式下,ADC_CFGR1寄存器中的CHESELRMOD位必须被置1。* {8 V2 ~" f6 g6 c+ g- ]- N* w $ ?& ?0 c8 n! i) b" D 全序列可支持的通道数最多8个,扫描顺序不是依照硬件约定的通道号来安排,而是依据ADC_CHSELR寄存器中的从SQ1[3:0]到SQ8[3:0]所选择的通道顺序进行,即按照我们在CubeMX或代码中配置的RANK顺序进行,不再涉及扫描方向forward/backward的配置,并且只有通道0 到 通道14可以被选择!4 l x( V' ^0 ^; W" S1 Q ![]() + M; U, m7 D- F8 s, t 还有,当SQn[3:0]里的赋值等于0b1111,即0x0f时则该通道选择域以及后续SQn的通道选择无效。比方说,假设SQ3[3:0]的数据为0b1111,则表示从SQ3[3:0]开始直到SQ8[3:0]的通道选择无效。由于SQn[3:0]才4位,所有它也没法选择高于14的有效通道号。【请特别注意这些特性!】% w5 F( d$ Q7 W" Y1 K; U 看到这里,我们不禁想到前面预先安排的4个通道中的有个CH17,显然不适合这种模式。如果被错误地强行使用该模式,基于CubeMx配置和现有Cube库所产生的代码运行结果会怎么样呢?3 m% ?$ Y n1 F2 A: ^/ {) f 7 H- v: `) u1 A5 G2 z& g; I 先用CubeMX进行配置:! [) f& }+ Y( Y ![]() 4个通道的扫描顺序配置如下,相比前面多了RANK顺序配置。# F! Y, k! f4 Z ![]() t4 M6 ~% x2 s- v5 Y y- |+ }0 k2 K 先撇开CH17合法性不谈,不难看出这里跟前面的扫描顺序配置有点不一样,这里的配置为我们提供了更多的自主性及便利性,转换扫描并不固定于通道号的顺序,具体由SQn[3:0]的配置选择决定。我这里让SQ1选择CH8,SQ2选择CH10,SQ3选择CH17,SQ4选择CH13,分别对应配置中的RANK1、RANK2、RANK3、RANK4顺序。 编译运行查看结果: ![]() ( t3 _' ~$ X4 J1 P- j 前面说过,CH17硬件上是接地的,显然此时对应于CH17的转换值【绿色箭头所指】跟实际情况完全不符,其它三个倒是跟实际情况吻合。409x对应CH8接VDD,0对应CH10接GND,149x对应内部vrefint。/ P; n; @* h1 u) p# t: Q7 f ( \/ N/ t1 `5 e" _ 我尝试将CH17接到VDD,转换结果还是跟实际情况还是完全不相符。# w% V5 I7 F( y8 s4 `0 B! Q ; `- J X) R' e( \2 l8 J 结合上面的介绍,我们知道对于完全配置序列模式不能选用高于通道14的通道号。我们不妨通过寄存器进一步看看,当我们错误地强行使用CH17时在现有库代码的情况下,对应的SQ3[3:0]真正的值是多少?到底选择了什么通道?还是CH17吗? 在调试环境下,打开通道选择寄存器,可以看到下面结果: . A8 y3 U7 w, L% W3 B ![]() 从上面通道选择寄存器不难看出,除了SQ3外,其它三个配置都是正确的,跟我们预设的通道是一致的。但是,SQ3被错误地配置为CH1了,也就是说上面看到的所谓CH17的转换结果都是来自CH1.难怪不论怎么改变CH17的外部连接时,SQ3选择通道所对应的转换结果没有相应变化,跟CH17的管脚电压也没啥关系。 $ n/ \% _3 I$ R; y& x5 [0 \2 j! s 看到这里有人可能会想,如果我们在前面规划ADC通道时把CH1同时规划进来、硬件上恰好也接地,这时就可能发生误判!这种巧合性的误判,有时可能给我们的调试带来极大隐患而一会半会又找不到原因。当然,具体会发生些什么要因具体应用而定。这里只是简单提醒下,就此打住。 总之,这点在STM32G0 ADC应用中是个很容易出错的地方,将本不该用在完全配置序列模式的通道被错误地强行使用,虽有转换结果,而转换结果却来自别的通道,往往为此觉得问题诡异、不可思议而备受折腾。0 H2 r$ U" W* _9 [& Q+ U" K 5 j3 Q2 F" j* z% a9 c0 n 最后,稍微小结下。对于STM32G0系列的ADC模块来说,其ADC通道在被转换时涉及到转换序列配置问题,这里有两种转换序列配置模式,即不完全配置序列模式和完全配置序列模式。 8 E( d: Z$ C4 }, A 所谓不完全配置序列模式,在进行多个通道AD转换时,转换顺序由各通道自身的硬件序列号和扫描方向决定,其中硬件序列号即CHn在数据手册里已经明确定义,扫描方向通过寄存器配置。整个转换序列可支持的通道数多达18个,没有被排除在外的通道。 + S& \( w9 ]: l# B. [* D) h 而完全配置序列模式呢,在进行多个通道AD转换时,转换顺序由通道选择寄存器中通道选择域SQn[3:0]来决定,即按照SQ1,SQ2.。。。。SQ7,SQ8的顺序,而且SQn[3:0]只能选择CH0到CH14的通道,整个序列最多支持8个通道。显然,CH15~CH18不能使用该模式。" V, {. j ^# A7 U( X' F* {% [9 P; Q 说到这里,或许有人会问,如果只使用1个ADC通道,还有这个转换序列模式的选择问题吗?你把1个通道看成一个特殊的转换序列来理解就知道有没有这个模式选择问题了。 c4 n" y, o6 I 芯片设计人员在此提供了两种转换序列模式,本意旨在让我们能在实际应用中可以根据实际需求灵活选择,然而,往往由于开发人员的惯性思维和无视手册导致在这个地方遇上点麻烦或困惑。在此分享之,祝君好运!+ H$ t4 E& A) Y" T& U 1 t: L* }* |7 l. M, C ' y! f1 P4 {+ Y9 R9 d/ i % y2 S1 a! Q5 Y# W) I/ Q% o |