Skip to content

Commit 2eca86e

Browse files
pi-anldpgeorge
authored andcommitted
stm32/powerctrl: Add sleep RCC semaphore management for WB55 MCUs.
Signed-off-by: Andrew Leech <[email protected]>
1 parent 2ec101e commit 2eca86e

File tree

4 files changed

+123
-8
lines changed

4 files changed

+123
-8
lines changed

ports/stm32/boards/stm32wbxx_hal_conf_base.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "stm32wbxx_hal_uart.h"
4343
#include "stm32wbxx_hal_usart.h"
4444
#include "stm32wbxx_ll_adc.h"
45+
#include "stm32wbxx_ll_hsem.h"
4546
#include "stm32wbxx_ll_lpuart.h"
4647
#include "stm32wbxx_ll_rtc.h"
4748
#include "stm32wbxx_ll_usart.h"
@@ -79,4 +80,41 @@
7980
// HAL parameter assertions are disabled
8081
#define assert_param(expr) ((void)0)
8182

83+
// Hardware Semaphores - ref: AN5289
84+
85+
// Used to prevent conflicts after standby / sleep.
86+
// Each CPUs takes this semaphore at standby wakeup until conflicting elements are restored.
87+
// Note: this is used in WB55 reference examples, but not listed in AN5289 Rev 6
88+
#define CFG_HW_PWR_STANDBY_SEMID 10
89+
90+
// Ensures that CPU2 does not update the BLE persistent data in SRAM2 when CPU1 is reading them
91+
#define CFG_HW_THREAD_NVM_SRAM_SEMID 9
92+
93+
// Ensures that CPU2 does not update the Thread persistent data in SRAM2 when CPU1 is reading them
94+
#define CFG_HW_BLE_NVM_SRAM_SEMID 8
95+
96+
// Used by CPU2 to prevent CPU1 from writing/erasing data in Flash memory
97+
#define CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID 7
98+
99+
// Used by CPU1 to prevent CPU2 from writing/erasing data in Flash memory
100+
#define CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID 6
101+
102+
// Used to manage the CLK48 clock configuration (RCC_CRRCR, RCC_CCIPR)
103+
#define CFG_HW_CLK48_CONFIG_SEMID 5
104+
105+
// Used to manage the entry Stop Mode procedure
106+
#define CFG_HW_ENTRY_STOP_MODE_SEMID 4
107+
108+
// Used to access the RCC (RCC_CR, RCC_EXTCFGR, RCC_CFGR, RCC_SMPSCR)
109+
#define CFG_HW_RCC_SEMID 3
110+
111+
// Used to access the FLASH (all registers)
112+
#define CFG_HW_FLASH_SEMID 2
113+
114+
// Used to access the PKA (all registers)
115+
#define CFG_HW_PKA_SEMID 1
116+
117+
// Used to access the RNG (all registers)
118+
#define CFG_HW_RNG_SEMID 0
119+
82120
#endif // MICROPY_INCLUDED_STM32WBXX_HAL_CONF_BASE_H

ports/stm32/powerctrl.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,58 @@ int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t
676676
return 0;
677677
}
678678

679+
static void powerctrl_switch_on_HSI(void) {
680+
LL_RCC_HSI_Enable();
681+
while (!LL_RCC_HSI_IsReady()) {
682+
}
683+
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI);
684+
LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSI);
685+
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI) {
686+
}
687+
return;
688+
}
689+
690+
static void powerctrl_low_power_prep_wb55() {
691+
// See WB55 specific documentation in AN5289 Rev 6, and in particular, Figure 6.
692+
while (LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID)) {
693+
}
694+
if (!LL_HSEM_1StepLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID)) {
695+
if (LL_PWR_IsActiveFlag_C2DS() || LL_PWR_IsActiveFlag_C2SB()) {
696+
// Release ENTRY_STOP_MODE semaphore
697+
LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0);
698+
699+
powerctrl_switch_on_HSI();
700+
}
701+
} else {
702+
powerctrl_switch_on_HSI();
703+
}
704+
// Release RCC semaphore
705+
LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0);
706+
}
707+
708+
static void powerctrl_low_power_exit_wb55() {
709+
// Ensure the HSE/HSI clock configuration is correct so core2 can wake properly again.
710+
// See WB55 specific documentation in AN5289 Rev 6, and in particular, Figure 7.
711+
LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0);
712+
// Acquire RCC semaphore before adjusting clocks.
713+
while (LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID)) {
714+
}
715+
716+
if (LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_HSI) {
717+
// Restore the clock configuration of the application
718+
LL_RCC_HSE_Enable();
719+
__HAL_FLASH_SET_LATENCY(FLASH_LATENCY_1);
720+
while (!LL_RCC_HSE_IsReady()) {
721+
}
722+
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
723+
while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE) {
724+
}
725+
}
726+
727+
// Release RCC semaphore
728+
LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0);
729+
}
730+
679731
#endif
680732

