NRF52840 DONGLE NCS 2.7.0 LOW POWER MODE

I'm trying to activate low power mode without success.
I found samples but it appears not to work with the last NCS version.

I want to get basic GPIO INPUT values at 32khz timer resolution. I get values with GPIO interruption during 100ms and send an average values on ESB radio, then the device get back to sleep for  1 second and read the signal again.

I'm lost in CONFIG_PM / CONFIG_PM_DEVICES and all parameters i should set in order to get less then 1mA during passive GPIO READS and then get less then 10uA during sleep mode.

-- CMake version: 3.21.0
-- Cache files will be written to: /Users/lilianbrun/Library/Caches/zephyr
-- Zephyr version: 3.6.99 (/opt/nordic/ncs/v2.7.0/zephyr)

In particular i can't use 
pm_state_force function, even with 

CONFIG_PM_DEVICE=y in prj.conf and 

#include <zephyr/pm/pm.h>
#include <zephyr/pm/policy.h>
#include <zephyr/pm/state.h>
#include <zephyr/pm/device.h>

I Power the device with PPK2 as 3.3V on VDD OUT pin, i cut SB2 and soldier SB1






Parents
  • As i understood, CONFIG_PM is deprecated and pm_state_* functions too.

    So i start a new simple project : 

    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <hal/nrf_rtc.h>
    #include <zephyr/pm/device.h>
    #include <zephyr/logging/log.h>
    
    LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);
    
    // Configuration RTC
    #define RTC NRF_RTC1
    #define RTC_FREQUENCY 32768    // Fréquence de l'horloge RTC (32.768 kHz)
    #define TIMEOUT_MS 900         // Temps d'attente en millisecondes
    #define TIMEOUT_TICKS (TIMEOUT_MS * RTC_FREQUENCY / 1000)
    
    volatile bool rtc_timeout = false;
    
    // Liste des périphériques à désactiver
    const char *devices_to_disable[] = {
        "UART_0",
        "UART_1",
        "SPI_0",
        "SPI_1",
        "I2C_0",
        "I2C_1",
        "PWM_0",
        "PWM_1",
        "ADC_0",
    };
    
    // Gestionnaire d'interruption RTC
    void rtc_handler(void)
    {
        if (nrf_rtc_event_check(RTC, NRF_RTC_EVENT_COMPARE_0)) {
            nrf_rtc_event_clear(RTC, NRF_RTC_EVENT_COMPARE_0);
            rtc_timeout = true;
            LOG_INF("RTC timeout reached");
        }
    }
    
    void RTC1_IRQHandler(void)
    {
        rtc_handler();
    }
    
    // Configurer le RTC pour générer une interruption après TIMEOUT_MS
    static void configure_rtc(void)
    {
        nrf_rtc_prescaler_set(RTC, 0);  // Pas de division, fréquence à 32.768 kHz
        nrf_rtc_cc_set(RTC, 0, TIMEOUT_TICKS);
        nrf_rtc_event_enable(RTC, NRF_RTC_INT_COMPARE0_MASK);
        nrf_rtc_int_enable(RTC, NRF_RTC_INT_COMPARE0_MASK);
        nrf_rtc_task_trigger(RTC, NRF_RTC_TASK_CLEAR);
        nrf_rtc_task_trigger(RTC, NRF_RTC_TASK_START);
    
        NVIC_ClearPendingIRQ(RTC1_IRQn);
        NVIC_SetPriority(RTC1_IRQn, 1);
        NVIC_EnableIRQ(RTC1_IRQn);
    
        LOG_INF("RTC configured for timeout of %d ms", TIMEOUT_MS);
    }
    
    // Désactiver les périphériques inutiles pour réduire la consommation
    static void disable_unused_devices(void)
    {
        for (int i = 0; i < ARRAY_SIZE(devices_to_disable); i++) {
            const struct device *dev = device_get_binding(devices_to_disable[i]);
            if (!dev) {
                LOG_WRN("Device %s not found", devices_to_disable[i]);
                continue;
            }
    
            if (pm_device_action_run(dev, PM_DEVICE_ACTION_SUSPEND) == 0) {
                LOG_INF("Device %s suspended", devices_to_disable[i]);
            } else {
                LOG_WRN("Failed to suspend device %s", devices_to_disable[i]);
            }
        }
    }
    
    void main(void)
    {
        LOG_INF("Starting low-power mode with RTC wakeup");
    
        // Configurer le RTC
        configure_rtc();
    
        // Désactiver les périphériques inutilisés
        disable_unused_devices();
    
        while (1) {
            rtc_timeout = false;
    
            LOG_INF("Entering low-power mode for 900 ms...");
            k_sleep(K_MSEC(900));  // Le système entre en System ON Idle ici
    
            // Attendre que le RTC atteigne son timeout
            while (!rtc_timeout) {
                k_sleep(K_MSEC(1));
            }
    
            LOG_INF("Woke up from low-power mode");
        }
    }
    


    # Enable GPIO and RTC
    CONFIG_GPIO=y
    
    # Enable power management
    CONFIG_PM_DEVICE=y
    
    # Optimize stack sizes
    CONFIG_MAIN_STACK_SIZE=1024
    CONFIG_IDLE_STACK_SIZE=256
    
    # Disable unnecessary logging to save power
    CONFIG_PRINTK=n
    CONFIG_CONSOLE=n
    CONFIG_SERIAL=n
    CONFIG_LOG=y
    


    And i works a bit, but i get a constant average consumption of 214uA, which is far more than expected, regarding what it does.

