2017-04-11 01:31 PM
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 theEXTI->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 thoughI 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 #interrupts2017-04-11 02:25 PM
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.
2017-04-11 05:00 PM
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
2017-04-11 06:40 PM
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.
2017-04-11 06:42 PM
https://community.arm.com/processors/f/discussions/4557/cortex-m4-exception-return-sequence
2017-04-13 08:15 PM
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....
2017-04-25 04:27 AM
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
2017-04-25 06:52 AM
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
2018-03-29 04:42 AM
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.
2018-05-03 04:09 PM
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