Wakeup from RTC or GPIO not working from Standby
I'm attempting to put my STM32L4xx into Standby mode, and then wake it up from GPIO or RTC. I'm not using any drivers. I've narrowed my problem down to the PWR peripheral clock, although I'm not sure if that is directly the cause.
If PWR clock is on when I call WFI, then it does not actually go to low power mode, and the GPIO does not return it from WFI. However it does pause until the RTC returns it from WFI, it just does not appear to go to a low power state.
If PWR clock is off (if I disable it after setting up the RTC, as shown in the code below), then the device appears to be asleep and the GPIO will wake it up, but the RTC does not.
Here is my clock set up code:
SET_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN); // enable PWR clock
asm("NOP");
asm("NOP");
// Configure the RTC
SET_BIT(PWR->CR1, PWR_CR1_DBP);
if ((uint32_t)(READ_BIT(RCC->BDCR, RCC_BDCR_RTCSEL)) != RCC_BDCR_RTCSEL_1) {
SET_BIT(RCC->BDCR, RCC_BDCR_BDRST); // reset the backup domain
CLEAR_BIT(RCC->BDCR, RCC_BDCR_BDRST);
MODIFY_REG(RCC->BDCR, RCC_BDCR_RTCSEL, RCC_BDCR_RTCSEL_1); // use LSI clock
}
SET_BIT(RCC->BDCR, RCC_BDCR_RTCEN); // enable RTC
CLEAR_BIT(RCC->APB1ENR1, RCC_APB1ENR1_PWREN); // disable PWR clockIf I remove the last line, which disables the PWR clock, then the RTC does cause an interrupt which returns from WFI(), but the MCU is not actually in low power mode while it is in WFI state. Additionally, the GPIO does not work to wake it up.
In case it is relevant, here is the RTC setup code. I can also share other code, such as GPIO interrupt setup if that would be useful.
/* SETUP RTC TIMER WAKEUP */
SET_BIT(RCC->BDCR, RCC_BDCR_RTCEN);
/* RTC interrupt Init */
NVIC_SetPriority(RTC_WKUP_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
NVIC_EnableIRQ(RTC_WKUP_IRQn);
WRITE_REG(RTC->WPR, RTC_WRITE_PROTECTION_ENABLE_1); // disable write protection for RTC registers
WRITE_REG(RTC->WPR, RTC_WRITE_PROTECTION_ENABLE_2);
// select wakeup alarm, enable wakeup interrupt, enable wakeup alarm, and select the slow 1 hz clock
CLEAR_BIT(RTC->CR, RTC_CR_WUTE); // disable wakeup so we can write to registers
while((RTC->ISR & RTC_ISR_WUTWF) == 0) {
asm("nop"); // wait until WUCKSEL write allowed
}
SET_BIT(RTC->CR, RTC_CR_OSEL_1); //
SET_BIT(RTC->CR, RTC_CR_WUTIE); //wakeup time interrupt enable
SET_BIT(RTC->CR, RTC_CR_WUCKSEL_2); // select 1 hz clock for wakeup clock
WRITE_REG(RTC->WUTR, PWR_WAKEUP_TIMER);
SET_BIT(RTC->CR, RTC_CR_WUTE); //wakeup timer enableAnd the code used to go to sleep:
PWR->CR1 |= PWR_CR1_LPMS_STANDBY;
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; // enable deep sleep mode
PWR->SR1 |= PWR_SR1_WUF1 | PWR_SR1_WUF2 | PWR_SR1_WUF3 | PWR_SR1_WUF4 | PWR_SR1_WUF5;
__WFI();