STM32在FreeRTOS环境下进入STOP模式后无法通过RTC闹钟唤醒的问题
问题:STM32+FreeRTOS下STOP1模式RTC闹钟唤醒失效
我在STM32上实现了STOP1模式下RTC闹钟唤醒的功能,启动FreeRTOS内核前测试完全正常,但启动FreeRTOS后,系统进入STOP1模式后无法被RTC闹钟唤醒,一直停留在低功耗模式。我怀疑是RTC闹钟中断被禁用,手动尝试启用中断后问题依旧,求排查方向。
进入STOP1模式的代码片段
taskDISABLE_INTERRUPTS(); HAL_SuspendTick(); HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn); HAL_NVIC_ClearPendingIRQ(RTC_Alarm_IRQn); SET_Alarm_A(); HAL_PWREx_EnterSTOP1Mode(PWR_STOPENTRY_WFI); SystemClock_Config(); HAL_ResumeTick(); taskENABLE_INTERRUPTS();
SET_Alarm_A函数代码
void SET_Alarm_A(uint8_t ui8_MinuteAlarm) { uint8_t ui8_AlarmInterval; RTC_AlarmTypeDef sAlarm = {0}; RTC_TimeTypeDef sTime = {0}; RTC_DateTypeDef sDate = {0}; // Get updated time from RTC HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN); // Get current Time HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN); // Get current Date. It is mandatory to read the Date after Time, even if not used gui8_RTChours = sTime.Hours; // Take the current RTC Hours gui8_RTCminutes = sTime.Minutes; // Take the current RTC Minutes gui8_RTCseconds = sTime.Seconds; // Take the current RTC Seconds ui8_AlarmInterval = gui8_RTCminutes + ui8_MinuteAlarm; // update the timing interval for next cycle if(ui8_AlarmInterval > 59U) { // check for values over 59 ui8_AlarmInterval = ui8_AlarmInterval - 60U; // calculate and compensate the overflow } sAlarm.AlarmTime.Hours = 0x0; sAlarm.AlarmTime.Minutes = ui8_AlarmInterval; sAlarm.AlarmTime.Seconds = 0x0; sAlarm.AlarmTime.SubSeconds = 0x0; sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET; sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS|RTC_ALARMMASK_SECONDS; // Compares Minutes only sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL; sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE; sAlarm.AlarmDateWeekDay = 0x1; sAlarm.Alarm = RTC_ALARM_A; if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN) != HAL_OK) { Error_Handler(); } }
排查方向
- FreeRTOS中断优先级配置:FreeRTOS规定,能抢占内核的中断优先级必须低于
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY(STM32中优先级数值越大,实际优先级越低)。检查RTC闹钟中断的NVIC优先级,确保其不高于该阈值,否则FreeRTOS会屏蔽此中断。 - 中断状态的实际验证:调用
taskDISABLE_INTERRUPTS()后手动启用RTC闹钟中断,可通过直接读取NVIC寄存器(如NVIC->ISER、NVIC->ICPR)确认中断是否真的被使能、挂起位是否清除,避免函数调用未生效。 - 任务调度导致的闹钟配置错误:FreeRTOS环境下,读取RTC时间和设置闹钟之间可能被任务调度打断,导致设置的闹钟时间早于当前实际时间,触发条件永远不满足。可在设置闹钟后立即读取RTC闹钟寄存器,验证配置的时间是否正确。
- FreeRTOS Tickless模式冲突:若开启了
configUSE_TICKLESS_IDLE,FreeRTOS的自动低功耗逻辑可能与手动进入STOP模式的代码冲突。可先关闭该配置测试,确认是否是此原因。 - RTC闹钟中断服务函数(ISR)正确性:确保ISR中正确调用
HAL_RTC_AlarmIRQHandler(&hrtc)清除中断标志,若ISR需要唤醒任务,需使用portYIELD_FROM_ISR()触发调度。同时检查ISR是否被正确注册到NVIC。 - STOP模式电源域配置:检查PWR相关寄存器,确认备份域(RTC所在域)在STOP1模式下保持供电,且RTC闹钟已被配置为合法唤醒源(部分型号需设置
PWR_CR中的对应位)。 - 时钟恢复的完整性:唤醒后执行
SystemClock_Config()时,需确保不仅恢复系统时钟,也正确恢复RTC的时钟源配置,避免后续RTC工作异常。
内容的提问来源于stack exchange,提问作者IGtti
相关产品推荐
相关产品推荐

