Electrical – STM32 EXTI does not trigger interrupt

gpio-external-interruptinterruptsstm32

I am working on a device with a button that is supposed to turn it on (when pressed briefly) and off (when held longer). The MCU is an STM32L432. The button is connected to PB0. I want to use EXTI as the wakeup source from stop mode 2.

I skipped the low power mode stuff for clarity.

In the main loop I am polling the button. If it is held for more than 3 seconds I call this function:

   void power_shutdown(void){

    volatile uint32_t x = 10000000;
    while (x--){ //ugly delay for button bounce, this one is ~2s
        while (PIN_BTN_LOW){} //wait for the button to be released
    }

    //configure button interrupt
    SYSCFG->EXTICR[0] = SYSCFG_EXTICR1_EXTI0_PB; //PB0 connected to EXTI0
    EXTI->IMR1 = 0x01; //enable EXTI0 interrupt
    EXTI->FTSR1 = 0x01; //EXTI0 line falling edge trigger enable

    //turn off LEDs
    PIN_LED_GREEN_HIGH();
    PIN_LED_BLUE_HIGH();

    debugf("PR1 %08X", EXTI->PR1); //this is always 0x00000000
    debugf("PR2 %08X", EXTI->PR2); //this is always 0x00000000

    NVIC_EnableIRQ(EXTI0_IRQn);

    PIN_LED_BLUE_LOW();

    //dummy loop - entry to low power mode will be here
    while (1){}
}

I have the following interrupt handler:

void EXTI0_IRQHandler(void){
    PIN_LED_BLUE_HIGH();
    PIN_LED_GREEN_LOW();
    while (1){} //dummy loop for debugging
    //TODO: system reset here
}

I expect the handler to be called when the button is pressed. If I call power_shutdown() without polling the button (automatically after some time), then the EXTI0 handler is properly called when the button is pressed, however if the button has been pressed before (like in the normal use case), then further button presses don't trigger the handler.

Also if I force trigger a software interrupt with EXTI->SWIER1 = 0x1; before the dummy loop the handler is only called if the button has not been pressed before. If the button has been pressed before, then the handler is not called even when the pending bit in EXTI->PR1 is set.

I do have default handler and hard fault handlers installed (they are not entered). This situation happens independently no matter if the debugger is connected or not. I know I am calling the function only once, because of the dummy loop at the end.

How to make EXTI trigger an interrupt if the button has been pressed before?

Best Answer

Sorry, I misread your question. The problem is you're not clearing the interrupt flag or exiting the ISR. Instead, your handler just goes into an infinite loop. It should be clearing the interrupt flag so it can trigger again and then exiting.