cancel
Showing results for 
Search instead for 
Did you mean: 

Premature TIM2 interrupt happening immediately on timer start

Todd Phelps
Associate II
Posted on January 15, 2018 at 19:53

Hi folks,

I'm having an issue with the TIM2 interrupt firing as soon as I start the timer rather than when the timer overflows -- was hoping someone could help me. I've set up TIM2 to interrupt once every 860 milliseconds or so, but am finding that the timer immediately interrupts about 75 microseconds after I activate it. I'm using the ST peripheral driver library for the STM8S on the STM8s Value Line Discovery board with IAR as the compiler.

Initialization code (slightly modified for clarity):

Note, timer_period = 836

void timebase_init(uint16_t timer_period)

{

/* Set the step time

TIM2 Clock = 16 Mhz

TIM2 Prescaler = 16384

TIM2 Counter Clock = 16 MHz / 16384 = 967 Hz

TIM2 Period range = 0.001 sec - 1 sec

*/

GPIO_WriteLow(GPIOD, GPIO_PIN_2); // For testing with logic analyzer

TIM2_DeInit();

TIM2_TimeBaseInit( TIM2_PRESCALER_16384, timer_period);

TIM2_ITConfig( TIM2_IT_UPDATE, ENABLE );

TIM2_Cmd( ENABLE );

}

Interrupt handler from stm8s_it.c:

INTERRUPT_HANDLER(TIM2_UPD_OVF_BRK_IRQHandler, 13)

{

GPIO_WriteHigh(GPIOD, GPIO_PIN_2);

time_event(); // User app function - change displayed value

GPIO_WriteLow(GPIOD, GPIO_PIN_2);

}

/* Clear Interrupt Pending bit */

TIM2_ClearITPendingBit(TIM2_IT_UPDATE);

}

I've set up the interrupt handler to toggle a debug pin when it runs. The timer period is set up for approx. 0.86 seconds, however the interrupt happens 75 microseconds after I enter the function that sets up the timer:

After this, it happens every 0.86 seconds as expected (can't see the above pulse in the following image, which is zoomed out a lot):

If I put a breakpoint on the entry to the interrupt handler, the first time it hits (the undesired interrupt), IAR reports the TIM2 registers as this:

I've seen a couple references saying the timer update will cause an interrupt when you change some of the timer's registers, but it seem silly to me that if you set a timer it goes off as soon as you press start rather than at the time you've set the timer for.

Thanks for any help or insight!

6 REPLIES 6
raimond
Associate III
Posted on January 16, 2018 at 07:08

The ST timers 'update events' include overflow, but can be other things too (timer register initialization for example, when you 'update' the ARR as an example).

That's the way it is about st timers.

Regarding your code, what is the ARR (auto reload register)? Seems that you use the default, 0x0000, and in that case the timer will start with an update (Remember that the timers are auto-reload on overflow, the overflow 'update' event is when the timer roll-over to zero from ARR. The timer counts as that: 0,1,2,3,4,5,6,0,1,2,... (ARR=6). Overflow update event is at 0).

I must say here that I'm not using the ST hal library (or whatever it's name is). Why you don't work with registers directly? It's such a simple chip... The hal library is just hiding the information from you. In the end you may be forced to read the manual/datasheets anyway, and you will have a hard time mapping the hal library to the manual. Think of that: why in the manual all the stories are with registers and NOT the hal library functions? I have a rule of thumb: I will use a chip vendor hal library when the manual/datasheet will include clear use of it along with the hardware register normal documentation....

Sam Zeng1
Associate II
Posted on January 16, 2018 at 20:40

I  encountered the same problem with Timer2 interrupt. So I ignore the first interrupt in my application and clear the TIM2_SR1 for the next interrupt.

Posted on January 17, 2018 at 00:47

Hi dragomir.raimond, and thanks for the reply. The value of ARR set by to 0xFFFF by TIM2_Deinit(); it is then changed to (a value of approximately)  0x0344 by

TIM2_TimeBaseInit() before the timer it started:

void TIM2_DeInit(void)

{

  TIM2->CR1 = (uint8_t)TIM2_CR1_RESET_VALUE;

  TIM2->IER = (uint8_t)TIM2_IER_RESET_VALUE;

...

  TIM2->ARRH  = (uint8_t)TIM2_ARRH_RESET_VALUE;

  TIM2->ARRL  = (uint8_t)TIM2_ARRL_RESET_VALUE;

...

}

 

void TIM2_TimeBaseInit( TIM2_Prescaler_TypeDef TIM2_Prescaler,

                        uint16_t TIM2_Period)

{

  /* Set the Prescaler value */

  TIM2->PSCR = (uint8_t)(TIM2_Prescaler);

  /* Set the Autoreload value */

  TIM2->ARRH = (uint8_t)(TIM2_Period >> 8);

  TIM2->ARRL = (uint8_t)(TIM2_Period);

}

I have tried clearing the TIM2->SR1 update bit (0x01) immediately before TIM2_Cmd() activates the timer by setting TIM2->CR1's CEN bit as I figured that should block any interrupts due to the preceding setup. It doesn't help though -- I still get that immediate interrupt.

> Why you don't work with registers directly? 

This is a one-off project for an external customer and may be the only time I use an STM8; I was using ST's HAL library to expedite the development as I don't have any other STM8-based projects coming up and didn't want to spend too much time poring over register definitions as the whole software development time was only around a week. 

At the moment I've just used a static bool in the interrupt handler to ignore the first time it runs, but I wanted a better way.

Thanks again,

Todd

Posted on January 17, 2018 at 00:48

That's what I'm doing at the moment, but I'm tying up RAM with a static bool in the ISR that I have to check each time it runs... it's fine, I suppose, but I was hoping to get away from that. 

Thanks!

Todd

Posted on January 17, 2018 at 07:11

That's always an unfortunate situation, and it's hard to say what is better to do

Anyway, probably you are in this situation: The first ARR counts are on the default prescaler which is just /1

That will be quite close to your measurement (836 counts * 0.0625ns = 52us). The prescaler will get your desired value (16384) at the 'next' update event, in your case just the first one.

Quote from the user manual:

'The prescaler value is loaded through a preload register. The shadow register, which

contains the current value to be used is loaded as soon as the LS Byte has been written.

The new prescaler value is taken into account in the following period (after the next counter

update event).'
Posted on January 17, 2018 at 19:08

You're right, that is the problem -- thank you @dragomir.raimond! I looked at the manual to see what I might do about it and the prescaler register description had this in section 8.6.15, reiterating what you'd said but also mentioning the UG bit:

PSCR contains the value which is loaded in the active prescaler register at each update event

(including when the counter is cleared through the UG bit of the TIMx_EGR register).

This means that a UEV must be generated so that a new prescaler value can be taken into account.

The STM's HAL library has a PrescalerConfig function that (unlike TimeBaseInit()) will set the TIM2->EGR's UG bit in order to immediately load the new prescaler value. So, if using the HAL library the key is to call TIMx_PrescalerConfig() and then clear the pending interrupt bit prior to enabling the timer. The following works for me, the first interrupt now happens at the 860 msec instead of 50-ish microseconds:

TIM2_DeInit();

TIM2_TimeBaseInit( TIM2_PRESCALER_16384,timer_period ); 

TIM2_ITConfig( TIM2_IT_UPDATE, ENABLE );

TIM2_PrescalerConfig( TIM2_PRESCALER_16384, TIM2_PSCRELOADMODE_IMMEDIATE );

TIM2_ClearITPendingBit(TIM2_IT_UPDATE);

TIM2_Cmd( ENABLE );

Thanks again!