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 <rene@see5.ch>
This commit is contained in:
Rene Straub 2023-10-21 15:03:53 +02:00 committed by Damien George
parent e5014a4d79
commit 47ea831c0e
4 changed files with 39 additions and 6 deletions

View File

@ -108,6 +108,12 @@ void machine_init(void) {
reset_cause = PYB_RESET_DEEPSLEEP; reset_cause = PYB_RESET_DEEPSLEEP;
PWR->CR1 |= PWR_CR1_CSBF; PWR->CR1 |= PWR_CR1_CSBF;
} else } 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) #elif defined(STM32H7)
if (PWR->CPUCR & PWR_CPUCR_SBF || PWR->CPUCR & PWR_CPUCR_STOPF) { if (PWR->CPUCR & PWR_CPUCR_SBF || PWR->CPUCR & PWR_CPUCR_STOPF) {
// came out of standby or stop mode // came out of standby or stop mode

View File

@ -48,6 +48,8 @@
#define POWERCTRL_GET_VOLTAGE_SCALING() PWR_REGULATOR_VOLTAGE_SCALE0 #define POWERCTRL_GET_VOLTAGE_SCALING() PWR_REGULATOR_VOLTAGE_SCALE0
#elif defined(STM32H723xx) #elif defined(STM32H723xx)
#define POWERCTRL_GET_VOLTAGE_SCALING() LL_PWR_GetRegulVoltageScaling() #define POWERCTRL_GET_VOLTAGE_SCALING() LL_PWR_GetRegulVoltageScaling()
#elif defined(STM32H5)
#define POWERCTRL_GET_VOLTAGE_SCALING() LL_PWR_GetRegulVoltageScaling()
#else #else
#define POWERCTRL_GET_VOLTAGE_SCALING() \ #define POWERCTRL_GET_VOLTAGE_SCALING() \
(((PWR->CSR1 & PWR_CSR1_ACTVOS) && (SYSCFG->PWRCR & SYSCFG_PWRCR_ODEN)) ? \ (((PWR->CSR1 & PWR_CSR1_ACTVOS) && (SYSCFG->PWRCR & SYSCFG_PWRCR_ODEN)) ? \
@ -797,6 +799,14 @@ void powerctrl_enter_stop_mode(void) {
HAL_PWREx_EnableFlashPowerDown(); HAL_PWREx_EnableFlashPowerDown();
#endif #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) #if defined(STM32H7)
// Save RCC CR to re-enable OSCs and PLLs after wake up from low power mode. // Save RCC CR to re-enable OSCs and PLLs after wake up from low power mode.
uint32_t rcc_cr = RCC->CR; 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) { 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 // 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. // the default VOS3 value. Restore the voltage scaling to the previous voltage scale.
if (vscaling != POWERCTRL_GET_VOLTAGE_SCALING()) { 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) { while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL1) {
} }
#else #else // defined(STM32H5)
// enable PLL // enable PLL
__HAL_RCC_PLL_ENABLE(); __HAL_RCC_PLL_ENABLE();
@ -899,7 +909,7 @@ void powerctrl_enter_stop_mode(void) {
} }
#endif #endif
#endif #endif // defined(STM32H5)
powerctrl_disable_hsi_if_unused(); powerctrl_disable_hsi_if_unused();
@ -912,6 +922,15 @@ void powerctrl_enter_stop_mode(void) {
} }
#endif #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) #if defined(STM32H7)
// Enable HSI // Enable HSI
if (rcc_cr & RCC_CR_HSION) { if (rcc_cr & RCC_CR_HSION) {

View File

@ -298,6 +298,10 @@ void SystemClock_Config(void) {
LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLL3Q); LL_RCC_SetUSBClockSource(LL_RCC_USB_CLKSOURCE_PLL3Q);
#endif #endif
#ifdef NDEBUG
DBGMCU->CR = 0;
#endif
} }
#elif defined(STM32L0) #elif defined(STM32L0)

View File

@ -756,9 +756,11 @@ mp_obj_t pyb_rtc_wakeup(size_t n_args, const mp_obj_t *args) {
RTC->WPR = 0xff; RTC->WPR = 0xff;
// enable external interrupts on line EXTI_RTC_WAKEUP // 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->IMR1 |= 1 << EXTI_RTC_WAKEUP;
EXTI->RTSR1 |= 1 << EXTI_RTC_WAKEUP; EXTI->RTSR1 |= 1 << EXTI_RTC_WAKEUP;
#elif defined(STM32H5)
EXTI->IMR1 |= 1 << EXTI_RTC_WAKEUP;
#elif defined(STM32H7) #elif defined(STM32H7)
EXTI_D1->IMR1 |= 1 << EXTI_RTC_WAKEUP; EXTI_D1->IMR1 |= 1 << EXTI_RTC_WAKEUP;
EXTI->RTSR1 |= 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 #endif
// clear interrupt flags // clear interrupt flags
#if defined(STM32G0) || defined(STM32G4) || defined(STM32H5) || defined(STM32WL) #if defined(STM32G0) || defined(STM32G4) || defined(STM32WL)
RTC->ICSR &= ~RTC_ICSR_WUTWF; RTC->ICSR &= ~RTC_ICSR_WUTWF;
#elif defined(STM32H5)
RTC->SCR = RTC_SCR_CWUTF;
#elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ) #elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ) || defined(STM32H7B3xx) || defined(STM32H7B3xxQ)
RTC->SR &= ~RTC_SR_WUTF; RTC->SR &= ~RTC_SR_WUTF;
#else #else