Skip to content

Commit f0b8d94

Browse files
mathieuchopstmnashif
authored andcommitted
soc: st: stm32: move POWEROFF entry sequence to common code
Move the architecture-specific (but implementation dependent!) code which performs entry in poweroff state (Shutdown/Standby without retention) to a common implementation shared by all STM32 SoC series. This is a first step and could be further refined at a later time; eventually, a unified z_sys_poweroff() implementation may even be possible. Signed-off-by: Mathieu Choplain <[email protected]>
1 parent 830bc4f commit f0b8d94

File tree

12 files changed

+118
-47
lines changed

12 files changed

+118
-47
lines changed

soc/st/stm32/common/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,6 @@ in STOP modes due to internal oscillators that remain active.")
3535
endif()
3636

3737
zephyr_sources_ifdef(CONFIG_DCACHE stm32_cache.c)
38+
zephyr_sources_ifdef(CONFIG_POWEROFF poweroff_common.c)
3839

3940
zephyr_sources_ifdef(CONFIG_STM32_BACKUP_PROTECTION stm32_backup_domain.c)
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright (c) 2025 STMicroelectronics
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#include <zephyr/kernel.h>
7+
#include <zephyr/toolchain.h>
8+
9+
#include <cmsis_core.h>
10+
11+
FUNC_NORETURN void stm32_enter_poweroff(void)
12+
{
13+
/* Disable interrupts */
14+
__disable_irq();
15+
16+
/* Enable SoC-specific low-power state */
17+
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
18+
19+
/* Make sure IRQs don't set the Event Register */
20+
SCB->SCR &= ~SCB_SCR_SEVONPEND_Msk;
21+
22+
/*
23+
* Trigger entry in low-power mode.
24+
*
25+
* Note that "sys_poweroff()" should only be called when
26+
* the system is in "a safe state", but we still make an
27+
* effort here to ensure entry low-power state suceeds
28+
* even if the system is still somewhat active...
29+
*
30+
* According to the ARM Architecture Reference Manual,
31+
* "[WFI is] the only architectually-defined mechanism
32+
* that completely suspends execution", but WFE is also
33+
* described as being able to suspend execution and make
34+
* the CPU enter in low-power state! In practice, both
35+
* instructions seem to trigger entry in low-power state.
36+
*
37+
* WFE can "guarantee" entry in low-power state despite
38+
* pending or incoming interrupts, but spurious Events
39+
* (as in "WFE wake-up event") turn it into a no-op; on
40+
* the other hand, WFI does ignore Events but not already
41+
* pending interrupts. Since spurious interrupts have a
42+
* higher chance of occurring, we try with WFE first then
43+
* fall back to WFI.
44+
*
45+
* The sequence is restarted forever; since this function
46+
* must never return anyways, it doesn't really matter.
47+
*/
48+
49+
while (1) {
50+
/* Clear the Event Register */
51+
__SEV();
52+
__WFE();
53+
54+
/*
55+
* Attempt entry in low-power state using WFE.
56+
*
57+
* This ought to always succeed because SEVONPEND=0,
58+
* interrupts are masked and we just cleared the Event
59+
* Register, but who knows...
60+
*
61+
* It can take up to two cycles for the processor
62+
* to actually turn off - NOPs are recommended here.
63+
*/
64+
__WFE();
65+
__NOP();
66+
__NOP();
67+
68+
/* WFE failed - try WFI instead */
69+
__WFI();
70+
__NOP();
71+
__NOP();
72+
73+
/* Neither worked... try again */
74+
}
75+
76+
CODE_UNREACHABLE;
77+
}

soc/st/stm32/common/stm32_common.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright (c) 2025 STMicroelectronics
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/kernel.h>
8+
#include <zephyr/toolchain.h>
9+
10+
/**
11+
* @brief Performs the entry-in-poweroff sequence.
12+
*
13+
* This function is reserved for internal usage by
14+
* the SoC-specific z_sys_poweroff() implementations.
15+
*
16+
* It merely performs the architectural low-power entry
17+
* sequence: the caller must configure the PWR registers
18+
* with the proper low-power mode, clear all wake-up flags
19+
* and possibly other operations (disable RAM retention,
20+
* turn off DBGMCU, ...) before calling this function.
21+
*/
22+
FUNC_NORETURN void stm32_enter_poweroff(void);

soc/st/stm32/stm32c0x/poweroff.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include <zephyr/toolchain.h>
1111
#include <zephyr/drivers/misc/stm32_wkup_pins/stm32_wkup_pins.h>
1212

13-
#include <stm32_ll_cortex.h>
13+
#include <stm32_common.h>
1414
#include <stm32_ll_pwr.h>
1515
#include <stm32_ll_system.h>
1616

@@ -23,10 +23,7 @@ void z_sys_poweroff(void)
2323
LL_PWR_ClearFlag_WU();
2424

2525
LL_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
26-
LL_LPM_EnableDeepSleep();
2726
LL_DBGMCU_DisableDBGStandbyMode();
2827

29-
k_cpu_idle();
30-
31-
CODE_UNREACHABLE;
28+
stm32_enter_poweroff();
3229
}

