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...
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!
Thanks!