问题分析:在V5.1.0版本启用PM组件后,进入Stop模式无法正常唤醒。这通常涉及几个关键因素:唤醒源配置、时钟恢复、外设状态管理、电源配置等问题。
以下是完整的解决方案:
#include
#include
#include
#include
#include "define_all.h"
#ifdef RT_USING_PM
#define DBG_TAG "drv.pm"
#define DBG_LVL DBG_LOG
#include
extern void SystemClock_ReConfig(uint8_t mode);
/* 串口控制台重配置 */
static void uart_console_reconfig(void)
{
#ifdef RT_USING_CONSOLE
struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;
rt_device_control(rt_console_get_device(), RT_DEVICE_CTRL_CONFIG, &config);
#endif
}
/* 系统时钟重新配置 */
static void clock_reinit_on_wakeup(void)
{
/* 1. 恢复时钟系统 */
SystemClock_ReConfig(0); // 0表示从低功耗唤醒
/* 2. 更新系统时钟计数 */
rt_tick_set(rt_tick_get() + RT_TICK_PER_SECOND/1000 * (uwWakeUpCounter + 1));
/* 3. 重新初始化关键外设 */
HAL_Init();
#if defined(RT_USING_SERIAL)
/* 4. 重新初始化串口子系统 */
rt_hw_serial_init();
uart_console_reconfig();
#endif
}
/* PM恢复回调函数 */
static int pm_resume_callback(struct rt_pm *pm, rt_uint8_t mode)
{
switch (mode)
{
case PM_SLEEP_MODE_DEEP: // Stop模式
/* 执行唤醒后的关键恢复操作 */
clock_reinit_on_wakeup();
/* 清除唤醒标志 */
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
/* 重新启用中断 */
__set_PRIMASK(0); // 全局中断使能
LOG_D("Exit from STOP mode");
break;
default:
break;
}
return RT_EOK;
}
/* PM挂起回调函数 */
static int pm_suspend_callback(struct rt_pm *pm, rt_uint8_t mode)
{
switch (mode)
{
case PM_SLEEP_MODE_DEEP: // Stop模式
LOG_D("Enter STOP mode");
/* 1. 配置唤醒源 */
// 示例:配置PA0作为唤醒源
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1); // 根据实际硬件选PIN
/* 2. 禁用全局中断 */
__set_PRIMASK(1); // 全局中断禁用
/* 3. 配置SysTick以正确处理唤醒 */
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
/* 4. 执行预休眠操作 */
HAL_SuspendTick();
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
break;
default:
break;
}
return RT_EOK;
}
/* 电源管理操作结构 */
static struct rt_pm_ops pm_ops = {
.suspend = pm_suspend_callback,
.resume = pm_resume_callback,
};
/* 初始化PM组件 */
int drv_pm_init(void)
{
rt_uint8_t modes[PM_SLEEP_MODE_MAX] = {
[PM_SLEEP_MODE_NONE] = 0, // 0表示不支持
[PM_SLEEP_MODE_IDLE] = 0, // 支持空闲模式
[PM_SLEEP_MODE_LIGHT] = 0, // 支持轻度睡眠
[PM_SLEEP_MODE_DEEP] = 1, // 支持深度睡眠(Stop)
[PM_SLEEP_MODE_STANDBY] = 0, // 不支持待机模式
[PM_SLEEP_MODE_SHUTDOWN] = 0, // 不支持关机模式
};
/* 注册电源管理回调 */
rt_pm_register(&pm_ops);
/* 设置支持的睡眠模式 */
for (int i = 0; i < PM_SLEEP_MODE_MAX; i++) {
rt_pm_add_sleep_mode(i, modes[i]);
}
/* 设置默认睡眠模式 */
rt_pm_default_set(PM_SLEEP_MODE_DEEP);
LOG_I("PM initialized with STOP mode support");
return RT_EOK;
}
INIT_DEVICE_EXPORT(drv_pm_init);
#else
int drv_pm_init(void)
{
LOG_D("PM component is disabled");
return RT_EOK;
}
INIT_DEVICE_EXPORT(drv_pm_init);
#endif /* RT_USING_PM */唤醒源配置
suspend回调中正确配置唤醒源HAL_PWR_EnableWakeUpPin()配置具体唤醒引脚__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU)清除唤醒标志时钟系统恢复
SystemClock_ReConfig()需正确处理不同模式的时钟切换中断管理
__set_PRIMASK(1)__set_PRIMASK(0)外设状态管理
rt_hw_serial_init()电源配置
PWR_LOWPOWERREGULATOR_ON进入低功耗模式PWR_STOPENTRY_WFI进入模式无法唤醒
唤醒后系统异常
SystemClock_ReConfig()实现正确计时不准确
rt_tick_set()串口无法工作
此解决方案针对STM32系列进行了优化,其他平台需调整相关硬件操作函数。建议通过示波器监测唤醒引脚和关键电源信号,配合调试器单步执行恢复流程进行精确排查。
举报
更多回帖