soc/st/stm32/stm32f1x/poweroff.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

7-
#include <stm32_ll_cortex.h>
7+
#include <stm32_common.h>
88
#include <stm32_ll_pwr.h>
99

1010
#include <zephyr/kernel.h>
@@ -15,11 +15,7 @@ void z_sys_poweroff(void)
1515
LL_PWR_ClearFlag_SB();
1616
LL_PWR_ClearFlag_WU();
1717

18-
LL_LPM_DisableEventOnPend();
1918
LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY);
20-
LL_LPM_EnableDeepSleep();
2119

22-
k_cpu_idle();
23-
24-
CODE_UNREACHABLE;
20+
stm32_enter_poweroff();
2521
}

soc/st/stm32/stm32f4x/poweroff.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,14 @@
1111
#include <zephyr/toolchain.h>
1212
#include <zephyr/drivers/misc/stm32_wkup_pins/stm32_wkup_pins.h>
1313

14-
#include <stm32_ll_cortex.h>
14+
#include <stm32_common.h>
1515
#include <stm32_ll_pwr.h>
1616

1717
void z_sys_poweroff(void)
1818
{
1919
LL_PWR_ClearFlag_WU();
2020

2121
LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY);
22-
LL_LPM_EnableDeepSleep();
2322

24-
k_cpu_idle();
25-
26-
CODE_UNREACHABLE;
23+
stm32_enter_poweroff();
2724
}

soc/st/stm32/stm32g0x/poweroff.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#include <zephyr/toolchain.h>
1212
#include <zephyr/drivers/misc/stm32_wkup_pins/stm32_wkup_pins.h>
1313

14-
#include <stm32_ll_cortex.h>
14+
#include <stm32_common.h>
1515
#include <stm32_ll_pwr.h>
1616
#include <stm32_ll_system.h>
1717

@@ -28,10 +28,7 @@ void z_sys_poweroff(void)
2828
#else
2929
LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY);
3030
#endif
31-
LL_LPM_EnableDeepSleep();
3231
LL_DBGMCU_DisableDBGStandbyMode();
3332

34-
k_cpu_idle();
35-
36-
CODE_UNREACHABLE;
33+
stm32_enter_poweroff();
3734
}

soc/st/stm32/stm32l4x/poweroff.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include <zephyr/toolchain.h>
1111
#include <zephyr/drivers/misc/stm32_wkup_pins/stm32_wkup_pins.h>
1212

13-
#include <stm32_ll_cortex.h>
13+
#include <stm32_common.h>
1414
#include <stm32_ll_pwr.h>
1515
#include <stm32_ll_system.h>
1616

@@ -23,10 +23,7 @@ void z_sys_poweroff(void)
2323
LL_PWR_ClearFlag_WU();
2424

2525
LL_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
26-
LL_LPM_EnableDeepSleep();
2726
LL_DBGMCU_DisableDBGStandbyMode();
2827

29-
k_cpu_idle();
30-
31-
CODE_UNREACHABLE;
28+
stm32_enter_poweroff();
3229
}

soc/st/stm32/stm32u5x/poweroff.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#include <zephyr/toolchain.h>
1111
#include <zephyr/drivers/misc/stm32_wkup_pins/stm32_wkup_pins.h>
1212

13-
#include <stm32_ll_cortex.h>
13+
#include <stm32_common.h>
1414
#include <stm32_ll_pwr.h>
1515

1616
void z_sys_poweroff(void)
@@ -20,11 +20,7 @@ void z_sys_poweroff(void)
2020
#endif /* CONFIG_STM32_WKUP_PINS */
2121

2222
LL_PWR_ClearFlag_WU();
23-
2423
LL_PWR_SetPowerMode(LL_PWR_SHUTDOWN_MODE);
25-
LL_LPM_EnableDeepSleep();
26-
27-
k_cpu_idle();
2824

29-
CODE_UNREACHABLE;
25+
stm32_enter_poweroff();
3026
}

soc/st/stm32/stm32wbax/poweroff.c

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include <zephyr/toolchain.h>
1010
#include <zephyr/drivers/misc/stm32_wkup_pins/stm32_wkup_pins.h>
1111

12-
#include <stm32_ll_cortex.h>
12+
#include <stm32_common.h>
1313
#include <stm32_ll_pwr.h>
1414

1515
void z_sys_poweroff(void)
@@ -24,9 +24,6 @@ void z_sys_poweroff(void)
2424
LL_PWR_SetRadioSBRetention(LL_PWR_RADIO_SB_NO_RETENTION);
2525
LL_PWR_SetSRAM1SBRetention(LL_PWR_SRAM1_SB_NO_RETENTION);
2626
LL_PWR_SetSRAM2SBRetention(LL_PWR_SRAM2_SB_NO_RETENTION);
27-
LL_LPM_EnableDeepSleep();
2827

29-
__WFI();
30-
31-
CODE_UNREACHABLE;
28+
stm32_enter_poweroff();
3229
}

0 commit comments

Comments
 (0)