681733
#endif // !defined(STM32F0) && !defined(STM32L0) && !defined(STM32L4)
@@ -729,6 +781,10 @@ void powerctrl_enter_stop_mode(void) {
729781
}
730782
#endif
731783

784+
#if defined(STM32WB)
785+
powerctrl_low_power_prep_wb55();
786+
#endif
787+
732788
#if defined(STM32F7)
733789
HAL_PWR_EnterSTOPMode((PWR_CR1_LPDS | PWR_CR1_LPUDS | PWR_CR1_FPDS | PWR_CR1_UDEN), PWR_STOPENTRY_WFI);
734790
#else
@@ -762,6 +818,10 @@ void powerctrl_enter_stop_mode(void) {
762818
}
763819
#endif
764820

821+
#if defined(STM32WB)
822+
powerctrl_low_power_exit_wb55();
823+
#endif
824+
765825
#if !defined(STM32L4)
766826
// enable clock
767827
__HAL_RCC_HSE_CONFIG(MICROPY_HW_RCC_HSE_STATE);
@@ -977,6 +1037,10 @@ void powerctrl_enter_standby_mode(void) {
9771037
DBGMCU->CR = 0;
9781038
#endif
9791039

1040+
#if defined(STM32WB)
1041+
powerctrl_low_power_prep_wb55();
1042+
#endif
1043+
9801044
// enter standby mode
9811045
HAL_PWR_EnterSTANDBYMode();
9821046
// we never return; MCU is reset on exit from standby

ports/stm32/powerctrlboot.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -298,21 +298,20 @@ void SystemClock_Config(void) {
298298
}
299299
#elif defined(STM32WB)
300300

301-
#include "stm32wbxx_ll_hsem.h"
302-
303-
// This semaphore protected access to the CLK48 configuration.
304-
// CPU1 should hold this semaphore while the USB peripheral is in use.
305-
// See AN5289 and https://github.com/micropython/micropython/issues/6316.
306-
#define CLK48_SEMID (5)
307-
308301
void SystemClock_Config(void) {
302+
while (LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID)) {
303+
}
304+
309305
// Enable the 32MHz external oscillator
310306
RCC->CR |= RCC_CR_HSEON;
311307
while (!(RCC->CR & RCC_CR_HSERDY)) {
312308
}
313309

314310
// Prevent CPU2 from disabling CLK48.
315-
while (LL_HSEM_1StepLock(HSEM, CLK48_SEMID)) {
311+
// This semaphore protected access to the CLK48 configuration.
312+
// CPU1 should hold this semaphore while the USB peripheral is in use.
313+
// See AN5289 and https://github.com/micropython/micropython/issues/6316.
314+
while (LL_HSEM_1StepLock(HSEM, CFG_HW_CLK48_CONFIG_SEMID)) {
316315
}
317316

318317
// Use HSE and the PLL to get a 64MHz SYSCLK
@@ -349,6 +348,9 @@ void SystemClock_Config(void) {
349348

350349
SystemCoreClockUpdate();
351350
powerctrl_config_systick();
351+
352+
// Release RCC semaphore
353+
LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0);
352354
}
353355

354356
#elif defined(STM32WL)

ports/stm32/rfcore.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,12 +534,23 @@ void rfcore_init(void) {
534534
// Ensure LSE is running
535535
rtc_init_finalise();
536536

537+
// In case we're waking from deepsleep, enforce core synchronisation
538+
__HAL_RCC_HSEM_CLK_ENABLE();
539+
while (LL_HSEM_1StepLock(HSEM, CFG_HW_PWR_STANDBY_SEMID)) {
540+
}
541+
537542
// Select LSE as RF wakeup source
538543
RCC->CSR = (RCC->CSR & ~RCC_CSR_RFWKPSEL) | 1 << RCC_CSR_RFWKPSEL_Pos;
539544

540545
// Initialise IPCC and shared memory structures
541546
ipcc_init(IRQ_PRI_SDIO);
542547

548+
// When the device is out of standby, it is required to use the EXTI mechanism to wakeup CPU2
549+
LL_C2_EXTI_EnableEvent_32_63(LL_EXTI_LINE_41);
550+
LL_EXTI_EnableRisingTrig_32_63(LL_EXTI_LINE_41);
551+
552+
LL_HSEM_ReleaseLock(HSEM, CFG_HW_PWR_STANDBY_SEMID, 0);
553+
543554
// Boot the second core
544555
__SEV();
545556
__WFE();

0 commit comments

Comments
 (0)