Skip to main content
LCE
Principal II
July 20, 2026
Solved

STM32G431 TIM2 (32bit) strange behavior

  • July 20, 2026
  • 4 replies
  • 101 views

Heyho,

working on a new project with a STM32G431, for now on a Nucleo-32 board.

I have lots of things running (bare-metal, mostly no HAL), then I needed a timer with a higher resolution than the SysTick (running at 1 ms, looks valid).

The only 32-bit timer is TIM2, so I set it up to simply count up, no interrupts, only with pre-scaler set to get 1 counter period of 10 us at a clock of 96 MHz. 

The code below is changed to a period of 1 ms, for simpler comparison to the 1 ms tick.

Here’s the setup:

/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* TIM2
* 32 bit timer
* init function
* 10 us timer -> NO interrupt
*/
void TimComInit(void)
{
/* peripheral clock enable */
__IO uint32_t u32TmpReg;

RCC->APB1ENR1 |= RCC_APB1ENR1_TIM2EN;
u32TmpReg = ( RCC->APB1ENR1 & RCC_APB1ENR1_TIM2EN );
(void)u32TmpReg;

TIM2->CR1 = 0;
TIM2->CR2 = 0;
TIM2->SMCR = 0;
TIM2->CCER = 0;
TIM2->CCMR1 = 0;
TIM2->CCMR2 = 0;
TIM2->CCMR3 = 0;
TIM2->DIER = 0;
TIM2->SR = 0;
TIM2->EGR = 0;
TIM2->OR = 0;

TIM2->PSC = (uint32_t)((float)u32CpuClock / 2E3f) - 1UL;
TIM2->ARR = 0xFFFFFFFF;

/* timer enable */
TIM2->CNT = 0;
TIM2->CR1 |= TIM_CR1_CEN;
}

 

Here’s the strange behavior (which was the same when set up for 10 us):

  • after init, the timer runs with full clock speed, ignoring the pre-scaler
  • after the first overflow, the pre-scaler is used

Here’s the UART output (which I confirmed with some timer controlled GPIO, where I actually found this problem, because the TIM2 controlled pulses where super-short after start-up, then okay):

directly after start:

T2 276587682 <- TIM2->CNT
TimMs 5762 <- TIM7 also set to 1 ms
Tick 5762

...

T2 476524324
TimMs 9927
Tick 9927

later, after 1st overflow, now OK: difference between T2 and Tick readings is about the same

T2 289650
TimMs 379129
Tick 379129

T2 294491
TimMs 383969
Tick 383969

 

What am I doing wrong?

As you can see, this set up code is so simple, only PSC set, then enable. Must something really stooopid…

 

Thanks in advance! 

 

Best answer by waclawek.jan

TIMx_PSC is unconditionally preloaded. This behaviour is documented.

JW

4 replies

LCE
LCEAuthor
Principal II
July 20, 2026

When I set CNT = 0xFFFFFFFE before setting the enable bit, then the timer works fine.

Played around with it by setting CNT to various values and comparing with the SysTick, it’s definitely taking PSC into account only after the first overrun.

waclawek.jan
waclawek.janBest answer
Super User
July 20, 2026

TIMx_PSC is unconditionally preloaded. This behaviour is documented.

JW

LCE
LCEAuthor
Principal II
July 20, 2026

Thanks ​@waclawek.jan !

Just found the same by setting it up via CubeMx, and there I found the line:

TIM2->EGR     = TIM_EGR_UG;

Then I checked the RM again.

 

I never came across this before, is this a feature for “advanced” timers only?

 

And interesting that this is required even before the timer was ever enabled.

waclawek.jan
Super User
July 20, 2026

> is this a feature for “advanced” timers only?

No, this is the same in all timers.

In 16-bit timers many users simply don’t notice that the first period was shorter. Also, “library” (SPL/Cube/LL/HAL) users won’t notice as the “libraries” tend to add setting TIMx_EGR.UG to timer initialization code.

JW