timer interrupt on STM32F303

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.

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.

• Yes! exactly what I was looking for. thanks! – Elad May 23 at 9:02
• "that kind of solution deserves a comment on code" - didn't understand this last note. – Elad May 23 at 20:30
• @Elad I meant that whenever the purpose of the code isn't obvious (as in this workaround), you should add a brief comment explaining why that code is there. – RaphaelP May 24 at 13:15