stm32/powerctrl: Add sleep RCC semaphore management for WB55 MCUs.
Signed-off-by: Andrew Leech <andrew.leech@planetinnovation.com.au>
This commit is contained in:
parent
2ec101e609
commit
2eca86e8fa
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue