cancel
Showing results for 
Search instead for 
Did you mean: 

Solution to avoid immediate TIM IRQ in CMSIS.

yabool2001
Associate III

Hi,

I 'm trying to code TIM to count 5s for me using CMSIS. Using the code snippet provided below I got IRQ immediately.

RCC->APBENR2 |= RCC_APBENR2_TIM16EN ; // Enable TIM16 clock
TIM16->PSC = 16000 - 1 ; // 1 ms
TIM16->ARR = 10000 - 1 ; // 10 s = 10000 * 1 ms
TIM16->DIER |= TIM_DIER_UIE ; // Enable interrupt generation
NVIC_SetPriority ( TIM16_IRQn , 0 ) ; // Configure interrupt priority
NVIC_EnableIRQ ( TIM16_IRQn ) ; // Enable interrupt
TIM16->CR1 |= TIM_CR1_CEN ; // Start count TIM16

 I know the solution for HAL to avoid immediate IRQ would be:

 

__HAL_TIM_CLEAR_IT ( &htim16 , TIM_IT_UPDATE ) ;

 

Please help to find relevant solution in CMSIS, because I stucked.

Here is entire code .

V/r

yabool2001

 

1 ACCEPTED SOLUTION

Accepted Solutions

Prescaler is unconditionally preloaded, so the value you write to it does not get applied until the next Update. In other words, during the first timer period timer works with the default PSC=0, which given you are setting it to relatively high value, is observed as "update happens immediately".

One solution is to

  1. write new value to TIMx_PSC
  2. force Update by setting TIMx_EGR.UG
  3. clear Update flag in TIMx_SR

Btw. for clearing flags in TIMx_SR, don't use RMW, write the value directly.

JW

View solution in original post

6 REPLIES 6
Issamos
Lead II

Hello @yabool2001 

I think you should put the bit UIF of the TIMx_SR register to 0 before enabling the TIMER.

Best regards.

II

Prescaler is unconditionally preloaded, so the value you write to it does not get applied until the next Update. In other words, during the first timer period timer works with the default PSC=0, which given you are setting it to relatively high value, is observed as "update happens immediately".

One solution is to

  1. write new value to TIMx_PSC
  2. force Update by setting TIMx_EGR.UG
  3. clear Update flag in TIMx_SR

Btw. for clearing flags in TIMx_SR, don't use RMW, write the value directly.

JW

Outstanding ! Thank you very much for your help. Following solution works:

RCC->APBENR2 |= RCC_APBENR2_TIM16EN ; // Enable TIM16 clock
TIM16->PSC = 16000 - 1 ; // write prescaler 0,001 s. My system clock is 16 000 000 Hz
TIM16->EGR |= TIM_EGR_UG ; //Clear EGR force Update
TIM16->SR &= ~TIM_SR_UIF ; //Clear UIF Flag
TIM16->DIER |= TIM_DIER_UIE ; // Enable interrupt generation
NVIC_SetPriority ( TIM16_IRQn , 0 ) ; // Configure interrupt priority
NVIC_EnableIRQ ( TIM16_IRQn ) ; // Enable interrupt
TIM16->ARR =  5000 - 1 ; // 5 s = 5000 * 0,001s (prescaler value)
TIM16->CR1 |= TIM_CR1_CEN ; // Start counting

 V/r

yabool2001

Hello Issamos,

It's not enough. waclawek.jan recommend 1 more crucial point (Force EGR.UG update):

TIM16->EGR |= TIM_EGR_UG ; // Force EGR.UG update
TIM16->SR &= ~TIM_SR_UIF ; // Clear UIF Flag

 and it works.

V/r

yabool2001

Jan also told you to not use RMW operations!

TIM16->EGR = TIM_EGR_UG;
TIM16->SR = ~TIM_SR_UIF;

And no - it's not just because of efficiency, but because the code with RMW is broken.

I missed it! I backed to Jan's link to g9 "STM32 gotchas" and found what you indicated "Performing RMW (&= or |=) with status registers is incorrect and dangerous".

It's corrected now. Thank you very much for your important remark.

V/r

yabool2001