NCS Power Management

Some clarification on Power Management using NCS/Zephyr, please, for present
and future use:
1. There is System PM and Device PM.
2. System PM is associated with the processor. When the main thread (and all
other threads) end (yield or sleep) and the idle thread runs, the processor
core is stopped. If CONFIG_PM is enabled, before stopping, the processor
core is configured for low-power state, which is apparently "SystemOn Idle";
that is, either PM_STATE_RUNTIME_IDLE or PM_STATE_SUSPEND_TO_IDLE.
3. By default (or if CONFIG_PM_POLICY_DEFAULT is enabled), no other attention
to managing the system power savings is required.
If CONFIG_PM_POLICY_CUSTOM is enabled, the API can/must be used to handle
power savings under direct program control.
4. The nRF52840 (and other nRF52, and maybe other nRF5) can turn off all/part
of RAM for further power savings. There's no mention of this in the Zephyr
docs, but if CONFIG_APP_RETENTION is enabled, nrfx library resources can
be used to do this. I'm guessing ordinarily RAM is left alone and all
the static, stack, and heap items are there available for when the
system wakes up again.
3. Device PM is associated with the devices or on-chip peripherals.
Unless otherwise stated, the devices get turned off when the CPU
does (i.e., Device PM == System PM). I'm guessing Device PM does
not occur and the peripherals are not altered (PM_STATE_RUNTIME_IDLE)
unless CONFIG_PM_DEVICE is enabled, in which case the peripherals
can be shut down or powered off during System PM
(PM_STATE_SUSPEND_TO_IDLE). Or will be shut down in the absence of
any other config options.
4. The recommendation for Device PM is CONFIG_PM_DEVICE_RUNTIME.
After activating a peripheral (via is_device_ready(), it is prepped
for Device PM by calling pm_device_runtime_enable() (which also shuts it
down). Thereafter, the application code must call pm_device_runtime_get()
to wake it up when it is required and then call pm_device_runtime_put()
to shut down a device when it is done being used.
Otherwise, all the peripherals wake up when the system does, even if
they're not going to be used.
5. If Runtime Device PM is enabled, a peripheral can be shut down and remove
its contribution from the power demand even while the rest of the system
is running.
6. I've seen external sample code (from a DevZone query) in which all the
unused peripherals are "disabled" in a DeviceTree overlay. Since none of
the Zephyr samples do this, I'm guessing that unless a peripheral is
activated (via is_device_ready()), it never gets powered, or Device PM
makes sure it never gets powered.
7. Apparently, Zephyr runs (gets its "ticks") from a RTC peripheral, which is
driven either by a 32KHz crystal or a 32KHz waveform synthesized from the
main clock. I'm guessing the RTC wakes up the CPU to run any timers that
are configured, and to perform the Bluetooth radio activities on schedule.
So one of the three RTCs never gets shut down (which one?).
None of the timers are involved with the kernel, so if timer activity is
required across system sleep/low-power intervals, either no Device PM
can be used or Runtime Device PM must intentionally exclude such timers
from being shut down. I'm guessing a timer interrupt will wake up
the system just like a "tick", and there will be a system wake-up latency.
8. In the nRF52840 datasheet, peripherals don't appear to have shutdown or
power-off controls but they do have enable/disable registers. I'm guessing
that Device PM turns on/off these bits and then the PMU turns off the power
to the disabled peripheral.
8. There are a CONFIG_PM_CPU_OPS and a CONFIG_PM_DEVICE_POWER_DOMAIN and a
CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE and a series of CONFIG_PM_MCUX_ config
options, but none of the nrf or Zephyr samples use them, so they must not
be critical. Or maybe not even wired up in NCS.
9. I see some main() functions in the samples end in a busy loop and some
that do not. I've got (pre-PM) code now that after setting up the
Bluetooth structure and start a timer just ends and lets everything
just work. I'm guessing that the main() function exits to the idle
thread. Or would it be better to end in a forever-sleep?

Parents
  • 6. I've seen external sample code (from a DevZone query) in which all the
    unused peripherals are "disabled" in a DeviceTree overlay. Since none of
    the Zephyr samples do this, I'm guessing that unless a peripheral is
    activated (via is_device_ready()), it never gets powered, or Device PM
    makes sure it never gets powered.

    ANot sure if you are asking any question but all points above and including this seems correct.

    I'm guessing the RTC wakes up the CPU to run any timers that
    are configured, and to perform the Bluetooth radio activities on schedule.
    So one of the three RTCs never gets shut down (which one?).

    It is NRF_RTC1, please look into \ncs\v2.x\zephyr\drivers\timer\nrf_rtc_timer.c

    I'm guessing a timer interrupt will wake up
    the system just like a "tick", and there will be a system wake-up latency.

    Yes,rtc  timer interrupt is enabled to wakeup and handle its current_tick count updates.

    8. There are a CONFIG_PM_CPU_OPS and a CONFIG_PM_DEVICE_POWER_DOMAIN and a
    CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE and a series of CONFIG_PM_MCUX_ config
    options, but none of the nrf or Zephyr samples use them, so they must not
    be critical. Or maybe not even wired up in NCS.

    I am not sure.

    9. I see some main() functions in the samples end in a busy loop and some
    that do not. I've got (pre-PM) code now that after setting up the
    Bluetooth structure and start a timer just ends and lets everything
    just work. I'm guessing that the main() function exits to the idle
    thread. Or would it be better to end in a forever-sleep?

    Main can exit when it is not doing kernel initialization. This is clearly defined in the documentation for system threads.Not using main in application is still ok if the application does not need one.

Reply
  • 6. I've seen external sample code (from a DevZone query) in which all the
    unused peripherals are "disabled" in a DeviceTree overlay. Since none of
    the Zephyr samples do this, I'm guessing that unless a peripheral is
    activated (via is_device_ready()), it never gets powered, or Device PM
    makes sure it never gets powered.

    ANot sure if you are asking any question but all points above and including this seems correct.

    I'm guessing the RTC wakes up the CPU to run any timers that
    are configured, and to perform the Bluetooth radio activities on schedule.
    So one of the three RTCs never gets shut down (which one?).

    It is NRF_RTC1, please look into \ncs\v2.x\zephyr\drivers\timer\nrf_rtc_timer.c

    I'm guessing a timer interrupt will wake up
    the system just like a "tick", and there will be a system wake-up latency.

    Yes,rtc  timer interrupt is enabled to wakeup and handle its current_tick count updates.

    8. There are a CONFIG_PM_CPU_OPS and a CONFIG_PM_DEVICE_POWER_DOMAIN and a
    CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE and a series of CONFIG_PM_MCUX_ config
    options, but none of the nrf or Zephyr samples use them, so they must not
    be critical. Or maybe not even wired up in NCS.

    I am not sure.

    9. I see some main() functions in the samples end in a busy loop and some
    that do not. I've got (pre-PM) code now that after setting up the
    Bluetooth structure and start a timer just ends and lets everything
    just work. I'm guessing that the main() function exits to the idle
    thread. Or would it be better to end in a forever-sleep?

    Main can exit when it is not doing kernel initialization. This is clearly defined in the documentation for system threads.Not using main in application is still ok if the application does not need one.

Children
  • Thanks, this helps a lot.

    Now I've got more of a QUESTION about NCS Power Management:

    I'm guessing (and was not informed otherwise by any response to my clarification point #8 (the first #8, oops)) that Device PM puts a peripheral into low-power by setting the ENABLE register of the peripheral to disable it, and then the PMU on the chip automatically shuts down the power and/or clock to the peripheral.

    The Runtime Device PM uses a pm_device_runtime_enable(dev) call, where "dev" is a pointer to a struct device pointer, same as used in the device_is_ready() call.

    Our project uses GPIO for LEDs, the ADC to monitor the supply bus, and I2C for a sensing peripheral.  In main(), I call device_is_ready() for everything, and that works.  At the end of main(), I call pm_device_runtime_enable() for all those struct device pointer things for which device_is_ready() was called.

    I2C works.  I guess Device PM for I2C is implemented.

    GPIO ("led.port") does not work.  -134, ENOTSUP.  I see in other DevZone queries that the GPIO subsystem is not subject to power shutdown, and it does not have an ENABLE register.  So I'm not surprised.

    ADC ("adc_channels[i].dev") does not work.  -134, ENOTSUP.  This is surprising that the SAADC cannot be controlled by Device PM under NCS.  It has an ENABLE register.  I see in other posts that the ADC could be shut down in older contexts (HAL/nrf?).  Am I missing something?  Or do I need to use the nrf libraries to shut down the SAADC between readings?

  • Please create a separate ticket for this. This thread has already been with multiple different info which would be hard to search for other forum members. 

    We try to keep one thread to one context/querry.

  • Just in case someone is looking for information on the follow-up subject, like I was, it can be found here.

Related