nRF52840 Power Management when idle

Greetings,

I am looking into power management options for our custom board using the nrf52840 with the nRF Connect SDK.

I wanted to ask for a clarification if possible.

Do I have to enable anything other than CONFIG_PM=y option to enable the system to go into low power mode when the idle thread is running?

Do I have to use the CAF for that to happen?

Thank you!

Best Regards,

Stavros

Parents
  • Hello Stavros,

     You can disable UART by using CONFIG_SERIAL=n.

    Thanks.

    BR

    Kazi

  • Hello Kazi.

    Thank you for your quick response!

    I did read about disabling the UART in the documentation, thank you for suggesting this (although in our case we need the UART for communication and DFU so that is not possible).

    If you could confirm my question as well it would be really helpful!

    When CONFIG_PM=y configuration option is selected the MCU will go into low-power/sleep mode when the idle thread is running, is that correct?Can you please confirm this?

    Thank you!

    BR

    Stavros

  • Hello Stavros,

    CONFIG_PM = y only includes the library which is used for the power state of peripherals. So, setting this configuration does not help MCU to go into low-power/sleep mode. 

    But if you want to use the power management library to turn off different peripherals before going to sleep, you need to enable this in config so the correct libraries are included in the build to turn the peripherals off. However, you still need to handle the power state of some of the peripherals in the code manually through this library.

    Thanks.

    BR
    Kazi

  • Hello Kazi,

    So the quote below is false? Seems this question has been asked before and a Nordic enginner confirmed this in this ticket (question 2).

    From the Zephyr docmentation:

    "The kernel enters the idle state when it has nothing to schedule. If enabled via the CONFIG_PM Kconfig option, the Power Management Subsystem can put an idle system in one of the supported power states, based on the selected power management policy and the duration of the idle time allotted by the kernel."

    Form the quote above I understand that when this configuration is enabled when the system runs the idle thread the Power Management Subsystem puts the device in one of the supported power states.

    It is also stated in this video by Zephyr that states "that when the idle thread is called and CONFIG_PM is enabled it calls the pm_system_suspend() function which takes care of the por management of the MCU"

    If this is indeed not the case are there any samples/examples that show how to use this library and put the device to a low-power state when the idle thread is running? I am refering to System PM not Device PM.

    Thank you

    Best regards,

    Stavros

Reply
  • Hello Kazi,

    So the quote below is false? Seems this question has been asked before and a Nordic enginner confirmed this in this ticket (question 2).

    From the Zephyr docmentation:

    "The kernel enters the idle state when it has nothing to schedule. If enabled via the CONFIG_PM Kconfig option, the Power Management Subsystem can put an idle system in one of the supported power states, based on the selected power management policy and the duration of the idle time allotted by the kernel."

    Form the quote above I understand that when this configuration is enabled when the system runs the idle thread the Power Management Subsystem puts the device in one of the supported power states.

    It is also stated in this video by Zephyr that states "that when the idle thread is called and CONFIG_PM is enabled it calls the pm_system_suspend() function which takes care of the por management of the MCU"

    If this is indeed not the case are there any samples/examples that show how to use this library and put the device to a low-power state when the idle thread is running? I am refering to System PM not Device PM.

    Thank you

    Best regards,

    Stavros

Children
  • Hi Kazi,

    Kind reminder if you have any updates or feedback on my previous message they will be greatly appreaciated!

    Thank you!

    BR

    Savros

  • Hi Savros,

    You don't have to do anything to actively put the chip into System ON idle mode. After all threads are finished (or threads are put to sleep by k_msleep() or similar), the CPU enters the idle thread, and wakes up on the next event. This happens regardless of the CONFIG_PM state.

    CONFIG_PM is set to =y by default in the samples, but actively turning this off does not prevent the CPU from entering the idle thread. What you want to do is to use CONFIG_PM_DEVICE to turn off peripherals that are still active after the CPU enters the idle thread.

    Here is an example using the zephyr/sample/basic/blinky:

    • When you run this out of the box on a nRF52 DK you can see that the idle current is around 500-800 uA (depending on which chip you use).
    • The main loop enters k_msleep() after toggling the GPIO.
    • k_msleep() lets the CPU enter the idle thread, and the CPU will now be in system ON idle until the timer runs out after SLEEP_TIME_MS milliseconds (or another thread wakes up the CPU)

    But why does the example still consume 500-800 uA? This is because logging is enabled, and logging uses the UART peripheral.

    There are two ways to turn off logging.

    1. The easiest way is to put CONFIG_SERIAL=n in the prj.conf file as this will shut down all the UART peripherals. But then you can not use UART later.
    2. Use the power management API:
      • Add CONFIG_PM_DEVICE=y to prj.conf
      • Add #include <zephyr/pm/device.h> to main.c
      • The following code will turn off the logging module (and UART):
        const struct device *uart0_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
        pm_device_action_run(uart0_dev, PM_DEVICE_ACTION_SUSPEND);

    The resulting main.c for the zephyr/samples/basic/blinky example will look something like this:

    #include <zephyr/kernel.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/pm/device.h>
    
    
    /* 1000 msec = 1 sec */
    #define SLEEP_TIME_MS   1000
    
    /* The devicetree node identifier for the "led0" alias. */
    #define LED0_NODE DT_ALIAS(led0)
    
    /*
     * A build error on this line means your board is unsupported.
     * See the sample documentation for information on how to fix this.
     */
    static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
    const struct device *uart0_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));
    
    void main(void)
    {
    	int ret;
    
    	ret = pm_device_action_run(uart0_dev, PM_DEVICE_ACTION_SUSPEND);
    	if (ret < 0) {
    		return;
    	}
    
    	if (!device_is_ready(led.port)) {
    		return;
    	}
    
    	ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
    	if (ret < 0) {
    		return;
    	}
    
    	while (1) {
    		ret = gpio_pin_toggle_dt(&led);
    		if (ret < 0) {
    			return;
    		}
    		k_msleep(SLEEP_TIME_MS);
    	}
    }

    And prj.conf:

    CONFIG_GPIO=y
    CONFIG_PM_DEVICE=y

    I tested the code above on a DK and the idle current is around 2 uA. If I set CONFIG_PM to =n the idle current is still around 2 uA.

    Best regards,
    Stian

  • Hi Stian,

    Thank you very much for the very thorough and helpful response!

    This is exactly the information I was looking for to confirm! 

    I will need a little bit of time to check if I have any other pending/followup questions and I will close the ticket asap.

    Thanks again!

    Best regards,

    Stavros

Related