RT-Thread论坛
直播中

王玲

8年用户 1508经验值
私信 关注
[问答]

PM组件低功耗定时器动态补偿后,进入stop2无法唤醒怎么处理?

版本5.1.0,采用STM32L476结合pm组件做低功耗管理,开启了低功耗定时器动态补偿时钟,但是发现发现一旦开启低功耗定时器补偿时钟,进入休眠后mcu就无法在被唤醒,尝试在io外部中断请求中,
调用rt_pm_request(PM_SLEEP_MODE_NONE);退出stop2,但是并不起作用,外部中断确实是有执行,请问这会是什么原因,该怎么排查?



回帖(2)

刘宇

2025-9-10 17:41:21
pm.c中的_pm_change_sleep_mode()函数,注销掉rt_timer_check()调用


  • //        if (pm->timer_mask & (0x01 << pm->sleep_mode))
  • //        {
  • //            if (delta_tick)
  • //            {
  • //                rt_timer_check();
  • //            }
  • //        }

举报

成尔秩

2025-9-12 18:20:14

针对你遇到的PM组件低功耗定时器动态补偿导致STM32L476进入STOP2无法唤醒的问题,以下是系统的分析和解决方案:




根本原因分析



  1. 动态补偿干扰唤醒时钟

    开启低功耗定时器动态补偿后,系统可能在进入STOP2前切换时钟源(如使用LSI/LSE),但唤醒时未恢复高速时钟(HSI/HSE),导致中断虽触发但MCU无法正常运行。

  2. PM组件状态机未更新

    rt_pm_request(PM_SLEEP_MODE_NONE) 可能因PM内部状态机未正确响应唤醒请求(例如未清除低功耗标志)。

  3. 中断配置缺失

    唤醒中断(如EXTI)未正确注册到PM组件,导致中断触发后PM未执行退出流程。

  4. 硬件唤醒源未使能

    STM32L476的STOP2模式需通过特定唤醒源(如EXTI)触发,硬件配置可能未生效。




解决方案


1. 确保唤醒后时钟恢复


在唤醒中断处理函数中强制恢复系统时钟


// 外部中断服务函数
void EXTI0_IRQHandler(void)
{
    rt_pm_request(PM_SLEEP_MODE_NONE);  // 请求退出低功耗
    SystemClock_Reinit();               // 重新初始化时钟(关键步骤)
    // ... 其他处理
    __HAL_GPIO_EXTI_CLEAR_IT();        // 清除中断标志
}



  • SystemClock_Reinit()实现参考


    void SystemClock_Reinit(void)
    {
      RCC_OscInitTypeDef RCC_OscInitStruct = {0};
      RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

      // 重新启用HSE(外部高速时钟)
      RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
      RCC_OscInitStruct.HSEState = RCC_HSE_ON;
      HAL_RCC_OscConfig(&RCC_OscInitStruct);

      // 设置系统时钟(根据实际配置调整)
      RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
      RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
      RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
      RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
      RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
      HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
    }



2. 正确注册唤醒源


在PM初始化时注册外部中断为唤醒源:


// 在启用PM组件后添加
rt_pm_register_wakeup_source(
    RT_PM_WAKEUP_MODE_EXTERNAL,  // 指定为外部中断模式
    (void*)KEY_IRQHandler,       // 唤醒中断处理函数
    RT_TRUE                      // 支持自动唤醒
);

3. 检查硬件配置


确保STM32CubeMX或代码中已配置:



  • EXTI中断引脚设置为上升沿/下降沿触发。

  • NVIC优先级:唤醒中断优先级需高于系统tick中断(避免调度阻塞)。

  • GPIO模式:配置为外部中断模式(GPIO_MODE_IT_RISING)。


4. 动态补偿模块优化


在PM组件的休眠/唤醒钩子中开关动态补偿:


// 进入休眠时关闭补偿,唤醒后重新启用
static int pm_dynamic_comp_hook(rt_uint8_t event, rt_uint8_t mode)
{
    switch (event)
    {
    case RT_PM_ENTER_SLEEP:
        lptimer_dynamic_compensation_stop();  // 停止补偿
        break;
    case RT_PM_EXIT_SLEEP:
        lptimer_dynamic_compensation_start(); // 启动补偿
        break;
    }
    return RT_EOK;
}

// 注册钩子函数
rt_pm_register_hook(pm_dynamic_comp_hook);



关键排查步骤



  1. 验证基础唤醒功能

    关闭动态补偿,测试是否能正常唤醒。若能,则问题定位在补偿逻辑。

  2. 调试中断流程

    在唤醒中断中加入LED翻转或串口打印,确认中断是否执行到rt_pm_request

  3. 检查PM状态

    在唤醒后调用rt_pm_get_sleep_mode(),确保状态已切换为PM_SLEEP_MODE_NONE

  4. 时钟寄存器检查

    唤醒后读取RCC寄存器(如RCC_CFGR),确认SYSCLK源是否为HSI/HSE。




补充建议



  • 更新PM组件:确认使用RT-Thread v5.1.0的最新源码(修复可能存在的STOP2兼容性问题)。

  • 简化测试代码:移除动态补偿外的其他功能,构建最小复现环境。

  • 功耗监测:用电流表测量STOP2模式电流(正常约1μA),确认是否真进入STOP2。


通过以上步骤,应能解决动态补偿导致的无法唤醒问题。若仍遇到阻塞,建议在RT-Thread社区提交详细日志(时钟配置、中断寄存器截图等)进一步分析。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分