2025-07-30 8:54 AM
I have developed code (on the NUCLEO-L433RC-P) that uses shutdown and wake.
The code works when I debug or run, but it stops working after a cold restart (power removed then reconnected).
After a cold restart, the software runs correctly until the first shutdown is called. Once shutdown is called, it seems to crash and I have to perform a reset.
From power up, the MCU should run as follows...
Why does it seem to crash after the first shutdown (step 2 above) ?
I am aware that RTC backup registers are lost when power is removed, but I cannot see this causing the problem.
I have attached a flowchart diagram (wake_shutdown.png) to show how my code works.
The relevant code is also below
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_DAC1_Init();
MX_TIM6_Init();
MX_SPI2_Init();
MX_LPUART1_UART_Init();
MX_SPI1_Init();
MX_I2C1_Init();
MX_USART3_UART_Init();
MX_ADC1_Init();
MX_TIM7_Init();
MX_RTC_Init();
if (__HAL_PWR_GET_FLAG(PWR_FLAG_SB)) {
// woken from low power mode
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
// read wake marker from RTC backup register to determine if woken from sleep or shutdown
wake_marker = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR2);
if (wake_marker == WAKE_FROM_SLEEP_RTC) {
// woken from sleep (RTC wake)
wakeConfigUpdate(); // get time and date and restore reference pressure from RTC backup register
uint32_t tmp = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR3); // restore power switch state from RTC backup register
powerSeq = *(uint8_t*)&tmp;
// check if elapsed time is greater then shutdown time
if (elapsedSeconds >= RTC_SHUTDOWN_S) {
mcuPowerdown();
}
} else if (wake_marker == WAKE_FROM_SHUTDOWN_WKUP) {
// woken from shutdown (power switch pressed during shutdown)
wakeConfigReset(); // reset time and date and set default reference pressure
}
}
else
{
// woken from reset
wakeConfigReset(); // reset time and date and set default reference pressure
// store value in RTC backup register to indicate mcu was reset
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR2, WAKE_FROM_RESET);
}
while (1) {
}
}
static void MX_RTC_Init(void)
{
/** Initialize RTC Only
*/
hrtc.Instance = RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 127;
hrtc.Init.SynchPrediv = 255;
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
if (HAL_RTC_Init(&hrtc) != HAL_OK)
{
Error_Handler();
}
}
void wakeConfigReset (void) {
// set reference pressure to default value
pressure_ref = REF_PRESS_DEFAULT;
/** Initialize RTC and set the Time and Date
*/
sTime.Hours = 0x0;
sTime.Minutes = 0x0;
sTime.Seconds = 0x0;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
{
Error_Handler();
}
sDate.WeekDay = RTC_WEEKDAY_MONDAY;
sDate.Month = RTC_MONTH_JANUARY;
sDate.Date = 0x1;
sDate.Year = 0x0;
if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK)
{
Error_Handler();
}
// get time and date
HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
// convert start time and date to unix time
startSeconds = RTC_to_unix(&sTime, &sDate);
// store start time in RTC backup register
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, startSeconds);
}
void wakeConfigUpdate (void) {
// Restore pressure reference after wake
uint32_t tmp = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR0);
pressure_ref = *(float*)&tmp;
// get time and date
HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
// convert time and date to unix time
currentSeconds = RTC_to_unix(&sTime, &sDate);
// read unix start time from RTC backup register
startSeconds = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1);
// calculate elapsed time
elapsedSeconds = currentSeconds - startSeconds;
}
void mcuSleep (void){
/* The Following Wakeup sequence is highly recommended prior to each Standby mode entry
mainly when using more than one wakeup source this is to not miss any wakeup event.
- Disable all used wakeup sources,
- Clear all related wakeup flags,
- Re-enable all used wakeup sources,
- Enter the shutdown mode.
*/
// write pressure to RTC backup register
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR0, *(uint32_t*)&pressure_bak);
// write value to RTC backup register to indicate mcu was in sleep
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR2, WAKE_FROM_SLEEP_RTC);
// write power switch state to RTC backup register
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR3, *(uint32_t*)&powerSeq);
// Disable all used wakeup sources
HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, RTC_WAKE_SEC, RTC_WAKEUPCLOCK_CK_SPRE_16BITS);
// Clear all related wakeup flags
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
// shutdown the audio amplifier
ampPowerDown();
// Call sleep (note that the terms 'sleep' and 'powerdown' are only used for readability, both call shutdown mode)
HAL_PWREx_EnterSHUTDOWNMode();
}
void mcuPowerdown (void){
// write value to RTC backup register to indicate mcu was in shutdown
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR2, WAKE_FROM_SHUTDOWN_WKUP);
// disable RTC wakeup
HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
Enable_PC13_Wakeup();
// shutdown the audio amplifier
ampPowerDown();
// Call power down (note that the terms 'sleep' and 'powerdown' are only used for readability, both call shutdown mode)
HAL_PWREx_EnterSHUTDOWNMode();
}