2025-02-17 08:13 PM - edited 2025-02-17 08:14 PM
Hi There,
I have setup TIMER4 on STM32G484 device for overflow event and enabled interrupt for events.
Everything works fine and as expected with correct fire time if I RESET the CNT register in the ISR. However, if I do not, it seems to do some level of free-running.
I only inquire about this, as in all of the STM32 reference manual images, when an overflow event occurs and it's been enabled to detect this, the CNT resets in the peripheral (as long as not single shot mode). So I'm just wanting to confirm that this seems normal and is not a hint that I've misconfigured something. Here are my configuration calls and ISR, I verify the ISR timing on the scope with a GPIO toggling (not shown here).
Register_t rcc_tim4_en = { .address = 0x40021058, .mask = 0x1, .bit_pos = 2 };
Read_Then_Write_Masked(rcc_tim4_en, 0x1);
Register_t tim4_cr_dir = { .address = k_tim4_addr + k_timx_cr1_offset, .mask = 0x1, .bit_pos = 4 };
Read_Then_Write_Masked(tim4_cr_dir, 0); // Up counter
Register_t tim4_smcr_sms = { .address = k_tim4_addr + k_timx_smcr_offset, .mask = 0x7, .bit_pos = 0 };
Read_Then_Write_Masked(tim4_smcr_sms, 0); // Slave mode disabled, use internal clock for timer
Read_Then_Write_Masked(k_tim4_arr, hal::Get_Timer_CLK_Hz() / k_timer_ISR_frequency_Hz); // No prescaler, overflow at this value
// Trigger a software driven event update so new capture parameters are forced through
Register_t tim4_egr_ug = { .address = k_tim4_addr + k_timx_egr_offset, .mask = 0x1, .bit_pos = 0 };
Read_Then_Write_Masked(tim4_egr_ug, 1);
....
Read_Then_Write_Masked(k_tim4_cr1_cen, 1);
Read_Then_Write_Masked(k_tim4_dier_ue, 1);
....
void hal::timers::Factory::run_priority_tasks()
{
// Make sure an overflow event is what got us here
if (! Read_Masked_Shifted(k_tim4_sr_ue))
{
//FIXME error handling? This is kind of mission critical
Abort();
}
Write_Masked(k_tim4_cnt, 0); // Unfortunately the peripheral does not reset this when overflowing
Write_Masked(k_tim4_sr_ue, 0); // Reset it so can check on it again next ISR (this is purely a flag, not the interrupt clearing)
hal::gpio::Factory::get_instance().toggle_debug_led();
}
Solved! Go to Solution.
2025-02-17 08:26 PM
When a timer is in normal upcounting free-run mode, CNT resets to 0 after it reaches ARR. It does not need reset to 0, and in fact is already at 0 when the update event is handled.
2025-02-17 08:26 PM
When a timer is in normal upcounting free-run mode, CNT resets to 0 after it reaches ARR. It does not need reset to 0, and in fact is already at 0 when the update event is handled.
2025-02-17 08:57 PM
Thank you for confirming, any ideas with my configuration above why that is not happening?
2025-02-17 09:05 PM
It probably is happening. The timer is a hardware state machine, if UIF gets set, an update event occurred, and CNT got set back to 0. It may tick a few times before you can handle it, depending on the timer tick speed. Probably you should recheck your assumptions which led you to believe it's not being set. Why do you think it's not happening?
2025-02-17 09:09 PM
NOTE: My bad, it was the lack of resetting the SR that was the issue, not the reset of CNT.
Works fine now like this:
void hal::timers::Factory::run_priority_tasks()
{
// Make sure an overflow event is what got us here
if (! Read_Masked_Shifted(k_tim4_sr_ue))
{
//FIXME error handling? This is kind of mission critical
Abort();
}
//Write_Masked(k_tim4_cnt, 0); // Unfortunately the peripheral does not reset this when overflowing
Write_Masked(k_tim4_sr_ue, 0); // Reset it so can check on it again next ISR (this is purely a flag, not the interrupt clearing)
2025-02-18 06:09 AM - edited 2025-02-18 06:10 AM
Note that UE is not a flag within TIMx->SR, but UIF is. Probably that is what you want.
Using standard CMSIS defines can help avoid typos like this, even if in this case the typo didn't matter.