cancel
Showing results for 
Search instead for 
Did you mean: 

Are EXTI flag bits sticky?

Pavel A.
Evangelist III

I have an EXTI interrupt with a shared handler, EXTI15_10_IRQHandler

Normally there should be only pin 15 interrupt.

So I did this:

void EXTI15_10_IRQHandler(void)
{
    if ((EXTI_D1->PR1 & (1<<15)) != 0)
    {
       my_handler();
      EXTI_D1->PR1 = (1 << 15);
      __DSB();
      return;
    }
 
   __BKPT(1); //unexpected interrupt
}

And sometimes I hit the breakpoint.

Looks like the EXTI_D1->PR1 corresponds to EXTI_CPUPR1 in the RM.

In debugger, bit 15 of EXTI_CPUPR1 is indeed clear.

So the question is, do EXTI_CPUPR1 bits stay on until cleared by software or they can auto-clear when the GPIO pin changes state?

-- pa

10 REPLIES 10

There are hazards here, not sure __DSB() is sufficient to address all of them as the clearance needs to escape the EXTI, into the NVIC, and effect the tail-chaining. Personally I suspect this is a race condition of several processor cycles.

Move the clearance above my_handler() and I don't thing you'll see the breakpointing.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
TDK
Guru

The EXTI_PR bits stay on until you reset them by writing 1 in software. So it will trigger off of a very short pulse even if your CPU is occupied in another IRQ when the pulse happens.

If you feel a post has answered your question, please click "Accept as Solution".

Think Pavel is battling a chain of synchronous flip-flops in the loop telling the MCU an interrupt is still pending, vs the pipeline of execution.

The DSB provides closure on the write buffers, but not on the downstream logic and flip-flops, and the propagation delays they introduce.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
berendi
Principal

The CPU might have started its interrupt tail-chaining logic already.

Maybe an __ISB() before returning would help, or reading back PR1, or both.

Pavel A.
Evangelist III

Thank you all, will try your ideas when I can get to my workplace...

--pa

>Maybe an __ISB() before returning would help, or reading back PR1, or both.

Either or none of them may help. They work only as a delay here, better or worse defined. There's no good solution, just ignore the extra interrupt.

JW

PS. On 'F4, there's a core bug as a bonus, causing similar symptoms...

Piranha
Chief II

Here is a nice explanation and a similar solution for disabling an interrupt:

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0321a/BIHJHJJA.html

Translating it to your example, putting this code before the processing code should ensure that extra interrupts don't happen:

do {
	EXTI_D1->PR1 = 1ul << 15u;
	NVIC_ClearPendingIRQ(EXTI15_10_IRQn);
} while (NVIC_GetPendingIRQ(EXTI15_10_IRQn));

But I agree to Jan - it's easier and better to make safe code, that just ignores the extra interrupts.

It's a bit tricky to get it right when more than one of EXTI{10-15} are active.

Better fall through the handler when PR1 == 0.

One day, I should revisit this observation (on an 'F4, probably everything except TIM3 in reset state - I'll try to find the original source...)

JW