# Power Management Subsystem

This document is supplemental to PowerManager_Interface.hpp. It provides some additional context and reference information for the various processor power states.

## Sleeping the System

The most basic power-management operation, and an alternative to a "delay", is `PowerManager::sleep()`. This puts the processor into CSLeep mode via a `wfi` operation. This reduces power consumption while there is no work to be performed. The processor will wake up and resume execution at the `sleep()` call when an interrupt occurs.

It's important to note that the processor requires an interrupt to wake up. If you don't have an interrupt pending, the system will not wake. You can instead invoke `PowerManager::sleep(max_time)` to configure a timer to wake the system after a specific period. This is useful in case there are no interrupts pending, or simply to provide intermittent wake-up capabilities.

## System Power States

Aside from `sleep()`, the system can be put into a number of power states via `PowerManagement::setState()`.

- Active (pending implementation), which represents a fully powered-on system
- Standby, which represents the state of the system immediately/ after booting up
- Suspend, which turns off most processor power sources. The processor will wake up from any interrupt.
	+ Maps to the processor power state "CStop/Stop"
- DeepSleep, which turns off everything but backup power to the processor. The processor will wake on an RTC event.
	+ Maps to the processor power state "Suspend"
- Shutdown
	+ Power-off the system

### Suspend Mode

Suspend mode maps to the processor's CStop/Stop power state. This state is entered via `wfi`. The system clocks are turned off, except those peripherals that are configured to stay active. The system will wake from any interrupt.

After waking up, the system clocks need to be reconfigured (if Stop mode was successfully entered). Execution will resume following the call to `setState(Suspend)`. All contents of memory will be preserved.

If no interrupt source is expected, it is recommended to use `PowerManagement::setWakeupAlarm()` to configure a future wakeup event.

### Deep Sleep Mode

Deep sleep mode maps to the processor's Suspend power state. Deep sleep mode is extremely low power. It will turn off all clocks except the LSE clock, and only the backup regulator will be kept on (to enable Backup SRAM). This means that contents of the normal SRAM region will be erased upon entering Deep Sleep mode.

You can place variables into Backup SRAM to preserve their value across Suspend/Deep Sleep state. See [MemoryRegions.md](MemoryRegions.md) for more  information on this. The RTC also contains backup registers that can be used to preserve data when the main supply is off.

Prior to entering deep sleep mode, you **must** use `PowerManagement::setWakeupAlarm()` to configure a future wakeup event. Otherwise, the system will not wake until you reset the system.

## Debugging in Low Power Mode

**NOTE: Low-power modes appear to cause some minor inconveniences with debugging.**

Sometimes you end up in a SIGTRAP situation when putting the system into Suspend mode. In these cases, you can continue after it has stopped with the SIGTRAP, and the system execution continues as expected (sometimes it might trap multiple times, e.g. if you’re Suspending for 5 seconds and click continue quickly, it will repeat until the 5 seconds has elapsed).

This behavior does not happen for me with DeepSleep mode or when issuing just a WFI, which is curious.

### Validating Low-Power Modes using GPIO

Power state monitoring pins are available for checking the power states:

- CSLEEP - Sleeping CPU state
- CDSLEEP - Deepsleep CPU state
- D1PWREN - Domain power enabled

## Processor Power State Documentation

The following notes were captured by Phillip when reviewing the processor reference manual on the supported power states.

### CSleep

- CSleep (CPU clock stopped)
	- 6.7.5, pg 293
	- The CSleep mode applies only to the CPU subsystem. In CSleep mode, the CPU clock is stopped. The CPU subsystem peripheral clocks operate according to the values of PERxLPEN bits in RCC_C1_xxxxENR or RCC_DnxxxxENR.
	- WFI or WFE while SLEEPDEEP=0, CPU NVIC interrupts and events cleared
	- On return from ISR while:
		- SLEEPDEEP = 0
		- SLEEPONEXIT = 1
		- CPU NVIC Interrupts and events cleared
	- Exits on any interrupt enabled in NVIC
	- Has No Wakeup Latency

