Electronic – Inaccurate timer interrupt STM32

embeddedinterruptsstm32timer

I wrote a simple program to toggle an LED on and off using the TIM1 interrupt on an STM32F0 discovery board.

CLK Freq = 48MHz
Prescalar = 48000
Auto Reload Register = 1000

Using the following formula to calculate the timer frequency:

Timer frequency = (CLK FREQ/ (Prescalar -1) * ARR)

In my case it is equal to 1 second. If I run this code without an interrupt, it toggles the LED on and off at 1-second intervals, which is what I want.

As soon as I use the ISR, my LED TOGGLE is really fast (approximately 500ms), if I make my Timer_Value = 60000

void TIM1_BRK_UP_TRG_COM_IRQHandler(void)
{
    Timer_Value++;

if(Timer_Value == 60000)
{
if(Timer_Change_Status == Timer_Deactive)
{
    SendBitToPortAndPin(LEDIND_Port, LEDIND_Pin,1);
    Timer_Change_Status = Timer_Active;
}
else {
    SendBitToPortAndPin(LEDIND_Port, LEDIND_Pin,0);
    Timer_Change_Status = Timer_Deactive;
}
Timer_Value = 0;
}
  // reload counter
TIM1->EGR |= 0x01;
}

In my main loop, I call the following function

void COnfig_Start_Timer(void)
    {   
    RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;

    TIM1->PSC = 48000;                          ///Load Prescalar
    TIM1->ARR = 1000;                           ///Load Auto Reload value


    NVIC_EnableIRQ(TIM1_BRK_UP_TRG_COM_IRQn);   ///Enable interrupt
    NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn,1);///Set interrupt priority
    TIM1->DIER |= TIM_DIER_UIE;                 ///Activate Timer Interrupt
    TIM1->CR1 |= TIM_CR1_CEN;                   ///start Timer


    while(1)
    {

    }
    }

I would like to know what is causing my ISR to fire so frequently, when it should only fire once every second. I have referred to my reference manual with no luck.

Best Answer

There are two things wrong with your code:

1) you attempt to reset and restart the counter in the interrupt handler with "TIM1->EGR |= 0x01;" . But you're using the automatic reload mode of the counter so you shouldn't do that.

2) You never clear the interrupt from the timer. The timer sets the interrupt, but you're responsible for clearing it once you've handled it. Since you don't do that, when your IRQ handler returns, the cpu immediately dispatches the same interrupt and calls it again. To clear the interrupt you need to clear bit 0 of TIM1_SR with something like

TIM1->SR &= ~0x1;

(or perhaps TIM1->SR &= ~TIM_SR_UIF; if you have that defined)