cancel
Showing results for 
Search instead for 
Did you mean: 

TIM2 Upcounting Count Restart Issue

jim_jones188
Associate II
Posted on May 02, 2018 at 03:43

The TIM2 timer on an STM32F0 seems to not be resetting to 0 once the counter reaches the ARR value on occasion. I am periodically changing the ARR value, but the values are all in a small range. After a random amount of cycles, the counter will increment beyond that range without triggering an update event, resetting the counter back to 0. I have tried this with and without TIM_CR1_URS set. TIM_CR1_UDIS bit is in the reset state. Anyone else run into this problem?

1 ACCEPTED SOLUTION

Accepted Solutions
Posted on May 03, 2018 at 07:54

Update occurs when CNT matches ARR (i.e. when they equal, CNT == ARR).

If, at a moment,  CNT was below ARR (e.g. CNT = 10, ARR = 15), and at that moment you change ARR to a value below CNT (e.g. CNT = 11, ARR = 5), then the next match occurs only after CNT counts up to its limit, wraps around and reaches 5 again - which, given TIM2 is a 32-bit counter, will seem to be 'forever'.

The solution here is to use the ARR-preload, i.e. to set TIMx_CR1.ARPE. This splits the ARR into two physical registers, one which you access from the processor and other which is used for the comparison; and the newly written value to the former is copied into the latter only at the moment of update, (i.e. it becomes effective one cycle later). There are two diagrams in the timer chapter of RM, illustrating this, search for ' Update event when ARPE=0 (TIMx_ARR not preloaded)' and 'Update event when ARPE=1 (TIMx_ARR preloaded)'

JW

View solution in original post

3 REPLIES 3
jim_jones188
Associate II
Posted on May 03, 2018 at 02:15

To add more information, I am only using Keil with CMSIS, no APIs. My program basically flows like what I have below. The timer generates an update event, assumingly loads the preload values, resets the TIM_CNT value, and calls the ISR for dozens of cycles. Then, randomly, I can see the TIM2 CNT register in the peripheral system viewer increment beyond the input value range that the ARR is set to, and never generates an update event to reset the CNT back to 0.

while(1){

   if(newInput){

      if(5 <= inputValue <= 2500){TIM2->ARR = inputValue;}

}

timer2ISR(void){count++;}

Posted on May 03, 2018 at 07:54

Update occurs when CNT matches ARR (i.e. when they equal, CNT == ARR).

If, at a moment,  CNT was below ARR (e.g. CNT = 10, ARR = 15), and at that moment you change ARR to a value below CNT (e.g. CNT = 11, ARR = 5), then the next match occurs only after CNT counts up to its limit, wraps around and reaches 5 again - which, given TIM2 is a 32-bit counter, will seem to be 'forever'.

The solution here is to use the ARR-preload, i.e. to set TIMx_CR1.ARPE. This splits the ARR into two physical registers, one which you access from the processor and other which is used for the comparison; and the newly written value to the former is copied into the latter only at the moment of update, (i.e. it becomes effective one cycle later). There are two diagrams in the timer chapter of RM, illustrating this, search for ' Update event when ARPE=0 (TIMx_ARR not preloaded)' and 'Update event when ARPE=1 (TIMx_ARR preloaded)'

JW

Posted on May 04, 2018 at 04:24

I did previously have

TIM2->CR1 |= TIM_CR1_ARPE;

, and

I mention the values being preloaded, but there was another error in my code that caused that line to be skipped. I checked the peripheral system viewer in keil to make sure it was being set, after you described the behavior of the registers not being preloaded, and sure enough it was not being set. Thank you for breaking it down for me like that.