简体   繁体   中英

STM32L0 Timer TIM22 cause interrupt in unpredictive way?

Every time I enable the timer it instantly activates the Interrupt. No matter how I try to prescale it. only ARR seems to work but 16 bit with 0,5MHz clock gives me ~160ms maneuver.

#define SYSCLK_FREQ 524288

void timer_init(uint16_t detonation_delay_ms);

int main(void){
RCC->APB2ENR = RCC_APB2ENR_TIM22EN;
TIM22->PSC = (SYSCLK_FREQ/1000)-1;
NVIC_EnableIRQ(TIM22_IRQn); 
NVIC_SetPriority(TIM22_IRQn,4);
}

/* calling function */
timer_init(65535);
/* calling function */

void timer_init(uint16_t detonation_delay_ms){
TIM22->CR1 &= ~TIM_CR1_CEN;
TIM22->SR=0;                                
TIM22->ARR = detonation_delay_ms;                   
TIM22->CR1 |= TIM_CR1_CEN;
TIM22->SR = 0;
}

void TIM22_IRQHandler(void){
    TIM22->CR1 &= ~TIM_CR1_CEN;
    TIM22->SR=0; 

        GPIOB->BSRR = GPIO_BSRR_BS_7;
}

I wish that calling function makes the timer tick till the called value in milisec. But no matter how I set it up it ends up with no scaled timer and instant interrupt after calling it.

Correct way to do it?

    TIM22->DIER = TIM_DIER_UIE;
    TIM22->ARR = 65535-detonation_delay_ms;
    TIM22->EGR = TIM_EGR_UG;
    TIM22->CR1 |= TIM_CR1_OPM | TIM_CR1_CEN;
    TIM22->SR=0;
  1. Do not delay in interrupts

  2. you enable the timer then set the ARR which is wrong - first set ARR and prescaller, then generate the UG event using the EGR register, then enable the timer.

Works like a charm. Just because I got help here will describe for future interested people.

The way to get the interrupt working for the timers is to generate interrupt 'by hand' once. It's okay to do it because you can control what's happening during the interrupt by a single 'if'.

    /* TIMER Enable */
    RCC->APB2ENR = RCC_APB2ENR_TIM22EN;

I had a problem with the above declaration, dunno why but it wasn't working after declaring some more modules before it. Had to put it on higher on the list. Manual does not say why it happened.

    /* Configure TIM22 interrupt */ 
    TIM22->PSC = (SYSCLK_FREQ/1000)-1;      /* Prescaler TIMERA 22 */
    TIM22->DIER = TIM_DIER_UIE;
    TIM22->CNT = 0;
    TIM22->EGR = TIM_EGR_UG;

    NVIC_EnableIRQ(TIM22_IRQn);             /* Zalaczenie przerwania od TIMER'a */
    NVIC_SetPriority(TIM22_IRQn,4);     /* Ustawienie priorytetu przerwania od TIMER'a */

The prescaler meant to be 1ms so I divided 524288 of my core speed. Then enabling the interrupt, resetting the counter to make sure it starts from 0 and then manually generating the interrupt. And it does the interrupt 'loop' once but with a single 'if' and variable, I can control what it does.

So what I do, I am calling a function that set the clock and enables the count inside another function enable = 1; timer_init(ms);

Then comes the function call

void timer_init(uint16_t ms)
{
    TIM22->CNT = 65535-ms;
    TIM22->CR1 |= TIM_CR1_CEN;                          
}

void TIM22_IRQHandler(void)
/* Up-Counter milisec */
{
    if(TIM22->CR1 & TIM_CR1_CEN) {TIM22->CR1 &= ~TIM_CR1_CEN;}
    if(TIM22->SR & TIM_SR_UIF) {
        if(enable == 1){
            GPIOB->BSRR = GPIO_BSRR_BS_7;
        }
    }       
    TIM22->SR=0;
}

And the interrupt. Thanks a lot!Have fun with registers!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM