Behaviour of STM32H743 general purpose timer
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-07-08 8:56 AM
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 ?
Solved! Go to Solution.
- Labels:
-
STM32H7 Series
-
TIM
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-07-08 9:35 AM
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-07-08 9:35 AM
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-07-08 11:02 PM
Thank you. I thought the preload was used only when you write PSC while CEN is 1.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-07-08 11:42 PM
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) ?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-07-09 12:02 AM
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-07-09 3:36 AM
You're right for the HAL
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-07-09 6:56 AM
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.
