cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with STM32F427 and spurious EXTI interrupts

Rhodes.Keith
Associate II
Posted on April 11, 2017 at 22:31

I use the following code to initialize the GPIO for EXTI interrupt handling.

I want GPIO F14 to trigger on the falling edge and most of the time it works properly.

However, every 1000 or so interrupts, the EXTI Interrupt routine is triggered and the

EXTI->PR register shows 0x4000, which inidicates Pin 14 was triggered.

However, the GPIO pin value is high, and a Scope shows the pin is also high (not

triggered).

When I hit the ASSERT in the interrupt routine, I examine the EXTI registers, the IMR and

FTSR registers are both 0xc000, which indicates only PIN 15 & 14 are configured.

The SYSCFG->EXTICR4 register is set to 0x5500, and all other CR registers are 0, which

indicates the interrupt didn't come from a different GPIO.

Anyone have any ideas? Do I have to mask the PR register value with the contents of the specific

GPIO to know that I am *really* triggered?

Is it possible the EXTI interrupt isn't being cleared on the previous request (even though

I don't see how)?

Thanks..Keith Rhodes

&sharpdefine POWERDOWN_PORT       GPIOF // Powerdown signal

&sharpdefine POWERDOWN_PIN          GPIO_PIN_15

&sharpdefine POWER_DOWN_MASK    0b1000000000000000 // 0x8000

&sharpdefine SPIREADY_PORT             GPIOF // SPI data ready

&sharpdefine SPIREADY_PIN                GPIO_PIN_14

&sharpdefine SPI_READY_MASK          0b0100000000000000 // 0x4000

&sharpdefine POWERDOWN_               INT_PRIORITY 5

// Initialization code for EXTI interrupts

static void EXTILine13_15_Config(void)

{

   GPIO_InitTypeDef GPIO_InitStructure;

   /* Configure PC15 pin as input floating */

   GPIO_InitStructure.Pin = POWERDOWN_PIN;

   GPIO_InitStructure.Mode = GPIO_MODE_IT_FALLING;

   GPIO_InitStructure.Pull = GPIO_PULLUP;

   GPIO_InitStructure.Speed = GPIO_SPEED_FAST;

   GPIO_InitStructure.Alternate = 0;

   HAL_GPIO_Init(POWERDOWN_PORT, &GPIO_InitStructure);

   GPIO_InitStructure.Pin = SPIREADY_PIN;

   GPIO_InitStructure.Mode = GPIO_MODE_IT_FALLING;

   GPIO_InitStructure.Pull = GPIO_PULLUP;

   GPIO_InitStructure.Speed = GPIO_SPEED_FAST;

   GPIO_InitStructure.Alternate = 0;

   HAL_GPIO_Init(SPIREADY_PORT, &GPIO_InitStructure);

   /* Enable and set EXTI15_10 Interrupt to the lowest priority */

   HAL_NVIC_SetPriority(EXTI15_10_IRQn, POWERDOWN_INT_PRIORITY, 0);

   HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);

   // Reset all interrupts

   EXTI->PR = GPIO_PIN_All;

}

volatile unsigned int tempPR;

volatile unsigned int tempEXTIGPIO = 0;

// EXTI15-10 Interrupt handler

void EXTI15_10_IRQHandler(void)

{

   tempPR = EXTI->PR;

   tempEXTIGPIO = GPIOF->IDR;

   // BUG: This ASSERT triggers when I sometimes get an interrupt

   // without the GPIO value being low

   // tempPR has 0x4000 and tempEXTIGPIO has bit 14 set

   ASSERT((tempEXTIGPIO & SPI_READY_MASK) == 0);

   if(0 != (tempPR & POWER_DOWN_MASK))

   {

      PowerDownInterruptHandler();

      __HAL_GPIO_EXTI_CLEAR_IT(POWERDOWN_PIN);

   }

   if(0 != (tempPR & SPI_READY_MASK))

   {

      SpiNotifyInterruptHandler();

      __HAL_GPIO_EXTI_CLEAR_IT(SPIREADY_PIN);

   }

}

#stm32f4 #exti #interrupts
9 REPLIES 9
Posted on April 11, 2017 at 23:25

There is a hazard if you clear the interrupt the instant prior to leaving the handler*

* It is a pipelined processor, it has delayed write buffers, you are writing to a slower peripheral, the CPU/NVIC makes tail-chaining decisions before these things close out.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on April 12, 2017 at 00:00

