0
\$\begingroup\$

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?

\$\endgroup\$
  • \$\begingroup\$ Yes - I call __HAL_RCC_SYSCFG_CLK_ENABLE(); at startup. \$\endgroup\$ – filo Apr 30 at 18:48
  • \$\begingroup\$ Yes. The button reacts correctly whenever I do GPIOB->IDR & GPIO_IDR_ID0_Msk, pullup is enabled. \$\endgroup\$ – filo Apr 30 at 18:50
  • \$\begingroup\$ It is correct because if I call the function after some time (ie. without pressing a button) and THEN press the button then the handler is called as expected. \$\endgroup\$ – filo Apr 30 at 18:55
0
\$\begingroup\$

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.

\$\endgroup\$
0
\$\begingroup\$

I have found the issue. During my testing when I called power_shutdown() manually it was done in the main loop (and behaved as expected), while button sampling was done in a timer interrupt callback (so in the ISR context). The EXTI handler could never be called, because power_shutdown() was already in ISR context (and never intended to return).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.