system off

Hi

Our goal is to wake up the board from system_off and read which button wakes it up. Can you provide an example for reference?

Use ncs 2.2.0

nrf52840Dk

  • Hi,

    You can check the LATCH register as explained in this post. You can use nrf_gpio_pin_latch_get() and nrf_gpio_pin_latch_clear() to achieve it. See this diff from the nRF5x System Off demo from nRF Connect SDK 2.2.0 for an example of how you can do it:

    diff --git a/samples/boards/nrf/system_off/src/main.c b/samples/boards/nrf/system_off/src/main.c
    old mode 100644
    new mode 100755
    index 5f99e51de0..d02fc08571
    --- a/samples/boards/nrf/system_off/src/main.c
    +++ b/samples/boards/nrf/system_off/src/main.c
    @@ -35,6 +35,19 @@ static int disable_ds_1(const struct device *dev)
     
     SYS_INIT(disable_ds_1, PRE_KERNEL_2, 0);
     
    +static void print_wakeup_source(void)
    +{
    +	if (nrf_gpio_pin_latch_get(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw0), gpios))) {
    +		printk("BUTTON1 woke me up!\n");
    +		nrf_gpio_pin_latch_clear(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw0), gpios));
    +	}
    +
    +	if (nrf_gpio_pin_latch_get(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw1), gpios))) {
    +		printk("BUTTON2 woke me up!\n");
    +		nrf_gpio_pin_latch_clear(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw1), gpios));
    +	}
    +}
    +
     void main(void)
     {
     	int rc;
    @@ -47,6 +60,8 @@ void main(void)
     
     	printk("\n%s system off demo\n", CONFIG_BOARD);
     
    +	print_wakeup_source();
    +
     	if (IS_ENABLED(CONFIG_APP_RETENTION)) {
     		bool retained_ok = retained_validate();
     
    @@ -62,11 +77,15 @@ void main(void)
     		printk("Retained data not supported\n");
     	}
     
    -	/* Configure to generate PORT event (wakeup) on button 1 press. */
    +	/* Configure to generate PORT event (wakeup) on button 1 or 2 press. */
     	nrf_gpio_cfg_input(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw0), gpios),
     			   NRF_GPIO_PIN_PULLUP);
     	nrf_gpio_cfg_sense_set(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw0), gpios),
     			       NRF_GPIO_PIN_SENSE_LOW);
    +	nrf_gpio_cfg_input(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw1), gpios),
    +			   NRF_GPIO_PIN_PULLUP);
    +	nrf_gpio_cfg_sense_set(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw1), gpios),
    +			       NRF_GPIO_PIN_SENSE_LOW);
     
     	printk("Busy-wait %u s\n", BUSY_WAIT_S);
     	k_busy_wait(BUSY_WAIT_S * USEC_PER_SEC);
    @@ -84,7 +103,7 @@ void main(void)
     	k_sleep(K_SECONDS(SLEEP_S));
     	rc = pm_device_action_run(cons, PM_DEVICE_ACTION_RESUME);
     
    -	printk("Entering system off; press BUTTON1 to restart\n");
    +	printk("Entering system off; press BUTTON1 or BUTTON2 to restart\n");
     
     	if (IS_ENABLED(CONFIG_APP_RETENTION)) {
     		/* Update the retained state */
    

  •  

    hi 

    I followed the steps to test, but the result is a failure. I attach main.c and log for your reference. Am I missing any steps?

    Can you test on nrf52840 dk? And give me suggestions

    /*
     * Copyright (c) 2019 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <stdio.h>
    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/init.h>
    #include <zephyr/pm/pm.h>
    #include <zephyr/pm/device.h>
    #include <zephyr/pm/policy.h>
    #include <soc.h>
    #include "retained.h"
    #include <hal/nrf_gpio.h>
    
    #define BUSY_WAIT_S 2U
    #define SLEEP_S 2U
    
    #if CONFIG_LOG
      #include <logging/log.h>
      LOG_MODULE_REGISTER(WAKEUP, LOG_LEVEL_DBG);
    #endif
    
    static void print_wakeup_source(void)
    {
        if (nrf_gpio_pin_latch_get(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw2), gpios))) {
            LOG_DBG("BUTTON3 woke me up!");
    		nrf_gpio_pin_latch_clear(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw2), gpios));
           }
        if (nrf_gpio_pin_latch_get(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw3), gpios))) {
            LOG_DBG("BUTTON4 woke me up!");
    		nrf_gpio_pin_latch_clear(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw3), gpios));
        }
    }
    
    
    void main(void)
    {
    	int rc;
    	const struct device *const cons = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
    
    	if (!device_is_ready(cons)) {
    		LOG_DBG("%s: device not ready.\n", cons->name);
    		return;
    	}
    
    	LOG_DBG("\n%s system off demo\n", CONFIG_BOARD);
    
    	print_wakeup_source();
    	
    	/* Configure to generate PORT event (wakeup) on button 3 or 4 press. */
    	nrf_gpio_cfg_input(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw2), gpios),
    			   NRF_GPIO_PIN_PULLUP);
    	nrf_gpio_cfg_sense_set(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw2), gpios),
    			       NRF_GPIO_PIN_SENSE_LOW);
    	nrf_gpio_cfg_input(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw3), gpios),
    			   NRF_GPIO_PIN_PULLUP);
    	nrf_gpio_cfg_sense_set(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw3), gpios),
    			       NRF_GPIO_PIN_SENSE_LOW);
    
    	LOG_DBG("Busy-wait %u s\n", BUSY_WAIT_S);
    	k_busy_wait(BUSY_WAIT_S * USEC_PER_SEC);
    	k_sleep(K_SECONDS(SLEEP_S));
    	rc = pm_device_action_run(cons, PM_DEVICE_ACTION_RESUME);
    
    	LOG_DBG("Entering system off; press BUTTON1 or BUTTON2 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_state_force(0u, &(struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
    
    	/* Now we need to go sleep. This will let the idle thread runs and
    	 * the pm subsystem will use the forced state. To confirm that the
    	 * forced state is used, lets set the same timeout used previously.
    	 */
    	k_sleep(K_SECONDS(SLEEP_S));
    
    	LOG_DBG("ERROR: System off failed\n");
    	while (true) {
    		/* spin to avoid fall-off behavior */
    	}
    }

  • Hi,

    The simplest would be to just test the exact changes I sugtested to the esample, which I tested and work out of the box on a nRF52840 DK. That said, I am a bit unsure about what SDK you use as this does not build out of the box with NCS 2.2.0 (to use the logger you need to include  #include <zephyr/logging/log.h>). Anyway, as logging is not enabled in the sample etc and not relevant here, I just replaced it with printk and fixed a few other things (button numbering, line breaks), and tested on my end, and this works as expected. Please note that you need to wait for the device to enter system off mode for this demo to be efficient.

    Here I wait for it entering system off mode, then wake it up by button 3. Then I wait and wake it up by botton 4. Lastly, I press both buttons, and you will see that as well.

    *** Booting Zephyr OS build v3.2.99-ncs1 ***
    
    nrf52840dk_nrf52840 system off demo
    Busy-wait 2 s
    Entering system off; press BUTTON3 or BUTTON4 to restart
    *** Booting Zephyr OS build v3.2.99-ncs1 ***
    
    nrf52840dk_nrf52840 system off demo
    BUTTON3 woke me up!
    Busy-wait 2 s
    Entering system off; press BUTTON3 or BUTTON4 to restart
    *** Booting Zephyr OS build v3.2.99-ncs1 ***
    
    nrf52840dk_nrf52840 system off demo
    BUTTON4 woke me up!
    Busy-wait 2 s
    Entering system off; press BUTTON3 or BUTTON4 to restart
    *** Booting Zephyr OS build v3.2.99-ncs1 ***
    
    nrf52840dk_nrf52840 system off demo
    BUTTON3 woke me up!
    BUTTON4 woke me up!
    Busy-wait 2 s
    Entering system off; press BUTTON3 or BUTTON4 to restart

    This is the modified code from you that I used:

    /*
     * Copyright (c) 2019 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <stdio.h>
    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/init.h>
    #include <zephyr/pm/pm.h>
    #include <zephyr/pm/device.h>
    #include <zephyr/pm/policy.h>
    #include <soc.h>
    #include "retained.h"
    #include <hal/nrf_gpio.h>
    
    #define BUSY_WAIT_S 2U
    #define SLEEP_S 2U
    
    
    static void print_wakeup_source(void)
    {
        if (nrf_gpio_pin_latch_get(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw2), gpios))) {
            printk("BUTTON3 woke me up!\n");
    		nrf_gpio_pin_latch_clear(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw2), gpios));
           }
        if (nrf_gpio_pin_latch_get(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw3), gpios))) {
            printk("BUTTON4 woke me up!\n");
    		nrf_gpio_pin_latch_clear(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw3), gpios));
        }
    }
    
    
    void main(void)
    {
    	int rc;
    	const struct device *const cons = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
    
    	if (!device_is_ready(cons)) {
    		printk("%s: device not ready.\n", cons->name);
    		return;
    	}
    
    	printk("\n%s system off demo\n", CONFIG_BOARD);
    
    	print_wakeup_source();
    	
    	/* Configure to generate PORT event (wakeup) on button 3 or 4 press. */
    	nrf_gpio_cfg_input(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw2), gpios),
    			   NRF_GPIO_PIN_PULLUP);
    	nrf_gpio_cfg_sense_set(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw2), gpios),
    			       NRF_GPIO_PIN_SENSE_LOW);
    	nrf_gpio_cfg_input(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw3), gpios),
    			   NRF_GPIO_PIN_PULLUP);
    	nrf_gpio_cfg_sense_set(NRF_DT_GPIOS_TO_PSEL(DT_ALIAS(sw3), gpios),
    			       NRF_GPIO_PIN_SENSE_LOW);
    
    	printk("Busy-wait %u s\n", BUSY_WAIT_S);
    	k_busy_wait(BUSY_WAIT_S * USEC_PER_SEC);
    	k_sleep(K_SECONDS(SLEEP_S));
    	rc = pm_device_action_run(cons, PM_DEVICE_ACTION_RESUME);
    
    	printk("Entering system off; press BUTTON3 or BUTTON4 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_state_force(0u, &(struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
    
    	/* Now we need to go sleep. This will let the idle thread runs and
    	 * the pm subsystem will use the forced state. To confirm that the
    	 * forced state is used, lets set the same timeout used previously.
    	 */
    	k_sleep(K_SECONDS(SLEEP_S));
    
    	printk("ERROR: System off failed\n");
    	while (true) {
    		/* spin to avoid fall-off behavior */
    	}
    }
    

  • Hi

    It works fine when using uart output log.but It fails when using jlink rrt output log. Is jlink rtt log not available in system off mode?

  • Technically neither should be "available" in system off mode.

    But the active Jlink debug connection needed for RTT also disables system OFF mode - it downgrades to simulated system off.

Related