Usage Guide

Quick Start

Three steps to have an application enter PG (power gating) and be woken by the RTC.

1. Enable the Kconfig options

CONFIG_PM=y

# The idle thread stack has to be enlarged, or the sleep path overflows it
CONFIG_IDLE_STACK_SIZE=4096

# The wake-up source device itself must be enabled too
CONFIG_RTC=y
CONFIG_RTC_ALARM=y
CONFIG_RTC_AMEBA=y

2. Mark the device as a wake-up source in an overlay

&rtc {
   status = "okay";
   wakeup-source;
};

3. Configure the device in the application

The PM framework only enables a device’s wake-up capability; the device itself still has to be initialised and configured as usual, such as setting an RTC alarm or configuring a GPIO interrupt.

The application does not request sleep explicitly. The default Residency Based policy selects a state whenever the idle time is long enough; for how that is decided see Selecting a Power State. APPG followed by APPW in the serial log means one PG sleep and wake completed; for the markers see Reading the Log.

Note

Zephyr takes over arming the AP wake-up sources only when it is booted by a Zephyr-side bootloader (MCUboot, or TF-M BL2 in the //ns split configuration). Under ameba-loader the KM0 firmware arms them and the DTS properties above have no effect.

Configuration Details

Kconfig for other wake-up sources

# timer (counter) as a wake-up source
CONFIG_COUNTER=y

# GPIO as a wake-up source
CONFIG_GPIO=y

DTS for other wake-up sources

&gpiob {
   status = "okay";
   wakeup-source;
};

&timer0 {
   status = "okay";
   wakeup-source;
};

The node also needs a wakeup-source-id property, the hardware event ID of that wake-up source. It is normally already given in the SoC’s dtsi.

Note

A node with wakeup-source but no wakeup-source-id is not enabled as a wake-up source, and nothing reports it.

Warning

The ameba counter driver supports relative alarms only. Setting COUNTER_ALARM_CFG_ABSOLUTE returns -ENOTSUP and the alarm is never armed, which presents as a device that never wakes and reports nothing.

Warning

counter_cancel_channel_alarm() does not stop the counter. Per the Zephyr counter API, counter_start() asks for free running and cancelling an alarm does not undo it; a node marked wakeup-source is armed in the PMC at boot, and whether the PMC wakes the AP is independent of whether the peripheral’s own interrupt is masked.

Call counter_stop() explicitly once the wake-up source is no longer needed; for the RTC, disable the alarm by calling rtc_alarm_set_time() with mask = 0. Otherwise the leftover source keeps producing wake events, which presents as later sleep requests not entering PG.

Selecting a Power State

The Residency Based policy is used by default: the framework compares the expected idle time against each state’s min-residency-us + exit-latency-us and picks the deepest state that fits, so the application never requests a state itself. See Introduction .

The expected idle time comes from the kernel and equals the time until the next registered timeout expires (z_get_next_timeout_expiry()). It is not directly configurable; what the application controls is its own behaviour, the duration of its k_msleep() calls, its timer periods, and whether threads wake frequently.

The thresholds are declared per SoC in the dtsi as power-states nodes. The current defaults:

State

power-state-name

min-residency-us

exit-latency-us

CG

suspend-to-idle

3000

2000

PG

suspend-to-ram

5000

2500

So an idle time of 5 ms is needed before PG is chosen, between 3 ms and 5 ms CG is chosen, and below 3 ms only WFI runs. The defaults are the same on all three SoCs. The board dts declares which states are available to the CPU through cpu-power-states, currently <&pm_cg &pm_pg>.

An application may override these in an overlay, for instance to lower the PG threshold:

&pm_pg {
   min-residency-us = <2000>;
};

Note

exit-latency-us describes the hardware wake-up cost and should match what the hardware actually takes; lowering it makes the framework choose the state when the idle time does not justify it, so the wake-up cost dominates. Adjusting the threshold normally means changing min-residency-us alone.

To restrict the available states temporarily, for example to forbid PG, use Zephyr’s pm_policy_state_lock_get() / pm_policy_state_lock_put().

Per-SoC Support

RTL8721F:

CG (PM_STATE_SUSPEND_TO_IDLE) and PG (PM_STATE_SUSPEND_TO_RAM) are supported.

Boot paths: MCUboot, the //ns split configuration (TF-M BL2), and ameba-loader.

In the //ns configuration the secure world is carried across a PG, so secure session state such as a volatile key stays valid after the wake.

Running the PM Tests

zephyr/tests/boards/realtek/pm covers the system timebase, waking on a kernel timeout, several wake-up sources under both CG and PG, and repeated PG.

west twister -p rtl8721f_evb/rtl8721f/ns -T zephyr/tests/boards/realtek/pm

Supported targets:

rtl8721f_evb/rtl8721f/mcuboot
rtl8721f_evb/rtl8721f/ns
rtl872xda_evb/rtl8721dx/mcuboot
rtl872xda_evb/rtl8721dx/ns
rtl8730e_evb/rtl8730e

Note

The ameba-loader variants are not among them: there the KM0 firmware arms the wake-up sources, the test cannot arm them itself, and the AP would stay powered down. For that scenario see applications/amebaloder_pm_system_manage.

For a ready-to-run sample rather than a test suite, see applications/mcuboot_pm_system_manage, woken in turn by the RTC, a counter and a GPIO.

Reading the Log

A complete PG sleep and wake looks like this:

<inf> soc_pm: call pm_state_set: 4
APPG
NPPG
NPPW
APPW
<inf> soc_pm: [pm_state_exit_post_ops] AP wake: 4
Wake up by: rtc@4080aa00.

What each marker means:

Marker

Meaning

pm_state_set: N

Entering state N (2 is CG, 4 is PG)

APPG / APCG

AP entered PG / CG

NPPG / NPCG

NP entered PG / CG

NPPW / NPCW

NP woke

APPW / APCW

AP woke

pm_state_exit_post_ops

Post-wake processing finished

The AP entering without the NP following (APPG with no NPPG) means the NP was not ready, and the AP leaves this sleep.

Troubleshooting

Symptom

Where to look

No pm_state_set log at all

The policy selected no state. Either the idle time is below

min-residency-us + exit-latency-us, or a leftover wake-up source keeps producing events

APPG but no NPPG

The NP was not ready and the AP left this sleep

Sleeps but never wakes

The wake-up source was never armed. Check that the node has both

wakeup-source and wakeup-source-id, that no absolute alarm is used, and whether the boot path is ameba-loader

Uptime does not advance after a wake

Time compensation relies on the always-on timer0 (TIM0). If the

application takes it over as a counter device and stops or resets it, the compensation is lost