How to detect GPIO interrupt source from deep sleep

Hi,

in my application I have setup the nRF52 to wake-up from deep sleep if a low value is detected on either of two GPIOs (4 and 5). What I'm trying to achieve, is to be able to detect upon wakeup which of the two has caused the interrupt. The issue is that it can be a very short pulse that appears on the GPIOs and causes the interrupt, such that when the device has booted again the signal has gone again to a non-interrupt state, therefore making it impossible (?) to know which GPIO caused the wakeup. Is there a good way to do it? Does the nRF52 chip has any feature that can help? Otherwise, I guess I'll have to implement externally some kind of latch.

Parents
  • Not sure if you got this sorted, but I've just been through this whole process myself.  A couple of things I uncovered:

    1. If you are using the nRF Connect SDK, this automatically enables the LFCLK, which adds a 300-400msec delay between the GPIO triggering your device out of deep sleep and your main.c code actually firing up.  Things can happen in this time that may impact the status of the LATCH register.  You can get around this by using the SYS_INIT function and running the code you need to have run (e.g. capturing the status of the LATCH register) in one of the pre-kernel states.  Below is how I did it in my code.

    /* Grabs contents of RESETREAS and LATCH registers  */
    static int detect_wakeup_latch(const struct device *dev)
    {
    	ARG_UNUSED(dev);
    
    	/* Check status of RESETREAS register to determine what caused exit from System OFF */
    	reset_reason = NRF_POWER->RESETREAS;
    	(void)NRF_TIMER0->EVENTS_COMPARE[0];
    
    	/* Record status of LATCH register to check with GPIO triggered exit from System OFF (if applicable) */
    	gpio_trigger = NRF_GPIO->LATCH;
    	
    	/* Disable inputs from affecting the DETECT signal, which should preserve LATCH and prevent spurious interrupts */
    	gpio_pin_trig_disable();
    
    	return (0);
    }
    
    SYS_INIT(detect_wakeup_latch, PRE_KERNEL_1, 0);

    2.  If you have OTA DFU functionality enabled, then the MCUBoot can scramble your LATCH register as well.  To get around that, you need to add an mcuboot.config file in a sub-directory called {your_project}/child_image.  The mcuboot.conf file just needs to contain the following:

    CONFIG_GPIO=n

    Running the MCUBoot takes around 300-400msec, so that will then push your SYS_INIT function out by the same amount of time after the GPIO trigger.

    3.  Just before my device goes back to sleep, I set up the appropriate GPIO so that their PIN_CFG[n].SENSE is set appropriately.  You can do this at a register level directly, or using one of the API's.  Below is the method I use for setting one of the buttons on the nRF52-DK to be my GPIO trigger (button corresponds to P0.13).  This will trigger the device out of sleep when the GPIO input goes low

    nrf_gpio_cfg_sense_input(sml_strike.pin, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW);

    So, with everything set up as above in my code, things go like this:

    1. GPIO triggers deivce out of sleep

    2. MCUBoot validates code in memory and then passes control to that once its happy

    3. SYS_INIT is called and I grab the value of RESETREAS and LATCH registers

    4. main.c code starts running

    Took me about a month to get to this point!! 

    Cheers,

    Mike

Reply
  • Not sure if you got this sorted, but I've just been through this whole process myself.  A couple of things I uncovered:

    1. If you are using the nRF Connect SDK, this automatically enables the LFCLK, which adds a 300-400msec delay between the GPIO triggering your device out of deep sleep and your main.c code actually firing up.  Things can happen in this time that may impact the status of the LATCH register.  You can get around this by using the SYS_INIT function and running the code you need to have run (e.g. capturing the status of the LATCH register) in one of the pre-kernel states.  Below is how I did it in my code.

    /* Grabs contents of RESETREAS and LATCH registers  */
    static int detect_wakeup_latch(const struct device *dev)
    {
    	ARG_UNUSED(dev);
    
    	/* Check status of RESETREAS register to determine what caused exit from System OFF */
    	reset_reason = NRF_POWER->RESETREAS;
    	(void)NRF_TIMER0->EVENTS_COMPARE[0];
    
    	/* Record status of LATCH register to check with GPIO triggered exit from System OFF (if applicable) */
    	gpio_trigger = NRF_GPIO->LATCH;
    	
    	/* Disable inputs from affecting the DETECT signal, which should preserve LATCH and prevent spurious interrupts */
    	gpio_pin_trig_disable();
    
    	return (0);
    }
    
    SYS_INIT(detect_wakeup_latch, PRE_KERNEL_1, 0);

    2.  If you have OTA DFU functionality enabled, then the MCUBoot can scramble your LATCH register as well.  To get around that, you need to add an mcuboot.config file in a sub-directory called {your_project}/child_image.  The mcuboot.conf file just needs to contain the following:

    CONFIG_GPIO=n

    Running the MCUBoot takes around 300-400msec, so that will then push your SYS_INIT function out by the same amount of time after the GPIO trigger.

    3.  Just before my device goes back to sleep, I set up the appropriate GPIO so that their PIN_CFG[n].SENSE is set appropriately.  You can do this at a register level directly, or using one of the API's.  Below is the method I use for setting one of the buttons on the nRF52-DK to be my GPIO trigger (button corresponds to P0.13).  This will trigger the device out of sleep when the GPIO input goes low

    nrf_gpio_cfg_sense_input(sml_strike.pin, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW);

    So, with everything set up as above in my code, things go like this:

    1. GPIO triggers deivce out of sleep

    2. MCUBoot validates code in memory and then passes control to that once its happy

    3. SYS_INIT is called and I grab the value of RESETREAS and LATCH registers

    4. main.c code starts running

    Took me about a month to get to this point!! 

    Cheers,

    Mike

Children
No Data
Related