Electrical – timer interrupt on STM32F303

interruptsstm32timer

I'm kind of a newbie so excuse me if this is a beginner's question. tried to find an answer but couldn't find one.

I'm working on STM32f3Discovery eval board, with the stm32f303vc on it.
The code uses TIM6 overflow interrupt to generate LEDs lighting on shifting fashion, using shift register (the LEDs connected to PORTE pins).
This is the code :

     #include "stm32f30x.h"
    #include "system_stm32f30x.h"

    void TIM6_DAC_IRQHandler(void);   
    void setTIM6(void);

volatile uint32_t _regValue = 1<<15;


    int main(void) {


    volatile int _timer = 1000000;

    RCC -> AHBENR |= (uint32_t) 1 <<21;
    GPIOE -> MODER |= 0x55550000; //ports 8-15 output
    setTIM6();
    TIM6 -> CR1 |=0x1; //timer enable

    while(1)
    {
    }
    } //end of main

    void setTIM6(void) {

    NVIC ->ISER[1] |= (uint32_t) 1<<22; //TIM6 int. enable
    RCC -> APB1ENR |= (uint32_t) 1<<4; //clock enable
    RCC -> CFGR |= 0x00000700; //APB1 prescaler -> clock=(8MHz/16)*2 = 1MHz
    TIM6->CR1 |= 0; 
    TIM6->DIER |=1; //int. enable
    TIM6->PSC = 0xFFFF; //prescaler for TIM6. -> clk = 1Mz/2^16 = 2^4 =16Hz
    TIM6->ARR = 240; // int. flag every couple of secs.   

      DBGMCU->APB1FZ |= 1<<4; //for debug - TIM6 counter freeze during breakpoint   
}

void TIM6_DAC_IRQHandler(void)
{   
    _regValue = _regValue >> 1;
    GPIOE -> ODR = _regValue; //writing value to PORTE output

    if (_regValue == 1<<9){
        _regValue = 1<<15;
    } //this is for rotational loop of LEDs  

    TIM6->SR &= ~0x1; //UIF (Interrupt flag) disabled
}

OK, so the problem is what I get in the board is a blink in LED(x) (first LED I intended to), then (after a timer's pause) blink in LED(x+2),
meaning LED(x+1) was "skipped"! this goes on: Led(x+3) on, then LED(x+5) and so on.
But when I enter debug mode (step-by-step), I see that this LED (x+1) is truly blinking, apparently it's just a matter of speed so the next interrupt overrides it before the eye notices. Any ideas what is the reason for this?
When I debug this I see that on the second time it enters the IRQ, the SR is NOT active. on the third it is, the fourth time not, and so on.

SO, I've got this weird assumption that the last line of IRQ is toggling SR to LOW, but the transition time is low
so the when the NVIC returns to main it sees that the UIF is still HIGH, so it jumps again to IRQ and do the LED shift rotation
and output it, but because the counter has already started ticking earlier it finishes too quickly and overrides the last blinking so we can't see it. but I don't know if it's reasonable in terms of the architecture of the Core. Although, still doesn't

Anyway, what solved this was to include the SR checking in the beginning of the IRQ, i.e :
if (TIM6->SR &= ~0x1)
{

}

Moreover , if I put the "TIM6->SR &= ~0x1;" line in the beginning of the IRQ, it also works well! and that's also indicates the reason
I've pointed to! (it gives the transition more time before returning to main).
So.. is it really that? it looks to fit, but still sounds strange: shouldn't the transition be quick enough, definitely quicker than the return to main?… (with POP stack etc.)

thanks.

Best Answer

According to this: http://www.keil.com/support/docs/3928.htm
there's actually an issue with Cortex-M3/M4 devices as

Cortex-M3 and Cortex-M4 interrupts appear to be triggering twice.

caused by

The ISR code exits immediately after a write to clear the interrupt.

which seems to be what you're experiencing and also goes along with your assumption.

The final resolution suggested is

(...) just perform another memory write before exiting the ISR.

which the article's example does by reordering the ISR instructions, leaving one memory write operation by the end. Or adding a dummy write.


As a personal note, if I were you I'd go for the safest approach: check the flag on entry and perform a dummy write on exit (GPIOE->ODR = GPIOE->ODR; maybe). And even though you seem to be just experimenting on the platform, that kind of solution deserves a comment on code.