Всем привет.
Настраиваю stm32l100 для режима STANDBY. Пробуждение 2 раза в секунду, для этого запускаю RTC wakeup-timer.
После включения питания, первый уход и выход из STANDBY проходит штатно, а затем начинается ерунда - контроллер сразу выходит из STANDBY. Флаг что был в режиме STANDBY выставлен, а флаг что сработал wakeup-timer сброшен.
Если вместо режима STANDBY использовать обычный сон, то все работает штатно.
Словами и кодом опишу основные моменты
1) При старте
- анализирую и сохраняю флаги событий CSR_SBF и CSR_WUF. После этого сбрасываю их
if (PWR->CSR & PWR_CSR_SBF_BIT) {
// ...
}
if (PWR->CSR & PWR_CSR_WUF_BIT) {
// ...
}
PWR->CR |= PWR_CR_CSBF_BIT|PWR_CR_CWUF_BIT;
//while (PWR->CSR & PWR_CSR_SBF_BIT);
while (PWR->CSR & PWR_CSR_WUF_BIT);
Заметил что флаг CSR_SBF никогда не сбрасывается, хотя в шите написано что должен. Если раскомментировать строчку с while, то там зависнет. Не понимаю почему так.
- анализирую и сохраняю причины сброса, потом эти флаги очищаю
volatile uint32_t csr;
csr = RCC->CSR;
// .... анализ и сохранение
// сброс флагов
RCC->CSR |= RCC_CSR_RMVF_BIT;
При проблемном выходе из STANDBY все флаги сброшены, т.е. выглядит так что причины сброса нет или сброса не было. Но контроллер стартует с нуля.
2) Настройка RTC wakeup-timer
- все делаю по даташиту. Если не уходить в STANDBY, а просто засыпать через __WFI(), то все работает нормально - таймер генерирует прерывания с нужным периодом.
void rtc_set_wakeup_mode(const uint32_t wakeup_counter)
{
RTC_WRITE_PROTECT_DISABLE();
RTC->CR &= ~RTC_CR_WUTE_BIT;
while (!(RTC->ISR & RTC_ISR_WUTWF_BIT));
RTC->WUTR = wakeup_counter;
RTC->CR &= 0xfffffff7;
RTC->CR |= RTC_WAKEUPCLOCK_RTCCLK_DIV2;
__HAL_RTC_WAKEUPTIMER_EXTI_ENABLE_IT();
__HAL_RTC_WAKEUPTIMER_EXTI_ENABLE_RISING_EDGE();
RTC->CR |= RTC_CR_WUTIE_BIT|RTC_CR_WUTE_BIT;
RTC_WRITE_PROTECT_ENABLE();
}
Таймер настраиваю только один раз, когда причина сброса - питание/пин_ресет, т.е. явно не выход их STANDBY. Как понимаю из шита, дальше он должен постоянно перезагружать счетчик даже в режиме STANDBY.
3) Переход в режим STANDBY
void pwdm_enter_standby_mode(void)
{
PWR->CR |= PWR_CR_PDDS_BIT;
SCB->SCR |= SCB_SCR_SLEEPDEEP_BIT;
__WFI();
}