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

  • 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?
Reply
  • 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?
Children
  • 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?

  • However, is it necessary for the peripherals to be available when the only threads running are those that the application don't care about?

    Well, the uart is a case when the uart driver is handling the tx/rx and with all the different methods of api to the uart (interuupt, async, console, etc) its not always clear when it can be powered off. And in fact, I discovered that the enabling of the PM_DRIVER/PM_DRIVER_RUNTIME somehow broke my use of uart2 in interrupt api mode - for now I've just removed these options as I don't see what is making the driver no longer call my isr to handle tx/rx?!

    However, as mentioned, because the nRF5340 doesn't support PM state anymore, this method is not available.

    This is IMHO a mistaken decision on Nordic's part and your dev team should seriously reconsider it. But what do I know, I'm just trying to make a product using this stuff....

    Regarding your current consumption measurements, the numbers you are measuring are definitely not good. We should have under 100uA.

    Ok. That would be nice..

    Are you working with a custom hardware, or a DK?

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

    Custom hardare, so I cannot rule out (right now) the other components on the board being the bad guys - although I have tried to force everything into reset or low power modes (and this has an effect and gets me to the current position).

    I'm measuring current draw from the battery connector using an Otii Arc to emulate the battery and show me the measurtement, with no charger connected (obviously!)

    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.

    Yes, I need to do this, on both the DK and then on my custom hw. This wont be until for 4-5 weeks now, as I am going to be out of the office for a while.... I'll update when I get new data!

Related