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_uart.h"
|
||||||
#include "stm32wbxx_hal_usart.h"
|
#include "stm32wbxx_hal_usart.h"
|
||||||
#include "stm32wbxx_ll_adc.h"
|
#include "stm32wbxx_ll_adc.h"
|
||||||
|
#include "stm32wbxx_ll_hsem.h"
|
||||||
#include "stm32wbxx_ll_lpuart.h"
|
#include "stm32wbxx_ll_lpuart.h"
|
||||||
#include "stm32wbxx_ll_rtc.h"
|
#include "stm32wbxx_ll_rtc.h"
|
||||||
#include "stm32wbxx_ll_usart.h"
|
#include "stm32wbxx_ll_usart.h"
|
||||||
|
@ -79,4 +80,41 @@
|
||||||
// HAL parameter assertions are disabled
|
// HAL parameter assertions are disabled
|
||||||
#define assert_param(expr) ((void)0)
|
#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
|
#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;
|
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
|
||||||
|
|
||||||
#endif // !defined(STM32F0) && !defined(STM32L0) && !defined(STM32L4)
|
#endif // !defined(STM32F0) && !defined(STM32L0) && !defined(STM32L4)
|
||||||
|
@ -729,6 +781,10 @@ void powerctrl_enter_stop_mode(void) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(STM32WB)
|
||||||
|
powerctrl_low_power_prep_wb55();
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(STM32F7)
|
#if defined(STM32F7)
|
||||||
HAL_PWR_EnterSTOPMode((PWR_CR1_LPDS | PWR_CR1_LPUDS | PWR_CR1_FPDS | PWR_CR1_UDEN), PWR_STOPENTRY_WFI);
|
HAL_PWR_EnterSTOPMode((PWR_CR1_LPDS | PWR_CR1_LPUDS | PWR_CR1_FPDS | PWR_CR1_UDEN), PWR_STOPENTRY_WFI);
|
||||||
#else
|
#else
|
||||||
|
@ -762,6 +818,10 @@ void powerctrl_enter_stop_mode(void) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(STM32WB)
|
||||||
|
powerctrl_low_power_exit_wb55();
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(STM32L4)
|
#if !defined(STM32L4)
|
||||||
// enable clock
|
// enable clock
|
||||||
__HAL_RCC_HSE_CONFIG(MICROPY_HW_RCC_HSE_STATE);
|
__HAL_RCC_HSE_CONFIG(MICROPY_HW_RCC_HSE_STATE);
|
||||||
|
@ -977,6 +1037,10 @@ void powerctrl_enter_standby_mode(void) {
|
||||||
DBGMCU->CR = 0;
|
DBGMCU->CR = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(STM32WB)
|
||||||
|
powerctrl_low_power_prep_wb55();
|
||||||
|
#endif
|
||||||
|
|
||||||
// enter standby mode
|
// enter standby mode
|
||||||
HAL_PWR_EnterSTANDBYMode();
|
HAL_PWR_EnterSTANDBYMode();
|
||||||
// we never return; MCU is reset on exit from standby
|
// we never return; MCU is reset on exit from standby
|
||||||
|
|
|
@ -298,21 +298,20 @@ void SystemClock_Config(void) {
|
||||||
}
|
}
|
||||||
#elif defined(STM32WB)
|
#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) {
|
void SystemClock_Config(void) {
|
||||||
|
while (LL_HSEM_1StepLock(HSEM, CFG_HW_RCC_SEMID)) {
|
||||||
|
}
|
||||||
|
|
||||||
// Enable the 32MHz external oscillator
|
// Enable the 32MHz external oscillator
|
||||||
RCC->CR |= RCC_CR_HSEON;
|
RCC->CR |= RCC_CR_HSEON;
|
||||||
while (!(RCC->CR & RCC_CR_HSERDY)) {
|
while (!(RCC->CR & RCC_CR_HSERDY)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent CPU2 from disabling CLK48.
|
// 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
|
// Use HSE and the PLL to get a 64MHz SYSCLK
|
||||||
|
@ -349,6 +348,9 @@ void SystemClock_Config(void) {
|
||||||
|
|
||||||
SystemCoreClockUpdate();
|
SystemCoreClockUpdate();
|
||||||
powerctrl_config_systick();
|
powerctrl_config_systick();
|
||||||
|
|
||||||
|
// Release RCC semaphore
|
||||||
|
LL_HSEM_ReleaseLock(HSEM, CFG_HW_RCC_SEMID, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(STM32WL)
|
#elif defined(STM32WL)
|
||||||
|
|
|
@ -534,12 +534,23 @@ void rfcore_init(void) {
|
||||||
// Ensure LSE is running
|
// Ensure LSE is running
|
||||||
rtc_init_finalise();
|
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
|
// Select LSE as RF wakeup source
|
||||||
RCC->CSR = (RCC->CSR & ~RCC_CSR_RFWKPSEL) | 1 << RCC_CSR_RFWKPSEL_Pos;
|
RCC->CSR = (RCC->CSR & ~RCC_CSR_RFWKPSEL) | 1 << RCC_CSR_RFWKPSEL_Pos;
|
||||||
|
|
||||||
// Initialise IPCC and shared memory structures
|
// Initialise IPCC and shared memory structures
|
||||||
ipcc_init(IRQ_PRI_SDIO);
|
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
|
// Boot the second core
|
||||||
__SEV();
|
__SEV();
|
||||||
__WFE();
|
__WFE();
|
||||||
|
|
Loading…
Reference in New Issue