### CStop, Stop

- CStop (CPU subsystem clock stopped)
	- 6.7.6, pg 294
	- The CStop mode applies only to the CPU subsystem. In CStop mode, the CPU clock is stopped. Most CPU subsystem peripheral clocks are stopped too and only the CPU subsystem peripherals having a PERxAMEN bit operate accordingly.
		- In CStop mode, the CPU subsystem peripherals that have a kernel clock request can still request their kernel clock. 
		- For the peripheral that have a PERxAMEN bit, this bit shall be set to be able to request the kernel clock.
	- Entry is the same as CSeep, but has SLEEPDEEP=1 set in appropriate spots
	- Exit with WFI or interrupt
		- EXTI Interrupt enabled in NVIC: Refer to Table 145: NVIC, for peripheral which are not stopped or powered down.
	- Wakeup latency: EXTI and RCC wakeup synchronization (see Section 8.4.7: Power-on and wakeup sequences)
- Stop (System clock stopped)
	- 6.7.8, pg 296
	- The system D3 domain enters Stop mode only when the CPU subsystem is in CStop mode, the EXTI wakeup sources are inactive and at least one PDDS_Dn bit in PWR CPU control register (PWR_CPUCR) for any domain request Stop.
	- In Stop mode, the system clock including a PLL and the D3 domain bus matrix clocks are stopped. When HSI or CSI is selected, the system oscillator operates according to the HSIKERON and CSIKERON bits in RCC_CR register. Other system oscillator sources are stopped.
	- I/O pin configuration remain unchanged in Stop mode.
	- What can operate in stop mode
		- In Stop mode, the domain peripherals that use the LSI or LSE clock, and the peripherals that have a kernel clock request to select HSI or CSI as source, are still able to operate.
		- In system Stop mode, the following features can be selected to remain active by programming individual control bits:
			- Independent watchdog (IWDG)
			- Real-time clock (RTC)
				- This is configured via the RTCEN bit in the RCC backup domain control register (RCC_BDCR).
			- Internal RC oscillator (LSI RC)
				- This is configured via the LSION bit in the RCC clock control and status register (RCC_CSR)
			- External 32.768 kHz oscillator (LSE OSC)
				- This is configured via the LSEON bit in the RCC backup domain control register (RCC_BDCR).
			-  Peripherals capable of running on the LSI or LSE clock.
			- Peripherals having a kernel clock request.
			- Internal RC oscillators (HSI and CSI)
				- This is configured via the HSIKERON and CSIKERON bits in the RCC clock control and status register (RCC_CSR).
			- The ADC or DAC can also consume power during Stop mode, unless they are disabled before entering this mode. To disable them, the ADON bit in the ADC_CR2 register and the ENx bit in the DAC_CR register must both be written to 0
	- Entering
		- When the CPU is in CStop mode and there is no active EXTI Wakeup source and Run_D3 = 0.
		- At least one PDDS_Dn bit for any domain select Stop.
		- Use a DSB instruction to ensure that outstanding memory transactions complete before entering stop mode.
	- Exit
		- On an EXTI wakeup
		- STOPF status flag in PWR CPU control register (PWR_CPUCR) indicates that the system has exited from Stop mode (see Table 37).
		- When exiting from Stop mode, the system clock, D3 domain bus matrix clocks and voltage scaling are reset.

### Standby

