cancel
Showing results for 
Search instead for 
Did you mean: 

Avoiding spurious interrupt

dismirlian2
Associate II
Posted on October 12, 2016 at 17:28

Hello all,

I'm trying to measure the frequency of a signal using the input capture. I'm using the STM32F030's timer 3, which is a 16 bit timer. I want to extend the resolution to 32 bits, using the Capture interrupt and the Overflow interrupt.

The frequency measurement works OK, but I'm having a problem with spurious interrupts. Please look at the code below. The only interrupts I have activated are UIE and CC1IE. In the ISR, I check both bits, and take appropriate actions. However, sometimes,the code marked ''THIS PATH IS EXECUTED'' is run, which means that the relevant status flags (UIF and CC1IF) are 0.

I know that there can be a race condition involving the pipeline and/or the APB->AHB bridge/write buffer which may be causing the processor to tail-chain the interrupts. But I'd like to avoid these spurious interrupts, because they unnecessarily overload the processor.

Any ideas or explanations?

Note: I can't use linked timers to extend the resolution, because I'm already using other resources.

Thank you very much,

Diego.

Here is the code for the initialization (TOP is defined as 65536):

TIM3->SR = 0;

TIM3->DIER = 0;

TIM3->PSC = 47;

TIM3->ARR = TOP - 1;

TIM3->CCMR1 = STM32_TIM_CCMR1_CC1S(1) | STM32_TIM_CCMR1_IC1F(3);

TIM3->CCER = TIM_CCER_CC1E;

TIM3->DIER = TIM_DIER_CC1IE | TIM_DIER_UIE;

TIM3->CR1 = TIM_CR1_CEN;

Here is the ISR code:

#define TOP 65536

void

isr(TIM_TypeDef *TIMx) {

static

bool

enabled;

static

uint16_t last_capture;

static

uint32_t overflow;

int

current_capture;

uint16_t sr = TIMx->SR;

if

(sr & TIM_SR_CC1IF) {

current_capture = TIMx->CCR1;

if

(sr & TIM_SR_CC1OF) {

TIMx->SR = ~TIM_SR_CC1OF;

enabled = FALSE;

return

;

}

if

(sr & TIM_SR_UIF) {

TIMx->SR = ~TIM_SR_UIF;

if

(current_capture < TOP / 2) {

overflow += TOP;

}

}

if

(enabled) {

period = current_capture - last_capture + overflow;

}

enabled = TRUE;

overflow = 0;

last_capture = current_capture;

if

(sr & TIM_SR_UIF) {

if

(current_capture >= TOP / 2) {

overflow += TOP;

}

}

}

else

if

(sr & TIM_SR_UIF) {

TIMx->SR = ~TIM_SR_UIF;

overflow += TOP;

}

else

{

//THIS PATH IS EXECUTED!

GPIOB->BSRR.H.clear = (1 << 13);

GPIOB->BSRR.H.

set

= (1 << 13);

}

}

5 REPLIES 5
Posted on October 12, 2016 at 17:50

> I know that there can be a race condition involving the pipeline and/or the APB->AHB bridge/write buffer which may be causing the processor to tail-chain the interrupts.

> But I'd like to avoid these spurious interrupts, because they unnecessarily overload the processor. Clear the status register as early as possible:

uint16_t sr = TIMx->SR;

TIMx->SR = 0;

and there's no need to clear individual SR bits later. This should help, but if it won't, read back the status register into a dummy and/or add NOPs (__asm(''nop'');).

Btw. where do you clear TIMx_SR.CCIF1? Did I miss something?

JW
dismirlian2
Associate II
Posted on October 12, 2016 at 18:37

Hi JW,

Thanks for your quick answer! If I do:

uint16_t sr = TIMx->SR;

TIMx->SR = 0;

couldn't I miss an event which could fire between the read of the SR and the write to 0? As per your suggestion, I removed the individual bit clears, and modified the code:

uint16_t sr = TIMx->SR;

TIMx->SR = ~sr;

It still works, and it's more compact, but it doesn't prevent the spurious interrupts. > This should help, but if it won't, read back the status register into a dummy and/or add NOPs (__asm(''nop'');). I already tried these suggestions; they don't do anything!

>Btw. where do you clear TIMx_SR.CCIF1? Did I miss something?

According to the reference manual, reading CCR1 automatically clears the CC1IF:

current_capture = TIMx->CCR1;

Thanks for your help. Regards, Diego.
Posted on October 12, 2016 at 18:55

> couldn't I miss an event which could fire between the read of the SR and the write to 0?

True.

uint16_t sr = TIMx->SR;

TIMx->SR = ~sr;

This is the real stuff. > > This should help, but if it won't, read back the status register into a dummy and/or add NOPs (__asm(''nop'');). > > I already tried these suggestions; they don't do anything! Hummm... That would be time to look at the disassembly, or to go straight for assembler. >> Btw. where do you clear TIMx_SR.CCIF1? Did I miss something?

>

> According to the reference manual, reading CCR1 automatically clears the CC1IF: Uh. I never noticed before... One learns something new every day. Thanks. Jan
dismirlian2
Associate II
Posted on October 12, 2016 at 18:56

Hi JW,

I'm sorry I made a big mistake!! I'm using the same code to measure two signals (TIM1_CH1 and TIM3_CH1). I wrote generic code for the two timers, and I thought I was using TIM3 to test, but I'm actually using TIM1. TIM1 has *two* interrupt vectors, one for CC and one for Update, so I redirected the two vectors to the same isr() function I copied earlier. In effect, using TIM3, there are no more spurious interrupts... I think I can't avoid the problem with TIM1, because it has two different vectors. Of course, any ideas for improvement will be appreciated, but at least now I understand the problem... I'm sorry for wasting your time. For reference, the complete (working) code:

#define TOP 65536
void
isr(TIM_TypeDef *TIMx) {
static
bool
enabled;
static
uint16_t last_capture;
static
uint32_t overflow;
int
current_capture;
uint16_t sr = TIMx->SR;
TIMx->SR = ~sr;
if
(sr & TIM_SR_CC1IF) {
current_capture = TIMx->CCR1;
if
(sr & TIM_SR_CC1OF) {
enabled = FALSE;
return
;
}
if
(sr & TIM_SR_UIF) {
if
(current_capture < TOP / 2) {
overflow += TOP;
}
}
if
(enabled) {
period = current_capture - last_capture + overflow;
}
enabled = TRUE;
overflow = 0;
last_capture = current_capture;
if
(sr & TIM_SR_UIF) {
if
(current_capture >= TOP / 2) {
overflow += TOP;
}
}
} 
else
if
(sr & TIM_SR_UIF) {
overflow += TOP;
} 
else
{
//This path is executed only with TIM1 (redirecting both CC and
// UP interrupts to this handler).
GPIOB->BSRR.H.clear = (1 << 13);
GPIOB->BSRR.H.
set
= (1 << 13);
}
}

Sorry again and thanks for your help.

Diego.
dismirlian2
Associate II
Posted on October 12, 2016 at 20:19

Jan,

> This is the real stuff.

Ok, I agree.

>Uh. I never noticed before... One learns something new every day. Thanks.Yes indeed. Thank you.

Diego.