Reply
  • As i understood, CONFIG_PM is deprecated and pm_state_* functions too.

    So i start a new simple project : 

    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <hal/nrf_rtc.h>
    #include <zephyr/pm/device.h>
    #include <zephyr/logging/log.h>
    
    LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);
    
    // Configuration RTC
    #define RTC NRF_RTC1
    #define RTC_FREQUENCY 32768    // Fréquence de l'horloge RTC (32.768 kHz)
    #define TIMEOUT_MS 900         // Temps d'attente en millisecondes
    #define TIMEOUT_TICKS (TIMEOUT_MS * RTC_FREQUENCY / 1000)
    
    volatile bool rtc_timeout = false;
    
    // Liste des périphériques à désactiver
    const char *devices_to_disable[] = {
        "UART_0",
        "UART_1",
        "SPI_0",
        "SPI_1",
        "I2C_0",
        "I2C_1",
        "PWM_0",
        "PWM_1",
        "ADC_0",
    };
    
    // Gestionnaire d'interruption RTC
    void rtc_handler(void)
    {
        if (nrf_rtc_event_check(RTC, NRF_RTC_EVENT_COMPARE_0)) {
            nrf_rtc_event_clear(RTC, NRF_RTC_EVENT_COMPARE_0);
            rtc_timeout = true;
            LOG_INF("RTC timeout reached");
        }
    }
    
    void RTC1_IRQHandler(void)
    {
        rtc_handler();
    }
    
    // Configurer le RTC pour générer une interruption après TIMEOUT_MS
    static void configure_rtc(void)
    {
        nrf_rtc_prescaler_set(RTC, 0);  // Pas de division, fréquence à 32.768 kHz
        nrf_rtc_cc_set(RTC, 0, TIMEOUT_TICKS);
        nrf_rtc_event_enable(RTC, NRF_RTC_INT_COMPARE0_MASK);
        nrf_rtc_int_enable(RTC, NRF_RTC_INT_COMPARE0_MASK);
        nrf_rtc_task_trigger(RTC, NRF_RTC_TASK_CLEAR);
        nrf_rtc_task_trigger(RTC, NRF_RTC_TASK_START);
    
        NVIC_ClearPendingIRQ(RTC1_IRQn);
        NVIC_SetPriority(RTC1_IRQn, 1);
        NVIC_EnableIRQ(RTC1_IRQn);
    
        LOG_INF("RTC configured for timeout of %d ms", TIMEOUT_MS);
    }
    
    // Désactiver les périphériques inutiles pour réduire la consommation
    static void disable_unused_devices(void)
    {
        for (int i = 0; i < ARRAY_SIZE(devices_to_disable); i++) {
            const struct device *dev = device_get_binding(devices_to_disable[i]);
            if (!dev) {
                LOG_WRN("Device %s not found", devices_to_disable[i]);
                continue;
            }
    
            if (pm_device_action_run(dev, PM_DEVICE_ACTION_SUSPEND) == 0) {
                LOG_INF("Device %s suspended", devices_to_disable[i]);
            } else {
                LOG_WRN("Failed to suspend device %s", devices_to_disable[i]);
            }
        }
    }
    
    void main(void)
    {
        LOG_INF("Starting low-power mode with RTC wakeup");
    
        // Configurer le RTC
        configure_rtc();
    
        // Désactiver les périphériques inutilisés
        disable_unused_devices();
    
        while (1) {
            rtc_timeout = false;
    
            LOG_INF("Entering low-power mode for 900 ms...");
            k_sleep(K_MSEC(900));  // Le système entre en System ON Idle ici
    
            // Attendre que le RTC atteigne son timeout
            while (!rtc_timeout) {
                k_sleep(K_MSEC(1));
            }
    
            LOG_INF("Woke up from low-power mode");
        }
    }
    


    # Enable GPIO and RTC
    CONFIG_GPIO=y
    
    # Enable power management
    CONFIG_PM_DEVICE=y
    
    # Optimize stack sizes
    CONFIG_MAIN_STACK_SIZE=1024
    CONFIG_IDLE_STACK_SIZE=256
    
    # Disable unnecessary logging to save power
    CONFIG_PRINTK=n
    CONFIG_CONSOLE=n
    CONFIG_SERIAL=n
    CONFIG_LOG=y
    


    And i works a bit, but i get a constant average consumption of 214uA, which is far more than expected, regarding what it does.

Children
No Data
Related