有人使用STM32G4系列芯片内部的多个定时器做PWM输出,输出频率一样,占空比也一样,均为50%。
可是,当他中途调整各个定时器以相同的工作参数,即改变ARR的值和CCR值后,会发现TIM2和TIM5两个定时器要比其它定时器延时等待一段长达20s左右的时间后才恢复正常PWM输出,觉得颇为奇怪。
扫描关注一起学嵌入式,一起学习,一起成长
该用户将芯片系统时钟配置成170MHz,并作为各个片内定时器的时钟源,不做分频后作为各个计数器的计数时钟。
起初各个定时器的参数配置如下图左边所示内容,工作起来后,于某时刻将各个定时器的工作参数改成下图右边所示内容。
参数的修改基本在同一时刻完成,可是修改完各定时器的参数后,除了TIM2/TIM5的通道外,其它都能及时地基于新参数产生PWM输出,TIM2/TIM5的输出通道竟然会持续20s左右的低电平后才重新产生基于新参数的PWM输出,怪异得很!
我们这里针对他用到的8个定时器来整理一下。8个定时器中除了TIM2/TIM5是32位定时器外,其它都是16位定时器。时钟源、时基参数、PWM输出配置都一样。
另外,他还强调关闭了各定时器的ARR和CCR的预装功能,就是说针对这两个寄存器即改即生效。
现在看来,感觉问题跟定时器的位宽有关。在STM32G4系列芯片里,TIM3是16位TIMER,TIM2是32位TIMER。
这里不妨就拿它两个作为代表做下测试,模拟该用户的使用场景,看看是否可以重现问题现象。
刚开始,两个定时器使用完全相同的参数配置。【见下图】
我在代码里随机地修改两个定时器以相同的参数,也依然保持跟用户相同数据。
测试发现,很容易遇到修改参数后,TIM2要延时20多秒后才恢复PWM输出的情形。如下图所示:
结合上图示波器输出截图,不难看出,针对TIM2/TIM3修改相同工作参数后,TIM2相对TIM3要延迟一段20多秒的低电平后才恢复PWM输出。见红色长椭圆形所圈出的地方。
其实,如果眼尖细心的人也许发现修改参数后,TIM3也保持了一段低电平时间后才做正常PWM输出,感觉TIM3的PWM输出也并非即该即生效,只是延时相比TIM2短了不少而已。见下图黄色箭头所指位置。
为什么会这样呢?
我们进一步理一下当前定时器的配置情况。现在两个TIMER除了计数器位宽不一样外,其它的具体配置都是完全一样的。
时基参数一样,向上计数模式,PWM1模式,极性选择为高有效。做PWM输出时OC端遵循当CCR大于CNT时输出高,否则输出低电平。
显然,两个定时器输出通道的输出规则也是一样的。
那问题到底出在哪里呢?
有个问题我们可能忽略了,那就是我们修改定时器工作参数【这里就是时基参数和CCR值】的时间点。
假设现有某定时器处于向上计数模式、自动重装值被设定为ARR_1值后开始计数工作,然后在如下图所示某时刻修改ARR值成ARR_2并立即生效。
当计数器计到CNT_x位置时成功修改了ARR的值变为ARR_2,此时计数器继续向上计到ARR2后发生溢出后,重装0开始新的计数循环。
但是,如果新的且生效的ARR值ARR_2比当前计数器值【CNT_x】还小会怎么样呢?即像下面图示的样子:
此时新的ARR值是ARR_2,不再是ARR_1。可此时的计数器的值CNT_x比新的ARR_2还大,计数器又是向上计数模式。
此时计数器如何计数呢?
计数器会依然按照现有计数方向计数:
对于16位宽度的定时器,它会从CNT_x一直计到0xffff时发生溢出,再从0开始计数,计到ARR_2后发生溢出重装,这样周期性地循环计数。
显然,如果定时器还做PWM输出的话,从CNT_x到0xffff这段时间的输出不是正常的,或者说不是预期的。
对于32位宽度的定时器,它会从CNT_x一直计到0xffffffff时才发生溢出,再从0开始计数,计到ARR_2后发生溢出重装,这样周期性地循环计数。
同样,如果定时器还做PWM输出的话,从CNT_x到0xffffffff这段时间的输出也不是正常的,或者说不是预期的。
也就是说,如果针对工作中的定时器中途成功修改ARR,且修改情形符合上面提到的第二种情形时,就会出现一段并不属于用户控制或用户期望的计数段。
自然,这段时间内的PWM输出往往也不是用户预期想要的。这段时间的长短取决于计数器的位宽和计数时钟频率。
这个现象不论16位还是32位TIMER都有可能出现,无非时间长短、现象是否明显罢了。这也解释了前面16位TIMER和32位TIMER在成功修改ARR后都可能出现一段不受控或说非预期的计数时间段。
好,拉回我们前面的模拟测试。在测试中发生TIM2长时间暂停PWM输出后才恢复的情形时,我们可以借助调试工具,发现成功修改ARR值时的CNT值要比新的ARR值【11332】大,见下面代码截图【图中数据是16机制】:
此时,不论TIM2还是TIM3都要继续往上计数到各自计数宽度所对应的默认计数最大值后才基于新的ARR值做循环计数。
在这段继续往上计数的时间段内,因为新的CCR值也已经生效且总是小于CNT的值,结合PWM1模式和高有效的极性选择配置,这段时间自然持续保持低电平输出。
前面也说了,是否会出现一段不受控或说非预期的较长计数段跟我们修改TIMER工作参数的时间点有关系。
当修改工作参数时间点符合前面分析的第一种情形,即新的ARR值大于当前计数器值时,是不会出现那段不受控或说非预期的较长延时的。
比如我在测试代码中,调整修改时间点如下面情形时,就看不到TIM2需要长时间延时后才输出PWM的情况。
从上图中不难看出,成功修改完新的ARR值后,当前计数器的值比新的ARR值小。
这时计数器只需按照原计数方向计到新的ARR值后溢出重装,开始循环计数。
此时也感觉不到PWM输出的明显异常,更看不到长时间无PWM输出的情形。
上面的问题也分析得差不多了,如何避免问题的产生呢?
我们可以开启ARR寄存器的预装功能,这样就可以避免可能出现一段漫长的非预期的计数段。
如果不希望开启ARR寄存器的预装功能,而希望随时修改ARR生效,我们可以在修改定时器的工作参数后,通过手动方式对TIMER进行复位,
即对TIMER事件发生寄存器的UG位置1,这样除了产生定时器更新事件外,计数器会根据计数模式重装新的计数初值,若是向下计数模式,重装ARR后开始向下计数,其它模式则重装0值后开始向上计数。
当然,也可以在修改定时器的工作参数后,直接对CNT赋予0值。
下面代码截图示意随机修改ARR及CCR【此时关闭了二者的预装功能】的情况,每次修改后都让计数器从0开始计数,就完全可以避免可能出现长时间无PWM输出的情况。
上面的分析都是基于计数器采用向上计数模式而言的,如果换了计数模式,有些描述可能需相应做调整,但基本意思是一样的。
好,今天的分享就到这里,下次再聊。诸君好运~!
关注【一起学嵌入式】,回复“加群”进技术交流群。
觉得文章不错,点击“分享”、“赞”、“在看” 呗!