From 47ea831c0e741722a9e7a94bb453947cff5f66d8 Mon Sep 17 00:00:00 2001 From: Rene Straub Date: Sat, 21 Oct 2023 15:03:53 +0200 Subject: [PATCH] stm32: Add STM32H5 support for sleep mode. Update rtc, machine and powerctrl drivers to support STM32H5 sleep modes. This makes RTC alarm wakeup working from lightsleep() and deepsleep(). Changes: - Determine start reason for machine.reset_cause() in modmachine.c. - Add proper interrupt clear code in rtc.c. - Add wakeup functionality in powerctrl_enter_stop_mode(). Remember and restore voltage scaling level. Restart HSI48 if it was on before entering sleep mode. - Clear DBGMCU_CR in SystemClock_Config() as for other variants. Otherwise debug flags prevent entering sleep mode. Implementation Notes: - rtc.c: EXTI_RTSTR1 bits are not present for H5. Code sequence from G0/G4/L4/WB/WL would be invalid. RTSTR is only defined for external (GPIO) interrupts. Maybe this is also true for other STM32 variants. - powerctrl_enter_stop_mode() uses complicated, nested conditionals to select STM32 variants. To make code slightly better readable, comment have been added. A non-nested, #if/#elif sequence would make the code more readable. I leave this to the original authors. Signed-off-by: Rene Straub --- ports/stm32/modmachine.c | 6 ++++++ ports/stm32/powerctrl.c | 27 +++++++++++++++++++++++---- ports/stm32/powerctrlboot.c | 4 ++++ ports/stm32/rtc.c | 8 ++++++-- 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/ports/stm32/modmachine.c b/ports/stm32/modmachine.c index 83327bede0..67fcffb0f1 100644 --- a/ports/stm32/modmachine.c +++ b/ports/stm32/modmachine.c @@ -108,6 +108,12 @@ void machine_init(void) { reset_cause = PYB_RESET_DEEPSLEEP; PWR->CR1 |= PWR_CR1_CSBF; } else + #elif defined(STM32H5) + if (PWR->PMSR & PWR_PMSR_STOPF || PWR->PMSR & PWR_PMSR_SBF) { + // came out of standby or stop mode + reset_cause = PYB_RESET_DEEPSLEEP; + PWR->PMCR |= PWR_PMCR_CSSF; + } else #elif defined(STM32H7) if (PWR->CPUCR & PWR_CPUCR_SBF || PWR->CPUCR & PWR_CPUCR_STOPF) { // came out of standby or stop mode diff --git a/ports/stm32/powerctrl.c b/ports/stm32/powerctrl.c index 03224f4d8b..1bb66c9781 100644 --- a/ports/stm32/powerctrl.c +++ b/ports/stm32/powerctrl.c @@ -48,6 +48,8 @@ #define POWERCTRL_GET_VOLTAGE_SCALING() PWR_REGULATOR_VOLTAGE_SCALE0 #elif defined(STM32H723xx) #define POWERCTRL_GET_VOLTAGE_SCALING() LL_PWR_GetRegulVoltageScaling() +#elif defined(STM32H5) +#define POWERCTRL_GET_VOLTAGE_SCALING() LL_PWR_GetRegulVoltageScaling() #else #define POWERCTRL_GET_VOLTAGE_SCALING() \ (((PWR->CSR1 & PWR_CSR1_ACTVOS) && (SYSCFG->PWRCR & SYSCFG_PWRCR_ODEN)) ? \ @@ -797,6 +799,14 @@ void powerctrl_enter_stop_mode(void) { HAL_PWREx_EnableFlashPowerDown(); #endif + #if defined(STM32H5) + // Save RCC CR to re-enable OSCs and PLLs after wake up from low power mode. + uint32_t rcc_cr = RCC->CR; + + // Save the current voltage scaling level to restore after exiting low power mode. + uint32_t vscaling = POWERCTRL_GET_VOLTAGE_SCALING(); + #endif + #if defined(STM32H7) // Save RCC CR to re-enable OSCs and PLLs after wake up from low power mode. uint32_t rcc_cr = RCC->CR; @@ -837,9 +847,9 @@ void powerctrl_enter_stop_mode(void) { while (__HAL_RCC_GET_SYSCLK_SOURCE() != RCC_CFGR_SWS_HSI48) { } - #else + #else // defined(STM32F0) - #if defined(STM32H7) + #if defined(STM32H5) || defined(STM32H7) // When exiting from Stop or Standby modes, the Run mode voltage scaling is reset to // the default VOS3 value. Restore the voltage scaling to the previous voltage scale. if (vscaling != POWERCTRL_GET_VOLTAGE_SCALING()) { @@ -879,7 +889,7 @@ void powerctrl_enter_stop_mode(void) { while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL1) { } - #else + #else // defined(STM32H5) // enable PLL __HAL_RCC_PLL_ENABLE(); @@ -899,7 +909,7 @@ void powerctrl_enter_stop_mode(void) { } #endif - #endif + #endif // defined(STM32H5) powerctrl_disable_hsi_if_unused(); @@ -912,6 +922,15 @@ void powerctrl_enter_stop_mode(void) { } #endif + #if defined(STM32H5) + if (rcc_cr & RCC_CR_HSI48ON) { + // Enable HSI48. + LL_RCC_HSI48_Enable(); + while (!LL_RCC_HSI48_IsReady()) { + } + } + #endif + #if defined(STM32H7) // Enable HSI if (rcc_cr & RCC_CR_HSION) { diff --git a/ports/stm32/powerctrlboot.c b/ports/stm32/powerctrlboot.c index c7802a5588..31dae527c1 100644 --- a/ports/stm32/powerctrlboot.c +++ b/ports/stm32/powerctrlboot.c @@ -298,6 +298,10 @@ void SystemClock_Config(void) { LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLL3Q); #endif + + #ifdef NDEBUG + DBGMCU->CR = 0; + #endif } #elif defined(STM32L0) diff --git a/ports/stm32/rtc.c b/ports/stm32/rtc.c index 3b05fb40eb..b209ea8354 100644 --- a/ports/stm32/rtc.c +++ b/ports/stm32/rtc.c @@ -756,9 +756,11 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) { RTC->WPR = 0xff; // enable external interrupts on line EXTI_RTC_WAKEUP - #if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL) + #if defined(STM32G0) || defined(STM32G4) || defined(STM32L4) || defined(STM32WB) || defined(STM32WL) EXTI->IMR1 |= 1 << EXTI_RTC_WAKEUP; EXTI->RTSR1 |= 1 << EXTI_RTC_WAKEUP; + #elif defined(STM32H5) + EXTI->IMR1 |= 1 << EXTI_RTC_WAKEUP; #elif defined(STM32H7) EXTI_D1->IMR1 |= 1 << EXTI_RTC_WAKEUP; EXTI->RTSR1 |= 1 << EXTI_RTC_WAKEUP; @@ -768,8 +770,10 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) { #endif // clear interrupt flags - #if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32WL) + #if defined(STM32G0) || defined(STM32G4) || defined(STM32WL) RTC->ICSR &= ~RTC_ICSR_WUTWF; + #elif defined(STM32H5) + RTC->SCR = RTC_SCR_CWUTF; #elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) RTC->SR &= ~RTC_SR_WUTF; #else