summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/stm32/boards/stm32wbxx_hal_conf_base.h38
-rw-r--r--ports/stm32/powerctrl.c64
-rw-r--r--ports/stm32/powerctrlboot.c18
-rw-r--r--ports/stm32/rfcore.c11
4 files changed, 123 insertions, 8 deletions
diff --git a/ports/stm32/boards/stm32wbxx_hal_conf_base.h b/ports/stm32/boards/stm32wbxx_hal_conf_base.h
index b03ad2686..25eb4b93e 100644
--- a/ports/stm32/boards/stm32wbxx_hal_conf_base.h
+++ b/ports/stm32/boards/stm32wbxx_hal_conf_base.h
@@ -42,6 +42,7 @@
#include "stm32wbxx_hal_uart.h"
#include "stm32wbxx_hal_usart.h"
#include "stm32wbxx_ll_adc.h"
+#include "stm32wbxx_ll_hsem.h"
#include "stm32wbxx_ll_lpuart.h"
#include "stm32wbxx_ll_rtc.h"
#include "stm32wbxx_ll_usart.h"
@@ -79,4 +80,41 @@
// HAL parameter assertions are disabled
#define assert_param(expr) ((void)0)
+// Hardware Semaphores - ref: AN5289
+
+// Used to prevent conflicts after standby / sleep.
+// Each CPUs takes this semaphore at standby wakeup until conflicting elements are restored.
+// Note: this is used in WB55 reference examples, but not listed in AN5289 Rev 6
+#define CFG_HW_PWR_STANDBY_SEMID 10
+
+// Ensures that CPU2 does not update the BLE persistent data in SRAM2 when CPU1 is reading them
+#define CFG_HW_THREAD_NVM_SRAM_SEMID 9
+
+// Ensures that CPU2 does not update the Thread persistent data in SRAM2 when CPU1 is reading them
+#define CFG_HW_BLE_NVM_SRAM_SEMID 8
+
+// Used by CPU2 to prevent CPU1 from writing/erasing data in Flash memory
+#define CFG_HW_BLOCK_FLASH_REQ_BY_CPU2_SEMID 7
+
+// Used by CPU1 to prevent CPU2 from writing/erasing data in Flash memory
+#define CFG_HW_BLOCK_FLASH_REQ_BY_CPU1_SEMID 6
+
+// Used to manage the CLK48 clock configuration (RCC_CRRCR, RCC_CCIPR)
+#define CFG_HW_CLK48_CONFIG_SEMID 5
+
+// Used to manage the entry Stop Mode procedure
+#define CFG_HW_ENTRY_STOP_MODE_SEMID 4
+
+// Used to access the RCC (RCC_CR, RCC_EXTCFGR, RCC_CFGR, RCC_SMPSCR)
+#define CFG_HW_RCC_SEMID 3
+
+// Used to access the FLASH (all registers)
+#define CFG_HW_FLASH_SEMID 2
+
+// Used to access the PKA (all registers)
+#define CFG_HW_PKA_SEMID 1
+
+// Used to access the RNG (all registers)
+#define CFG_HW_RNG_SEMID 0
+
#endif // MICROPY_INCLUDED_STM32WBXX_HAL_CONF_BASE_H
diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c
index 2f5e78f34..3439b0d1f 100644
--- a/ports/stm32/powerctrl.c
+++ b/ports/stm32/powerctrl.c
@@ -676,6 +676,58 @@ int powerctrl_set_sysclk(uint32_t sysclk, uint32_t ahb, uint32_t apb1, uint32_t
return 0;
}
+static void powerctrl_switch_on_HSI(void) {
+ LL_RCC_HSI_Enable();
+ while (!LL_RCC_HSI_IsReady()) {
+ }
+ LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI);
+ LL_RCC_SetSMPSClockSource(LL_RCC_SMPS_CLKSOURCE_HSI);
+ while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI) {
+ }
+ return;
+}
+
+static void powerctrl_low_power_prep_wb55() {
+ // See WB55 specific documentation in AN5289 Rev 6, and in particular, Figure 6.
+ while (LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID)) {
+ }
+ if (!LL_HSEM_1StepLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID)) {
+ if (LL_PWR_IsActiveFlag_C2DS() || LL_PWR_IsActiveFlag_C2SB()) {
+ // Release ENTRY_STOP_MODE semaphore
+ LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0);
+
+ powerctrl_switch_on_HSI();
+ }
+ } else {
+ powerctrl_switch_on_HSI();
+ }
+ // Release RCC semaphore
+ LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0);
+}
+
+static void powerctrl_low_power_exit_wb55() {
+ // Ensure the HSE/HSI clock configuration is correct so core2 can wake properly again.
+ // See WB55 specific documentation in AN5289 Rev 6, and in particular, Figure 7.
+ LL_HSEM_ReleaseLock(HSEM, CFG_HW_ENTRY_STOP_MODE_SEMID, 0);
+ // Acquire RCC semaphore before adjusting clocks.
+ while (LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID)) {
+ }
+
+ if (LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_HSI) {
+ // Restore the clock configuration of the application
+ LL_RCC_HSE_Enable();
+ __HAL_FLASH_SET_LATENCY(FLASH_LATENCY_1);
+ while (!LL_RCC_HSE_IsReady()) {
+ }
+ LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSE);
+ while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSE) {
+ }
+ }
+
+ // Release RCC semaphore
+ LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0);
+}
+
#endif
#endif // !defined(STM32F0) && !defined(STM32L0) && !defined(STM32L4)
@@ -729,6 +781,10 @@ void powerctrl_enter_stop_mode(void) {
}
#endif
+ #if defined(STM32WB)
+ powerctrl_low_power_prep_wb55();
+ #endif
+
#if defined(STM32F7)
HAL_PWR_EnterSTOPMode((PWR_CR1_LPDS | PWR_CR1_LPUDS | PWR_CR1_FPDS | PWR_CR1_UDEN), PWR_STOPENTRY_WFI);
#else
@@ -762,6 +818,10 @@ void powerctrl_enter_stop_mode(void) {
}
#endif
+ #if defined(STM32WB)
+ powerctrl_low_power_exit_wb55();
+ #endif
+
#if !defined(STM32L4)
// enable clock
__HAL_RCC_HSE_CONFIG(MICROPY_HW_RCC_HSE_STATE);
@@ -977,6 +1037,10 @@ void powerctrl_enter_standby_mode(void) {
DBGMCU->CR = 0;
#endif
+ #if defined(STM32WB)
+ powerctrl_low_power_prep_wb55();
+ #endif
+
// enter standby mode
HAL_PWR_EnterSTANDBYMode();
// we never return; MCU is reset on exit from standby
diff --git a/ports/stm32/powerctrlboot.c b/ports/stm32/powerctrlboot.c
index 61d48ffe5..b78fcae4b 100644
--- a/ports/stm32/powerctrlboot.c
+++ b/ports/stm32/powerctrlboot.c
@@ -298,21 +298,20 @@ void SystemClock_Config(void) {
}
#elif defined(STM32WB)
-#include "stm32wbxx_ll_hsem.h"
-
-// This semaphore protected access to the CLK48 configuration.
-// CPU1 should hold this semaphore while the USB peripheral is in use.
-// See AN5289 and https://github.com/micropython/micropython/issues/6316.
-#define CLK48_SEMID (5)
-
void SystemClock_Config(void) {
+ while (LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID)) {
+ }
+
// Enable the 32MHz external oscillator
RCC->CR |= RCC_CR_HSEON;
while (!(RCC->CR & RCC_CR_HSERDY)) {
}
// Prevent CPU2 from disabling CLK48.
- while (LL_HSEM_1StepLock(HSEM, CLK48_SEMID)) {
+ // This semaphore protected access to the CLK48 configuration.
+ // CPU1 should hold this semaphore while the USB peripheral is in use.
+ // See AN5289 and https://github.com/micropython/micropython/issues/6316.
+ while (LL_HSEM_1StepLock(HSEM, CFG_HW_CLK48_CONFIG_SEMID)) {
}
// Use HSE and the PLL to get a 64MHz SYSCLK
@@ -349,6 +348,9 @@ void SystemClock_Config(void) {
SystemCoreClockUpdate();
powerctrl_config_systick();
+
+ // Release RCC semaphore
+ LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0);
}
#elif defined(STM32WL)
diff --git a/ports/stm32/rfcore.c b/ports/stm32/rfcore.c
index 55d6d17ad..20b2c5a7e 100644
--- a/ports/stm32/rfcore.c
+++ b/ports/stm32/rfcore.c
@@ -534,12 +534,23 @@ void rfcore_init(void) {
// Ensure LSE is running
rtc_init_finalise();
+ // In case we're waking from deepsleep, enforce core synchronisation
+ __HAL_RCC_HSEM_CLK_ENABLE();
+ while (LL_HSEM_1StepLock(HSEM, CFG_HW_PWR_STANDBY_SEMID)) {
+ }
+
// Select LSE as RF wakeup source
RCC->CSR = (RCC->CSR & ~RCC_CSR_RFWKPSEL) | 1 << RCC_CSR_RFWKPSEL_Pos;
// Initialise IPCC and shared memory structures
ipcc_init(IRQ_PRI_SDIO);
+ // When the device is out of standby, it is required to use the EXTI mechanism to wakeup CPU2
+ LL_C2_EXTI_EnableEvent_32_63(LL_EXTI_LINE_41);
+ LL_EXTI_EnableRisingTrig_32_63(LL_EXTI_LINE_41);
+
+ LL_HSEM_ReleaseLock(HSEM, CFG_HW_PWR_STANDBY_SEMID, 0);
+
// Boot the second core
__SEV();
__WFE();