cancel
Showing results for 
Search instead for 
Did you mean: 

Behaviour of STM32H743 general purpose timer

Gpeti
Senior II

Hello,

I'm using TIM2 on STM32H743 (Nucleo, rev Y, Keil 5.31).

Just before setting the bit TIM_CR1_EN the setting of the timer is the following:

  • DIER : bit UIE set
  • PSC: expected value (0x4E1F)
  • ARR expected value (0x4E20). it is almost the same as PSC but normal
  • all other registers are 0, including CNT

TIM2 interrupt is enabled. No pending interrupt at this time.

As you can see it is a pretty simple setup.

When I set the bit CEN , I get the first TIM2 interrupt way too quickly (the timer is supposed to trig an update event every 2s).

At this first interrupt the status register is 0x0000001F (bit UIF set + bits CCxIF).

The next interrupts are happening at the correct frequency, around 2s.

I've checked the timer duration using CYCCNT register (and after having set the timer freeze functionality during break). Except for the first interrupt, I indeed measure 800M cycles with CYCCNT (cpu @ 400MHz).

But the first interrupt happens around 40 k cycles after the set of CEN bit.

Any idea ?

1 ACCEPTED SOLUTION

Accepted Solutions
berendi
Principal

PSC is preloaded, so setting it takes effect at the next update event. The first cycle runs effectively with PSC=0, i.e. exactly 0x4e1f+1=20000 times faster as you expect. You can force an update before starting the timer by writing the EGR register, but keep in mind that it causes an update event right then, which you might want to clear before enabling the interrupt, or there is some bit in CR1 that prevents triggering an update interrupt on setting TIM_EGR_UG.

View solution in original post

6 REPLIES 6
berendi
Principal

PSC is preloaded, so setting it takes effect at the next update event. The first cycle runs effectively with PSC=0, i.e. exactly 0x4e1f+1=20000 times faster as you expect. You can force an update before starting the timer by writing the EGR register, but keep in mind that it causes an update event right then, which you might want to clear before enabling the interrupt, or there is some bit in CR1 that prevents triggering an update interrupt on setting TIM_EGR_UG.

Thank you. I thought the preload was used only when you write PSC while CEN is 1.

It's indeed working fine now (set UG, wait for UIF, clear UIF, enable interrupt).

However i'm still confused by how the HAL is managing this point (I'm not using the HAL in my code but I use it as a "helper" to understand some peripheral behaviors so I want to understand what it does). I had seen that the HAL timer init was writing the bit UG in EGR (although I hadn't understand the reason before). But I don't see where it clears the bit UIF before enabling the interrupt ? I'm probably missing something but doesn't the HAL have the same issue than I had in my code (wrong duration for first timer interrupt) ?

berendi
Principal

If it sets TIM_EGR_UG but does not clear UIF then it would trigger an interrupt immediately, so the duration between starting the timer and getting the first interrupt would be 0.

It does not matter in the most common use cases, as timer periods would have the same length and interrupts would occur in regular intervals. So it is good enough for HAL.

You're right for the HAL

berendi
Principal

The root cause of the weirdness is that PSC is always preloaded. It was a design decision 15+ years ago, and never changed for compatibility reasons. Note that general timer functions are register level compatible across the whole STM32 portfolio and even some 8 bit MCUs.

So we have to live with the fact that setting PSC a multiple step process. Either this (what you actually did)

TIM->PSC = x;
TIM->EGR = TIM_EGR_UG;
while((TIM->SR & TIM_SR_UIF) == 0)
  ;
TIM->SR = ~TIM_SR_UIF;

or

TIM->CR1 |= TIM_CR1_URS;
TIM->PSC = x;
TIM->EGR = TIM_EGR_UG;

would get it done. The first one works only when the update interrupt is not yet enabled, the second one has other side effects, see the description of TIM_CR1_URS in the reference manual.

Setting ARR=0 stops the timer, ARR=1 would generate an update event one cycle later than setting EGR.