Power consumption on nrf5340 when idle is about 4mA, how to get it lower?

I have a custom board, with nrf5340, nrf7002 on it.

I would like to get the uA levels of power consumption I see other nrf5340 projects talk about (eg here  How to achieve low power consumption on custom nRF5340 board.  ) when my application is idle and the wifi is off (ie 

net_if_down(net_if_get_default());
which gives same result as actually turning off the IOVDD control)

I read here  Optimizing Power on nRF5340 SoC Designs that I need to just set

CONFIG_PM=y
CONFIG_PM_DEVICE=y
and it should enter the lowest power mode possible automatically..But this post and many others are all using old versions of NCS, and it seems the PM stuff has evolved?

On my Otii, the lowest power consumption I can see is about 4mA! This is with everything on my board held in reset or power off, and PM/PM_DEVICE enabled.

Any pointers on how to get the nrf5340 to actually go into a state where we are looking at <1mA (with RAM preservation)?

Parents
  • Hi BrianW,

    Only information regarding CONFIG_PM is outdated. The System Power Management (PM) API controls the CPU state. However, as the nRF5340 only has two states, System ON and System OFF, support for PM has been dropped, and going into System OFF is done via the Power Off API instead.

    What kind of RAM retention are you looking for? With System OFF, the system reinitializes when it wakes up. Some level of RAM retention is possible, still.

    As for CONFIG_PM_DEVICE, it enables the Device Power Management API, which let you put the "Device" in DeviceTree, so peripherals and/or sensors with drivers, into different power state. It supports two methods, runtime and system-managed. Because the nRF5340 doesn't have System PM, you will need to use the runtime API and manually disable each device.
    The runtime API is enabled with CONFIG_PM_DEVICE_RUNTIME, and usage of the API is explained in that blog post.

    We also have this documentation: Optimizing application.

    I think perhaps the peripherals weren't disabled since you misunderstood the Device PM API a little. Could you please check again?

    Hieu

Reply
  • Hi BrianW,

    Only information regarding CONFIG_PM is outdated. The System Power Management (PM) API controls the CPU state. However, as the nRF5340 only has two states, System ON and System OFF, support for PM has been dropped, and going into System OFF is done via the Power Off API instead.

    What kind of RAM retention are you looking for? With System OFF, the system reinitializes when it wakes up. Some level of RAM retention is possible, still.

    As for CONFIG_PM_DEVICE, it enables the Device Power Management API, which let you put the "Device" in DeviceTree, so peripherals and/or sensors with drivers, into different power state. It supports two methods, runtime and system-managed. Because the nRF5340 doesn't have System PM, you will need to use the runtime API and manually disable each device.
    The runtime API is enabled with CONFIG_PM_DEVICE_RUNTIME, and usage of the API is explained in that blog post.

    We also have this documentation: Optimizing application.

    I think perhaps the peripherals weren't disabled since you misunderstood the Device PM API a little. Could you please check again?

    Hieu

