1. 问题提出
客户使用 STM32G474 的高精度定时器,基于 CubeMX 进行外设配置与代码生成,将某个子定时器的计数方式设置为 retriggerable single shot 方式,发现该子定时器无 PWM 输出,在调试模式下发现该子定时器的计数器一直为 0,即计数器一直没有启动,但如果将计数方式修改为continuous 模式,其他保持不变,定时器工作正常。
2. 问题分析
检查客户提供的 CubeMx 配置文件,客户使能了 Master Timer 与 Timer B,Master Timer 的比较器事件 2 触发 Timer B 复位与运行,并配置了 Timer B 的 PWM 输出,使用该工程文件直接生成代码,并添加高精度定时器计数使能与输出使能函数,如下:
进入调试模式观察,发现 Master Timer 正常计数,但是 Timer B 的计数器一直保持 0,按照客户的描述,将 Timer B 的计数方式修改为“continous”后,Timer B 恢复正常计数。对比 TimerB 在“retriggerable single shot”与“continous”两种工作模式下的相关寄存器的值进行对比,发现除了计数模式不同之外,其他所有的状态都相同。
莫非真是“retriggerable single shot”存在问题?这明显不可能,此前多次使用过该模式并没有发现问题,于是将以前设计的能成功工作的例程拿来与该“问题”工程进行对比。经过比对分析发现,工程配置中使用的寄存器更新方式存在不同,如下图所示:
图1.正常工作工程中的寄存器更新配置
图2.“问题”工作工程中的寄存器更新配置
“问题”工程配置中使用 Master timer 的更新事件作为触发寄存器更新触发源,并且更新要等到本定时器的下一次的 Reset/Roll-over 事件出现时才生效。通过将“Update taken into accounton the following Reset/Roll-over event”修改为“Update taken into account immediately”,定时器也可以正常运行了,问题的原因就是由于该配置引起的。
查看该配置对应的寄存器说明:
当配置“Update taken into account on the following Reset/Roll-over event”对应于该位置“1”,即更新事件,无论是来自相邻定时器的还是软件产生的,都需要等到下一个 Reset/Rollover event 才生效。
在直接使用 CubeMx 产生的 HAL 底层配置代码且配置中使能了预加载的情况下,该寄存器更新配置方式会导致 Timer B 的初始化配置无法生效。
如图 3/4/5 所显示的,因为在 CubeMx 直接生成的代码中,Timer B 参数的配置通过调用函数HAL_HRTIM_WaveformTimerConfig()写入寄存器,然后在该函数中调用软件更新函数HRTIM_ForceRegistersUpdate()的方式让配置生效,那么在目前的配置下,软件触发更新也必须等待 Reset/Roll-over event 的出现。而在 retriggerable single shot 计数模式下,定时器不能自动启动计数,必须等待来自 Master Timer 的 Reset 事件(即前文提到的比较器事件 2)。
图3.“问题”工程中的寄存器更新与定时器 Reset 配置
图4.“问题”工程产生的 Timer B 初始化代码
图5.Timer B 初始化代码中调用软件触发更新
综上,虽然正确的配置了 Reset 事件,Master Timer 也正常计数且产生了比较事件 2,但问题在于在运行了初始化代码后,该配置仅仅是写到了 preload 寄存器中,而没有写入 active 寄存器中,即 Timer B 的复位源没有生效,带来的后果就是 Timer B 的计数器不运行,一直保持 0,且所有带有预加载特性的寄存器的值也没有生效。
作为对比,当配置为“Update taken into account immediately”时,调用软件触发更新函数HRTIM_ForceRegistersUpdate()函数,将使所有配置立即生效,定时器可正常工作。
3. 解决方法
基于以上分析,造成该问题的主要原因是 CubeMx 基于 HAL 库自动生成的初始化代码中没有考虑不同的寄存器更新配置方式,只是单一的采用软件更新的方式来触发寄存器更新。要解决以上问题,需要修改代码中的定时器初始化的时序,在配置寄存器更新方式为“Update taken intoaccount on the following Reset/Roll-over event”前,让其他的配置先生效,基本逻辑如下,逻辑在客户自己编写初始化代码时也需要遵循。
4. 小结
解决客户提出的高精度定时器中的子定时器在 retriggerable single shot 计数模式下无法工作的问,原因在于该计数模式下,当更新配置方式为“ Update taken into account on the following eset/Roll-over event ”时,使用 CubeMx 生成的原始初始化代码出现了定时器配置无法生效,从导致问题的出现。通过对初始化代码的逻辑进行简单修改,问题得以解决。当然,TM32CubeMx 的未来版本应会就这个地方做针对性地完善。
本文档参考ST官方的《【应用笔记】LAT1187+在Keil中使用STM32CubeProgrammer》文档。
参考下载地址:https://download.csdn.net/download/u014319604/88971341