Multiple GPIO interrupts from SYSTEM_SOFT_OFF

OK, so it seems if you accidently hit "VERIFY ANSWER" your discussion gets locked and you can no longer comment, nor reverse that process.  So, I've had to start a new discussion in order to keep on with the old one:

https://devzone.nordicsemi.com/f/nordic-q-a/88286/multiple-gpio-interrupts-from-system_soft_off

What I wanted to say, rather than verify the answer, was:

Hi Simon,

Firstly, I seem to have accidently set your reply to "verified answer" and I can't seem to work out how to reverse that.

Anyway, I'm actually using the nRF Connect SDK (V1.9.1) and Zephyr, and may be 'cross-pollinating" by using those API's.  But I did ask on here if they were the only ones to use and didn't ever get an answer, so have just made them work for the moment.

What I'm seeing I don't think will benefit from button debounce, but I may be wrong.  What seems to be happening is that the first button press will trigger the device out of SYSTEM_OFF mode, and then my code starts running.  But any subsequent button press seems to interrupt the code that is being run and boot the device out of SYSTEM_OFF mode, even though I don't think it is actually in that mode.  This then seems to scramble all the registers I am using to determine how/why it came out of SYSTEM_OFF, and then I can't get it to do what it is supposed to do.

What I want to be able to do is the moment any GPIO triggers an exit from SYSTEM_OFF, that I disable this function so that any subsequent button presses will have no impact.  Essentially a bit like disabling interrupts whilst you service an exisiting interrupt.

But I can't find anywhere online where the functionality to achieve this is described.

I'd be happy to go with a low power mode rather than SYSTEM_OFF if it makes achieving what I want easier.  I can probably deal with quiescent currents of < 5uA.  Its just I couldn't actually find any helpful Zephyr/nRF Connect SDK low power examples, and everyone I have asked seems to look at me blankly.

I had a quick look at the example you listed in the original post.  Can't immediately understand much of it, but I'll go and have a more detailed look.  Also, not sure how relevant it is given I'm not using the nRF5 SDK

Cheers,

Mike

Parents Reply Children
  • Hi Simon,

    So, I'm using the system_off example in ...v1.9.1\zephyr\samples\boards\nrf\system_off and the only modifications I have made are:

    1. Configure P0.14 to be an output and set it low on start up

    2. Removed all the stuff about enabling/disabling the UART and putting it into various low(er) power modes

    3. Set P0.14 just prior to entering System Off

    4. Added a k_sleep() statement straight after the call to go into System Off, otherwise it doesn't work (a known issue with the example code)

    The delay between my button0 signal going low, and my button1 signal going low, which is essentially measuring the time it takes to get to the first line in my main.c, is around 400msec, although it does vary a bit

    This is my main.c in full.

    /*
     * Copyright (c) 2019 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <stdio.h>
    #include <zephyr.h>
    #include <device.h>
    #include <init.h>
    #include <pm/pm.h>
    #include <pm/device.h>
    #include "retained.h"
    #include <hal/nrf_gpio.h>
    
    #define CONSOLE_LABEL DT_LABEL(DT_CHOSEN(zephyr_console))
    
    #define BUSY_WAIT_S 2U
    #define SLEEP_S 2U
    
    /* Prevent deep sleep (system off) from being entered on long timeouts
     * or `K_FOREVER` due to the default residency policy.
     *
     * This has to be done before anything tries to sleep, which means
     * before the threading system starts up between PRE_KERNEL_2 and
     * POST_KERNEL.  Do it at the start of PRE_KERNEL_2.
     */
    static int disable_ds_1(const struct device *dev)
    {
    	ARG_UNUSED(dev);
    
    	pm_constraint_set(PM_STATE_SOFT_OFF);
    	return 0;
    }
    
    SYS_INIT(disable_ds_1, PRE_KERNEL_2, 0);
    
    void main(void)
    {
    	/* Configure button 1 (P0.14) to be an output to allow start up delay measurement */
    	nrf_gpio_cfg_output(DT_GPIO_PIN(DT_NODELABEL(button1), gpios));
    
    	/* Toggle P0.14 output on startup.  P0.14 is linked to button1, which has a resistor pull-up, so need to clear it */
    	nrf_gpio_pin_clear(DT_GPIO_PIN(DT_NODELABEL(button1), gpios));
    
    	printk("\n%s system off demo\n", CONFIG_BOARD);
    
    	if (IS_ENABLED(CONFIG_APP_RETENTION)) {
    		bool retained_ok = retained_validate();
    
    		/* Increment for this boot attempt and update. */
    		retained.boots += 1;
    		retained_update();
    
    		printk("Retained data: %s\n", retained_ok ? "valid" : "INVALID");
    		printk("Boot count: %u\n", retained.boots);
    		printk("Off count: %u\n", retained.off_count);
    		printk("Active Ticks: %" PRIu64 "\n", retained.uptime_sum);
    	} else {
    		printk("Retained data not supported\n");
    	}
    
    	/* Configure to generate PORT event (wakeup) on button 1 press. */
    	nrf_gpio_cfg_input(DT_GPIO_PIN(DT_NODELABEL(button0), gpios),
    			   NRF_GPIO_PIN_PULLUP);
    	nrf_gpio_cfg_sense_set(DT_GPIO_PIN(DT_NODELABEL(button0), gpios),
    			       NRF_GPIO_PIN_SENSE_LOW);
    
    	/* Reset P0.14 */
    	nrf_gpio_pin_set(DT_GPIO_PIN(DT_NODELABEL(button1), gpios));
    
    	printk("Entering system off; press BUTTON1 to restart\n");
    
    	if (IS_ENABLED(CONFIG_APP_RETENTION)) {
    		/* Update the retained state */
    		retained.off_count += 1;
    		retained_update();
    	}
    
    	/* Above we disabled entry to deep sleep based on duration of
    	 * controlled delay.  Here we need to override that, then
    	 * force entry to deep sleep on any delay.
    	 */
    	pm_power_state_force(0u, (struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
    	k_sleep(K_SECONDS(SLEEP_S));
    	printk("ERROR: System off failed\n");
    	while (true) {
    		/* spin to avoid fall-off behavior */
    	}
    }
    

    Regards,

    Mike

  • Putting the pin toggle in a SYS_INT call in either of the PRE_KERNEL stages (I've tried both PRE_KERNEL_1 and PRE_KERNAL_2) drops the start up delay down to < 400usec, which is more what I would have expected to see.

    I think if I can get my start-up delay to < 10msec, I can make things work for my application

    Cheers,

    Mike

Related