Children
  • Only information regarding CONFIG_PM is outdated. The System Power Management (PM) API controls the CPU state. However, as the nRF5340 only has two states, System ON and System OFF, support for PM has been dropped, and going into System OFF is done via the Power Off API instead.

    Ok, so you really need to update or flag the blog post with this information.

    What kind of RAM retention are you looking for? With System OFF, the system reinitializes when it wakes up. Some level of RAM retention is possible, still.

    I do not want to turn the system off, I want it to be in the lowest possible power state when it is in the idle state in zephyr. I expected this to be automatic, but apparently not....

    Because the nRF5340 doesn't have System PM, you will need to use the runtime API and manually disable each device.

    And where do I do this? How does my app code 'know' that zephyr is in the idle state? I understand I can turn off different devices, but I only want (for example) the UART to be off when the app is idle (which I don't know as there are multiple tasks in the system eg for the wifi stack).

    Is there a sample showing how to get a proper low power application running, eg one of the ble operational cases? I saw a post here https://github.com/zephyrproject-rtos/zephyr/issues/41382 which makes the same point.... he then goes to hack various parts of the uart code to get it to deal with the idle -> power off case, but I don't want to go changing the core NCS source! (already had to do that for other 'features' and its not sustainable). Also his MCU seems to be a nrf52, and the NCS version is old (2.6 I think)

    btw, even if I turn off all my external hardware on my board, including the nrf70, then do sys_poweroff() : its still sucking around 3.2mA....this is not what I expected from a Nordic MCU...

    Can you give me some example code that actually gets proper low power operation using the device PM API here?

    Brian

  • As for CONFIG_PM_DEVICE, it enables the Device Power Management API, which let you put the "Device" in DeviceTree, so peripherals and/or sensors with drivers, into different power state.

    So, to be clear, I cannot use the method described: https://docs.nordicsemi.com/bundle/ncs-2.9.1/page/zephyr/services/pm/device.html#system-managed_device_power_management but must call the device power management functions from my app?

  • I tried to disable all the devices in nrf53 that I use like this:

       
        pm_device_action_run((struct device *)(DEVICE_DT_GET(DT_NODELABEL(i2c1))), PM_DEVICE_ACTION_SUSPEND);
        pm_device_action_run((struct device *)(DEVICE_DT_GET(DT_NODELABEL(uart2))), PM_DEVICE_ACTION_SUSPEND);
        pm_device_action_run((struct device *)(DEVICE_DT_GET(DT_NODELABEL(spi3))), PM_DEVICE_ACTION_SUSPEND);
        pm_device_action_run((struct device *)(DEVICE_DT_GET(DT_NODELABEL(spi4))), PM_DEVICE_ACTION_SUSPEND);
        pm_device_action_run((struct device *)(DEVICE_DT_GET(DT_NODELABEL(i2s0))), PM_DEVICE_ACTION_SUSPEND);
    //  pm_device_action_run((struct device *)(DEVICE_DT_GET(DT_NODELABEL(pdm0))), PM_DEVICE_ACTION_SUSPEND);

        // Wait for logs etc to empty
        k_msleep(2000);
        pm_device_action_run((struct device *)(DEVICE_DT_GET(DT_NODELABEL(uart0))), PM_DEVICE_ACTION_SUSPEND);
        sys_poweroff();
    And the power consumption went UP from 4.2mA to 8.9mA!!!!  What is the cirrect way to suspend a device using PM_DEVICE_RUNTIME apis?
  • using the action

    PM_DEVICE_ACTION_TURN_OFF
    returns me to the case with 3.2mA after the sys_poweroff(), so no impact there (but at least its not worse!)
  • It seems a lot of things happened... I will try to address one point at a time.

    BrianW said:
    Ok, so you really need to update or flag the blog post with this information.

    I agree. I will inform our blog team.

    BrianW said:
    I do not want to turn the system off, I want it to be in the lowest possible power state when it is in the idle state in zephyr. I expected this to be automatic, but apparently not....
    BrianW said:
    And where do I do this? How does my app code 'know' that zephyr is in the idle state? I understand I can turn off different devices, but I only want (for example) the UART to be off when the app is idle (which I don't know as there are multiple tasks in the system eg for the wifi stack).

    What you are referring to is the System-managed Device PM method. In this solution, when the system changes PM state, the peripherals can also automatically change state. However, as mentioned, because the nRF5340 doesn't support PM state anymore, this method is not available.

    I can see your point about your application doesn't know when the system is or isn't idle, due to there being other SDK stacks like Wi-Fi running.
    However, is it necessary for the peripherals to be available when the only threads running are those that the application don't care about?
    I think it would be sufficient for most use cases that the application controls peripherals' power states based only on the information it has.

    Regarding your current consumption measurements, the numbers you are measuring are definitely not good. We should have under 100uA. Are you working with a custom hardware, or a DK?

    What is your measuring method? What current draws are included in the measurement?

    I think it is helpful to establish a baseline first. I usually start with Hello World, disable CONFIG_SERIAL, and that would give me a baseline for what System ON Idle should look like.
    For a Wi-Fi setup, you can refer to Lesson 6 of our Wi-Fi course for a low-power setup and use it as a baseline.

    Could you please try measure those two scenarios and let me know what value you have?

Related