nRF52810 will not enter deep sleep (system level power management)

nRF52810 will not enter deep sleep (system level power management). The method used is through pm_policy_next_state, sleep entry function , sleep exit function, and  PM notifier. All peripherals are suspended/disabled to ensure no blocking. These are in prj.conf:

CONFIG_PM=y
CONFIG_PM_DEVICE=y
CONFIG_PM_POLICY_CUSTOM=y
CONFIG_PM_DEVICE_RUNTIME=y
CONFIG_PM_DEVICE_SYSTEM_MANAGED=y
This is the source code: 
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/pm/device_runtime.h>
#include <zephyr/pm/pm.h>
#include <zephyr/sys/printk.h>
#include <hal/nrf_gpio.h>
#include <hal/nrf_clock.h>
#include <cmsis_core.h>
#include <hal/nrf_power.h>

#include <hal/nrf_gpiote.h>


#include <nrfx.h>
#include <nrfx_gpiote.h>

// Replace with your actual button pin
#define WAKEUP_PIN 20  // Example: P0.20

// --- Power diagnostics ---
static void print_clock_state(void)
{
    bool hfclk = nrf_clock_hf_is_running(NRF_CLOCK, NRF_CLOCK_DOMAIN_HFCLK);
    bool lfclk = nrf_clock_lf_is_running(NRF_CLOCK);
    printk("HFCLK running: %d\n", hfclk);
    printk("LFCLK running: %d\n", lfclk);
}

static void check_pending_irqs(void)
{
    printk("Checking pending IRQs...\n");
    for (int i = 0; i < 32; i++) {
        if (NVIC_GetPendingIRQ(i)) {
            printk("IRQ %d is pending\n", i);
        }
    }
}

static void check_gpio_sense_config(void)
{
    printk("Checking GPIO sense configs...\n");
    for (int pin = 0; pin < 32; pin++) {
        nrf_gpio_pin_sense_t sense = nrf_gpio_pin_sense_get(pin);
        if (sense != NRF_GPIO_PIN_NOSENSE) {
            printk("Pin P0.%d has sense enabled (%s)\n",
                   pin,
                   sense == NRF_GPIO_PIN_SENSE_HIGH ? "HIGH" : "LOW");
        }
    }
}

const struct pm_state_info *pm_policy_next_state(uint8_t cpu, int32_t ticks)
{
    static const struct pm_state_info suspend_state = {
        .state = PM_STATE_SUSPEND_TO_RAM,
        .substate_id = 0,
        .min_residency_us = 1000,
        .exit_latency_us = 500,
    };
    printk("pm_policy_next_state() called\n");
    // Replace with your custom condition
    bool ready_to_sleep = true;
    if (ready_to_sleep) {
        return &suspend_state;
    }

    return NULL; // Stay in active state
}

void pm_state_set(enum pm_state state, uint8_t substate_id)
{
    if (state == PM_STATE_SUSPEND_TO_RAM) {
        printk("PM: Preparing to suspend...\n");

        // Configure wake-up GPIO
        nrf_gpio_cfg_input(WAKEUP_PIN, NRF_GPIO_PIN_PULLUP);
        nrf_gpio_cfg_sense_set(WAKEUP_PIN, NRF_GPIO_PIN_SENSE_LOW);

        print_clock_state();
        check_pending_irqs();
        check_gpio_sense_config();

        __SEV();
        __WFE();
        __WFE();

        printk("PM: Woke from suspend\n");
    }
}

void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
{
    // Optional: re-init post wake if needed
}

static void on_pm_entry(enum pm_state state)
{
    if (state == PM_STATE_SUSPEND_TO_RAM) {
        //suspend_peripherals();
        printk("Notifier: system preparing to suspend.\n");
    }
}

static void on_pm_exit(enum pm_state state)
{
    if (state == PM_STATE_SUSPEND_TO_RAM) {
        //resume_peripherals();
        printk("Notifier: system resumed from suspend.\n");
    }
}

static struct pm_notifier pm_cb = {
    .state_entry = on_pm_entry,
    .state_exit = on_pm_exit,
};

static int pm_hooks_init(void)
{
    pm_notifier_register(&pm_cb);
    return 0;
}

SYS_INIT(pm_hooks_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);

void main(void)
{
    printk("System starting.\n");
    print_clock_state();
    check_pending_irqs();
    check_gpio_sense_config();
    printk("Sleeping now...\n");
    k_sleep(K_FOREVER);
   
}
I expect that after the message "Sleeping now...", I will get a message "pm_policy_next_state() called" followed by "PM: Preparing to suspend..." then "Notifier: system preparing to suspend." But the board is stuck at "Sleeping now..." Here's the RTT Viewer output:
System starting.
HFCLK running: 0
LFCLK running: 0
Checking pending IRQs...
Checking GPIO sense configs...
Sleeping now...
Does anyone have an idea on what I am doing wrong? 
I am using nRF Connect SDK v2.9.0 for VS Code, and Zephyr v3.7.99.

Thanks!


Parents
  • Hello Edgar,

    I have looked at the output dts (zephyr.dts) file. Most of the peripherals are disbaled so it is in accrodance to the dts and overlay file in the application.

    PM_STATE_SOFT_OFF resets your board upon wake up because, by design, System OFF mode always triggers a reset on wakeup, and this is the only way to achieve the lowest power state on nRF52810 devices. 

    This is the expected behavior on nRF52810 - ''

    System OFF is the deepest power saving mode the system can enter. In this mode, the system’s core functionality is powered down and all ongoing tasks are terminated.

    The device can be put into System OFF mode using the register SYSTEMOFF. When in System OFF mode, the device can be woken up through one of the following signals:

    • The DETECT signal, optionally generated by the GPIO peripheral
    • A reset''

    If you need to retain execution context and resume without a reset, you must use System ON idle mode, but this will not achieve the lowest possible current consumption. The nRF52810 does not support a "deep sleep with context retention" mode like PM_STATE_SUSPEND_TO_RAM.

Reply
  • Hello Edgar,

    I have looked at the output dts (zephyr.dts) file. Most of the peripherals are disbaled so it is in accrodance to the dts and overlay file in the application.

    PM_STATE_SOFT_OFF resets your board upon wake up because, by design, System OFF mode always triggers a reset on wakeup, and this is the only way to achieve the lowest power state on nRF52810 devices. 

    This is the expected behavior on nRF52810 - ''

    System OFF is the deepest power saving mode the system can enter. In this mode, the system’s core functionality is powered down and all ongoing tasks are terminated.

    The device can be put into System OFF mode using the register SYSTEMOFF. When in System OFF mode, the device can be woken up through one of the following signals:

    • The DETECT signal, optionally generated by the GPIO peripheral
    • A reset''

    If you need to retain execution context and resume without a reset, you must use System ON idle mode, but this will not achieve the lowest possible current consumption. The nRF52810 does not support a "deep sleep with context retention" mode like PM_STATE_SUSPEND_TO_RAM.

Children
No Data
Related