- Standby (System powered down)
	- based on CPU subsystem CStop mode. However the VCORE supply regulator is powered off.
	- The system exits from Standby mode when an external Reset (NRST pin), an IWDG Reset, a WKUP pin event, a RTC alarm, a tamper event, or a time stamp event is detected. All registers are reset after waking up from Standby except for power control and status registers (PWR control register 2 (PWR_CR2), PWR control register 3 (PWR_CR3)), SBF bit in PWR CPU control register (PWR_CPUCR), PWR wakeup flag register (PWR_WKUPFR), and PWR wakeup enable and polarity register (PWR_WKUPEPR).
	- ==After waking up from Standby mode, the program execution restarts in the same way as after a system reset (boot option sampling, boot vector reset fetched, etc.).== The SBF status flags in PWR CPU control register (PWR_CPUCR) registers indicate from which mode the system has exited (see Table 45).
	- In system Standby mode, the following features can be selected by programming individual control bits:
		- Independent watchdog (IWDG)
			- The IWDG is started by programming its Key register or by hardware option. Once started, it cannot be stopped except by a reset (see Section 45.3 in Section 45: Independent watchdog (IWDG).
		- Real-time clock (RTC)
			- This is configured via the RTCEN bit in the backup domain control register (RCC_BDCR).
		- Internal RC oscillator (LSI RC)
			- This is configured by the LSION bit in the Control/status register (RCC_CSR).
		- External 32.768 kHz oscillator (LSE OSC)
			- This is configured by the LSEON bit in the backup domain control register (RCC_BDCR).
	- In Standby mode, all I/O pins are high impedance without pull, except for:
		- Reset pad (still available)
		- RTC_AF1 pin if configured for tamper, time stamp, RTC Alarm out, or RTC clock calibration out
		- WKUP pins (if enabled). The WKUP pin pull configuration can be defined through WKUPPUPD register bits in PWR wakeup enable and polarity register (PWR_WKUPEPR).
	- Entry
		- The CPU subsystem is in CStop mode, and there is no active EXTI Wakeup source and RUN_D3 = 0.
		- All PDDS_Dn bits for all domains select Standby.
		- All WKUPF bits in Power Control/Status register (PWR_WKUPFR) are cleared.
	- Exit
		- WKUP pins rising or falling edge, RTC alarm (Alarm A and Alarm B), RTC wakeup, tamper event, time stamp event, external reset in NRST pin, IWDG reset.
		- The system exits from Standby mode when an external Reset (NRST pin), an IWDG Reset, a WKUP pin event, a RTC alarm, a tamper event, or a time stamp event is detected. All registers are reset after waking up from Standby except for power control and status registers (PWR control register 2 (PWR_CR2), PWR control register 3 (PWR_CR3)), SBF bit in PWR CPU control register (PWR_CPUCR), PWR wakeup flag register (PWR_WKUPFR), and PWR wakeup enable and polarity register (PWR_WKUPEPR).
		- After waking up from Standby mode, the program execution restarts in the same way as after a system reset (boot option sampling, boot vector reset fetched, etc.). The SBF status flags in PWR CPU control register (PWR_CPUCR) registers indicate from which mode the system has exited (see Table 45).

### Exiting Low-Power Modes

The CPU subsystem exits from CSleep mode through any interrupt or event depending on how the low-power mode was entered:
-   If the WFI instruction or Return from ISR was used to enter to low-power mode, any peripheral interrupt acknowledged by the NVIC can wake up the system.
-   If the WFE instruction is used to enter to low-power mode, the CPU exits from low- power mode as soon as an event occurs. The wakeup event can be generated either by:
	- An NVIC IRQ interrupt.
		- When SEVONPEND = 0 in the Cortex®-M7 System Control register, the interrupt must be enabled in the peripheral control register and in the NVIC.
		- When the MCU resumes from WFE, the peripheral interrupt pending bit and the NVIC peripheral IRQ channel pending bit in the NVIC interrupt clear pending register have to be cleared. Only NVIC interrupts with sufficient priority will wakeup and interrupt the MCU.
		- When SEVONPEND = 1 in the Cortex®-M7 System Control register, the interrupt must be enabled in the peripheral control register and optionally in the NVIC. When the MCU resumes from WFE, the peripheral interrupt pending bit and, when enabled, the NVIC peripheral IRQ channel pending bit (in the NVIC interrupt clear pending register) have to be cleared.
		- All NVIC interrupts will wakeup the MCU, even the disabled ones.
		- Only enabled NVIC interrupts with sufficient priority will wakeup and interrupt the MCU.
	- An event
		- An EXTI line must be configured in event mode. When the CPU resumes from WFE, it is not necessary to clear the EXTI peripheral interrupt pending bit or the NVIC IRQ channel pending bit as the pending bits corresponding to the event line is not set. It might be necessary to clear the interrupt flag in the peripheral.
- The CPU subsystem exits from CStop, DStop and Stop modes by enabling an EXTI interrupt or event depending on how the low-power mode was entered (see above).
- The system can wakeup from Stop mode by enabling an EXTI wakeup, without waking up a CPU subsystem. In this case the system will operate in D3 autonomous mode.
- The CPU subsystem exits from DStandby mode by enabling an EXTI interrupt or event, regardless on how DStandby mode was entered. Program execution restarts from CPU local reset (such as a reset vector fetched from System configuration block (SYSCFG).
- The D2 domain can exit from DStop or DStandby mode when the CPU allocates a first peripheral in the domain.
- The CPU subsystem exits from Standby mode by enabling an external reset (NRST pin), an IWDG reset, a rising edge on one of the enabled WKUPx pins or a RTC event. Program execution restarts in the same way as after a system reset (such as boot pin sampling, option bytes loading or reset vector fetched).

### Exiting Low Power Modes

The CPU subsystem exits from CSleep mode through any interrupt or event depending on how the low-power mode was entered:
-   If the WFI instruction or Return from ISR was used to enter to low-power mode, any peripheral interrupt acknowledged by the NVIC can wake up the system.
-   If the WFE instruction is used to enter to low-power mode, the CPU exits from low- power mode as soon as an event occurs. The wakeup event can be generated either by:
	- An NVIC IRQ interrupt.
		- When SEVONPEND = 0 in the Cortex®-M7 System Control register, the interrupt must be enabled in the peripheral control register and in the NVIC.
		- When the MCU resumes from WFE, the peripheral interrupt pending bit and the NVIC peripheral IRQ channel pending bit in the NVIC interrupt clear pending register have to be cleared. Only NVIC interrupts with sufficient priority will wakeup and interrupt the MCU.
		- When SEVONPEND = 1 in the Cortex®-M7 System Control register, the interrupt must be enabled in the peripheral control register and optionally in the NVIC. When the MCU resumes from WFE, the peripheral interrupt pending bit and, when enabled, the NVIC peripheral IRQ channel pending bit (in the NVIC interrupt clear pending register) have to be cleared.
		- All NVIC interrupts will wakeup the MCU, even the disabled ones.
		- Only enabled NVIC interrupts with sufficient priority will wakeup and interrupt the MCU.
	- An event
		- An EXTI line must be configured in event mode. When the CPU resumes from WFE, it is not necessary to clear the EXTI peripheral interrupt pending bit or the NVIC IRQ channel pending bit as the pending bits corresponding to the event line is not set. It might be necessary to clear the interrupt flag in the peripheral.
- The CPU subsystem exits from CStop, DStop and Stop modes by enabling an EXTI interrupt or event depending on how the low-power mode was entered (see above).
- The system can wakeup from Stop mode by enabling an EXTI wakeup, without waking up a CPU subsystem. In this case the system will operate in D3 autonomous mode.
- The CPU subsystem exits from DStandby mode by enabling an EXTI interrupt or event, regardless on how DStandby mode was entered. Program execution restarts from CPU local reset (such as a reset vector fetched from System configuration block (SYSCFG).
- The D2 domain can exit from DStop or DStandby mode when the CPU allocates a first peripheral in the domain.
- The CPU subsystem exits from Standby mode by enabling an external reset (NRST pin), an IWDG reset, a rising edge on one of the enabled WKUPx pins or a RTC event. Program execution restarts in the same way as after a system reset (such as boot pin sampling, option bytes loading or reset vector fetched).
