2016-08-09 07:53 PM
I am using Timer6 on STM32L051 as a base 2 S timer with overflow interrupt.
By some reason on a first run interrupt fires immediately, and I can't figure out the reason for this behavior. Here are my initialization and timer start functions. Initialization:/**************************************************************** Timer6_init **
** Name : Timer6_init()
** Returns : none
** Args : none
** Description : configure timer6 as a base timer
** Notes : auto-reload register is loaded with amount for 2S
** Timer6 is fed by 16 MHz clock
** timer is used as upcounter (DIR=0).
** Only overflow generates an update event (URS=1),
** update event generates interrupt
*******************************************************************************/
void Timer6_init(void)
{
/* enable TIM6 clock */
RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; /* init timer 6 */
/* time base:
TIM6_Prescaler = 15999 (count frequency is 1 KHz)
TIM_ClockDivision = 0
TIM_CounterMode = 0 (up counter */
/* update on overflow only */
/* time base is 1mS - 1 KHz */
TIM6->PSC = 15999;
TIM6->ARR = 2000; // in mS
TIM6->SR &= ~0x0001;
TIM6->CR1 |= 0x0004; // update source regular
/* enable overflow interrupt */
TIM6->DIER |= 0x0001;
} /* end Timer6_init() */
Timer start:
/***************************************************************** Start_tim6 **
** Name : Start_tim6
** Returns : none
** Args : none
** Description : timer 6 - base milliseconds timer
** Notes :
*******************************************************************************/
void Start_tim6(void)
{
TIM6->CNT = 0;
TIM6->ARR = 2000; // in mS - not needed, just in case
TIM6->SR &= ~0x0001; /* clear update flag */
/* start timer */
TIM6->CR1 |= 0x0001;
if (first_run != 0)
{
TIM6->SR &= ~0x0001;
first_run = 0;
}
__NOP();
} /* end Start_tim6() */
When timer runs for the first time, interrupt is fired immediately.
I tried to set breakpoints in a timer start routine to see when the overflow flag is set.
In the above Start_tim6 snippet it worked as follows:
- Breakpoint at line 14 - SR is 0,
- Breakpoint at line15 (after timer start) - SR is 1.
I tried to clear flag on first run (lines 15-19). Flag is not cleared, it stays set. And, of coarse, interrupt is fired.
This happens only on a first run. Every time after that interrupt occurs after 2 S.
I wonder what could I overlook.
Please help me to figure it out.
Thank you,
Gennady
2016-08-09 08:08 PM
Yes, the Update event is zero, so it will fire
Don't use the RMW form to clear, just write the mask, the TIM is designed to do it this way and avoid the race hazardTIM6->SR = ~0x0001; // Just write to clear
2016-08-10 09:05 AM
I've tried using direct write (used TIM6->SR = 0 before also), and it doesn't help.
And I don't understand few things:- why is UIF set on a timer start (setting CR1.0), though update request is set to 'overflow/underflow only' (URS is set)?- why I can't clear UIF after that, either by RMW or direct write?- why does it happen on a first timer run only?2016-08-10 10:35 AM
The RMW is not atomic, the timer can go through multiple cycles, and bits can set in SR between the read and the write. Remember if you AND any bit with zero you get zero.
2016-08-10 11:05 AM
I understand that. And I replaced RMW by a direct write for a flag clearing. Didn't work.
And it still doesn't answer questions in my last post above.2016-08-11 10:09 AM
What might confuse you is that TIMx_PSC is not the prescaler reload register, rather it's its shadow, which is loaded into the prescaler reload register and into the prescaler register upon the subsequent update. Ergo, the first update happens 2000 CK_INT cycles after the timer is enabler, rather than 2000x16000 you expect.
Also note, that unless you have set the respective bit in some of the DBGMCU ''freeze'' registers, the timer is running while the program is stopped by debugger. For the debugger, it takes time to read out the registers, so you don't see a consistent ''snapshot'' of the registers. JW2016-08-19 09:41 AM
Yes, it was my fault.
By some reason I assumed that since ARR is not buffered (ARPE is cleared in TIM6->CR1), PSC is also not buffered. Wrong :(So all I needed is to configure TIM6->CR1 for an update from UG, set UG and clear an update flag.Now PSC is loaded, I can enable overflow interrupt and start a timer.Works fine.Thanks a lot for pointing me in a right direction,Gennady