What is the best practice here? If I clear the interrupt before my handler, the CPU could interrupt again in my handler. Is it acceptable to add a few NOP instructions after clearing it?

Also do you have more detailed information on the NVIC implementation in the 427? I haven't seen detailed information on how the NVIC handles things like interrupting from same priority interrupts, are interrupts disabled in the handler, who pushes/pops the registers in the ISR, etc.

Thanks...Keith

Posted on April 12, 2017 at 01:40

Ok,

NOPs are non-fencing, so won't clear the pending write. Do a read of the same register, read some other volatile memory, or do the clearing earlier.

The interrupt won't preempt, at the same priority the next decision by the NVIC is made after you leave. Same with all other interrupts at the same priority level. A new decision is made when the CPU executes the 'bx lr', LR contains a magic value in this context. You can't preempt yourself, others with a higher preemption level can. Note: Higher in the NVIC sense is a smaller number.

The NVIC is part of the core, refer to ARM TRM, or Joseph Yiu's Essential Cortext-M3/M4, to better understand.

The processor pushes a minimal stack upon initial entry to IRQ context, the NVIC picks the recipient based on priority, or IRQ ♯ if others are the same. Upon EXIT the NVIC decides if another recipient is pending, if so it calls that with the dirty stack from before, if nothing is pending it pops the stack to the foreground.

One of the interesting side-effects here is if you don't CLEAR your interrupt it will simple keep re-entering, and no foreground execution will occur. This bites people the most.

The minimal stack push is primarily R0-R3,basically the registers C can use as parameters/scratch per the ABI. Also R12, LR (R14), PC (R15) and PSR. The C compiler will push LR if you call other subroutines, and R4..R7, etc if it uses them in the IRQ Handler, as it would with any C function.

Edit: Removing cite to clear the moderation.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on April 12, 2017 at 01:42

https://community.arm.com/processors/f/discussions/4557/cortex-m4-exception-return-sequence

 
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on April 14, 2017 at 03:15

I changed the order of sequence to put the clearing before my handler and it didn't change the behavior. The only way I could fix it was to use the status of its GPIO to know that I had a valid interrupt. This is a kludge, but I can't think of a better way. Happy to hear other ideas....

Rhodes.Keith
Associate II
Posted on April 25, 2017 at 13:27

I believe I must be doing something fundamentally incorrect with EXTI interrupts. I have a different board that uses the STM32F205 processor. I am also using a single EXTI interrupt (PD11 in this case). 

I have an input signal that is coming from a motor encoder and it toggles the input at a 100mS frequency. If I use the EXTI interrupt, it counts over 700 pulses in a 1 second interval. If I filter the input signal by tracking whether the GPIO is truly set, the number goes down to around 650, with a reasonable amount of variability (around 30 pulses).

If I use an alternative approach, based on a 1mS SYSTICK timer to do edge detection and filtering in the timer callback, it generates a perfect 600 pulses.

This is telling me that the EXTI interrupt is still generating false pulses. If I look at the input signal on a scope, it does have a slight rise time delay.

Does anyone have any experience implementing EXTI interrupts that work reliably?

Thanks...Keith Rhodes

Posted on April 25, 2017 at 13:52

If I look at the input signal on a scope, it does have a slight rise time delay.

If there's some noise (10%VDD, i.e. roughly 200-300mV) on that signal, plus on the referencing ground (roughly, VSS closest to that pin), and if the rise time is significantly longer than the edge detector's clock (= APB2 clock), then the EXTI unit may sense a falling edge on what you see as a slowly rising slope.

JW

juozas
Associate III
Posted on March 29, 2018 at 13:42

Hi, I am writing because believe - someone will find helpful. Crazy behavior of EXTI15_10_IRQHandler can be result of not allowed SYSCFG clock. You have to add the line RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); (if your processor STM32F4 and you are using STM stdperiphlib). Or add the line LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG); if you are using STM32F7 and STM LL libraries. Regards.

Posted on May 03, 2018 at 23:09

I know this is a cold thread but in case somebody drops in later:

While it's a common source of errors not to enable SYSCFG's (or any other module's) clock before using it, it's surely not the issue in this particular case, as witnessed by this remark in the opening post:

The SYSCFG->EXTICR4 register is set to 0x5500

JW