You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 19:13:12