/* * Copyright (c) 2022-2024, Xiaohua Semiconductor Co., Ltd. * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2024-12-30 CDT first version */ /* * 功能 * 程序清单:这是一个 PM 设备使用例程 * 例程导出了 pm_sample_init 命令到控制终端 * 命令调用格式:pm_sample_init * * 展示RTT休眠模式的进入和退出 * hc32 drv_pm 支持的RTT休眠模式包括: idle、deep、standby、shutdown * 每种休眠模式与芯片低功耗模式的对应关系是: * RTT | HC32 * -----------------------|---------- * PM_SLEEP_MODE_IDLE | 睡眠模式 * PM_SLEEP_MODE_DEEP | 停止模式 * PM_SLEEP_MODE_STANDBY | 掉电模式1或2(可配,默认配置是模式1) * PM_SLEEP_MODE_SHUTDOWN | 掉电模式3或4(可配,默认配置是模式3) * * 操作步骤1: * 1)按下WKUP按键: MCU进入休眠模式 * 2)再按下WKUP按键:MCU退出休眠模式 * 3)重复上述按键操作,MCU循环进入休眠模式(deep、standby、shutdown、idle)和退出对应的休眠模式。 * 每次进入休眠模式前,MCU打印 "sleep:" + 休眠模式名称 * 每次退出休眠模式后,MCU打印 "wake from sleep:" + 休眠模式名称 * 操作步骤2: * 1)支持运行模式切换的芯片循环切换 低速->高速->低速 运行模式,对应时钟输出口输出对应模式下的时钟信号 */ #include #include #include #include #if defined(BSP_USING_PM) #if defined (HC32F4A0) || defined (HC32F4A8) #define PLL_SRC ((CM_CMU->PLLHCFGR & CMU_PLLHCFGR_PLLSRC) >> CMU_PLLHCFGR_PLLSRC_POS) #define BSP_KEY_PORT (GPIO_PORT_A) #define BSP_KEY_PIN (GPIO_PIN_00) #define BSP_KEY_EXTINT (EXTINT_CH00) #define BSP_KEY_INT_SRC (INT_SRC_PORT_EIRQ0) #define BSP_KEY_IRQn (INT001_IRQn) #define BSP_KEY_INTC_STOP_WKUP_EXTINT (INTC_STOP_WKUP_EXTINT_CH0) #define BSP_KEY_EVT (EVT_SRC_PORT_EIRQ0) #define BSP_KEY_PWC_PD_WKUP_TRIG_WKUP (PWC_PD_WKUP_TRIG_WKUP0) #define BSP_KEY_PWC_PD_WKUP_WKUP (PWC_PD_WKUP_WKUP00) #define LED_GREEN_PORT (GPIO_PORT_C) #define LED_GREEN_PIN (GPIO_PIN_09) #define MCO_PORT (GPIO_PORT_A) #define MCO_PIN (GPIO_PIN_08) #define MCO_GPIO_FUNC (GPIO_FUNC_1) #elif defined (HC32F460) #define PLL_SRC ((CM_CMU->PLLCFGR & CMU_PLLCFGR_PLLSRC) >> CMU_PLLCFGR_PLLSRC_POS) #define BSP_KEY_PORT (GPIO_PORT_B) /* Key10 */ #define BSP_KEY_PIN (GPIO_PIN_01) #define BSP_KEY_EXTINT (EXTINT_CH01) #define BSP_KEY_INT_SRC (INT_SRC_PORT_EIRQ1) #define BSP_KEY_IRQn (INT001_IRQn) #define BSP_KEY_INTC_STOP_WKUP_EXTINT (INTC_STOP_WKUP_EXTINT_CH1) #define BSP_KEY_EVT (EVT_SRC_PORT_EIRQ1) #define BSP_KEY_PWC_PD_WKUP_TRIG_WKUP (PWC_PD_WKUP_TRIG_WKUP1) #define BSP_KEY_PWC_PD_WKUP_WKUP (PWC_PD_WKUP_WKUP01) #define LED_GREEN_PORT (GPIO_PORT_D) #define LED_GREEN_PIN (GPIO_PIN_04) #define MCO_PORT (GPIO_PORT_A) #define MCO_PIN (GPIO_PIN_08) #define MCO_GPIO_FUNC (GPIO_FUNC_1) #elif defined (HC32F448) #define PLL_SRC ((CM_CMU->PLLHCFGR & CMU_PLLHCFGR_PLLSRC) >> CMU_PLLHCFGR_PLLSRC_POS) #define BSP_KEY_PORT (GPIO_PORT_B) /* Key5 */ #define BSP_KEY_PIN (GPIO_PIN_06) #define BSP_KEY_EXTINT (EXTINT_CH06) #define BSP_KEY_INT_SRC (INT_SRC_PORT_EIRQ6) #define BSP_KEY_IRQn (INT001_IRQn) #define BSP_KEY_INTC_STOP_WKUP_EXTINT (INTC_STOP_WKUP_EXTINT_CH6) #define BSP_KEY_EVT (EVT_SRC_PORT_EIRQ6) #define BSP_KEY_PWC_PD_WKUP_TRIG_WKUP (PWC_PD_WKUP_TRIG_WKUP1) #define BSP_KEY_PWC_PD_WKUP_WKUP (PWC_PD_WKUP_WKUP12) #define LED_GREEN_PORT (GPIO_PORT_A) #define LED_GREEN_PIN (GPIO_PIN_02) #define MCO_PORT (GPIO_PORT_A) #define MCO_PIN (GPIO_PIN_08) #define MCO_GPIO_FUNC (GPIO_FUNC_1) #elif defined (HC32F472) #define PLL_SRC ((CM_CMU->PLLHCFGR & CMU_PLLHCFGR_PLLSRC) >> CMU_PLLHCFGR_PLLSRC_POS) #define BSP_KEY_PORT (GPIO_PORT_B) /* Key5 */ #define BSP_KEY_PIN (GPIO_PIN_05) #define BSP_KEY_EXTINT (EXTINT_CH05) #define BSP_KEY_INT_SRC (INT_SRC_PORT_EIRQ5) #define BSP_KEY_IRQn (INT001_IRQn) #define BSP_KEY_INTC_STOP_WKUP_EXTINT (INTC_STOP_WKUP_EXTINT_CH5) #define BSP_KEY_EVT (EVT_SRC_PORT_EIRQ5) #define BSP_KEY_PWC_PD_WKUP_TRIG_WKUP (PWC_PD_WKUP_TRIG_WKUP1) #define BSP_KEY_PWC_PD_WKUP_WKUP (PWC_PD_WKUP_WKUP11) #define LED_GREEN_PORT (GPIO_PORT_C) #define LED_GREEN_PIN (GPIO_PIN_09) #endif #define KEYCNT_BACKUP_ADDR (uint32_t *)(0x200F0010) #define KEYCNT_CMD_SLEEP_NONE (0) #define KEYCNT_CMD_SLEEP_IDLE (1) #define KEYCNT_CMD_SLEEP_DEEP (3) #define KEYCNT_CMD_SLEEP_STANDBY (5) #define KEYCNT_CMD_SLEEP_SHUTDOWN (7) #define PM_DBG #if defined PM_DBG #define pm_dbg rt_kprintf #else #define pm_dbg #endif static volatile uint32_t g_keycnt_cmd; static volatile rt_bool_t g_wkup_flag = RT_FALSE; static void KEY_IrqHandler(void) { if (SET == EXTINT_GetExtIntStatus(BSP_KEY_EXTINT)) { EXTINT_ClearExtIntStatus(BSP_KEY_EXTINT); __DSB(); __ISB(); } if (g_wkup_flag) { g_wkup_flag = RT_FALSE; return; } g_keycnt_cmd++; pm_dbg("g_keycnt_cmd =%d, ", g_keycnt_cmd); pm_dbg("recv sleep request\n"); NVIC_DisableIRQ(BSP_KEY_IRQn); NVIC_ClearPendingIRQ(BSP_KEY_IRQn); } static void _key_int_init(void) { stc_extint_init_t stcExtIntInit; stc_irq_signin_config_t stcIrqSignConfig; stc_gpio_init_t stcGpioInit; /* configuration structure initialization */ (void)GPIO_StructInit(&stcGpioInit); stcGpioInit.u16ExtInt = PIN_EXTINT_ON; stcGpioInit.u16PullUp = PIN_PU_ON; /* GPIO config */ (void)GPIO_Init(BSP_KEY_PORT, BSP_KEY_PIN, &stcGpioInit); /* Extint config */ (void)EXTINT_StructInit(&stcExtIntInit); stcExtIntInit.u32Edge = EXTINT_TRIG_FALLING; (void)EXTINT_Init(BSP_KEY_EXTINT, &stcExtIntInit); /* IRQ sign-in */ stcIrqSignConfig.enIntSrc = BSP_KEY_INT_SRC; stcIrqSignConfig.enIRQn = BSP_KEY_IRQn; stcIrqSignConfig.pfnCallback = KEY_IrqHandler; (void)INTC_IrqSignIn(&stcIrqSignConfig); /* NVIC config */ NVIC_ClearPendingIRQ(stcIrqSignConfig.enIRQn); NVIC_SetPriority(stcIrqSignConfig.enIRQn, DDL_IRQ_PRIO_DEFAULT); NVIC_EnableIRQ(stcIrqSignConfig.enIRQn); } static void _wkup_cfg_sleep_deep() { INTC_WakeupSrcCmd(BSP_KEY_INTC_STOP_WKUP_EXTINT, ENABLE); } static void _wkup_cfg_sleep_standby(void) { PWC_PD_SetWakeupTriggerEdge(BSP_KEY_PWC_PD_WKUP_TRIG_WKUP, PWC_PD_WKUP_TRIG_FALLING); PWC_PD_WakeupCmd(BSP_KEY_PWC_PD_WKUP_WKUP, ENABLE); PWC_PD_ClearWakeupStatus(PWC_PD_WKUP_FLAG_ALL); } static void _wkup_cfg_sleep_shutdown(void) { PWC_PD_SetWakeupTriggerEdge(BSP_KEY_PWC_PD_WKUP_TRIG_WKUP, PWC_PD_WKUP_TRIG_FALLING); PWC_PD_WakeupCmd(BSP_KEY_PWC_PD_WKUP_WKUP, ENABLE); } static void _sleep_enter_event_idle(void) { rt_kprintf("sleep: idle\n"); } static void _sleep_enter_event_deep(void) { _wkup_cfg_sleep_deep(); rt_kprintf("sleep: deep\n"); DDL_DelayMS(50); } static void _sleep_enter_event_standby(void) { _wkup_cfg_sleep_standby(); #if defined (HC32F4A0) || defined (HC32F4A8) PWC_BKR_Write(0, g_keycnt_cmd & 0xFF); #endif *KEYCNT_BACKUP_ADDR = g_keycnt_cmd; rt_kprintf("sleep: standby\n"); DDL_DelayMS(50); } static void _sleep_enter_event_shutdown(void) { _wkup_cfg_sleep_shutdown(); *KEYCNT_BACKUP_ADDR = g_keycnt_cmd; rt_kprintf("sleep: shutdown\n"); DDL_DelayMS(50); } static void _sleep_exit_event_idle(void) { rt_pm_release(PM_SLEEP_MODE_IDLE); rt_pm_request(PM_SLEEP_MODE_NONE); rt_kprintf("wakeup from sleep: idle\n"); } static void _sleep_exit_event_deep(void) { #if defined (HC32F460) PWC_STOP_ClockRecover(); #endif rt_pm_release(PM_SLEEP_MODE_DEEP); rt_pm_request(PM_SLEEP_MODE_NONE); rt_kprintf("wakeup from sleep: deep\n"); } typedef void (*notify)(void); static notify sleep_enter_func[PM_SLEEP_MODE_MAX] = { RT_NULL, _sleep_enter_event_idle, RT_NULL, _sleep_enter_event_deep, _sleep_enter_event_standby, _sleep_enter_event_shutdown, }; static notify sleep_exit_func[PM_SLEEP_MODE_MAX] = { RT_NULL, _sleep_exit_event_idle, RT_NULL, _sleep_exit_event_deep, RT_NULL, RT_NULL, }; static void _notify_func(uint8_t event, uint8_t mode, void *data) { if (event == RT_PM_ENTER_SLEEP) { SysTick_Suspend(); if (sleep_enter_func[mode] == RT_NULL) { return; } GPIO_ResetPins(LED_GREEN_PORT, LED_GREEN_PIN); sleep_enter_func[mode](); } else { SysTick_Resume(); if (sleep_exit_func[mode] != RT_NULL) { sleep_exit_func[mode](); } g_keycnt_cmd++; g_wkup_flag = RT_TRUE; pm_dbg("g_keycnt_cmd =%d, ", g_keycnt_cmd); NVIC_EnableIRQ(BSP_KEY_IRQn); } } static void pm_cmd_handler(void *parameter) { rt_uint8_t sleep_mode = PM_SLEEP_MODE_NONE; while (1) { if ((KEYCNT_CMD_SLEEP_IDLE == g_keycnt_cmd) || (KEYCNT_CMD_SLEEP_DEEP == g_keycnt_cmd) || \ (KEYCNT_CMD_SLEEP_STANDBY == g_keycnt_cmd) || (KEYCNT_CMD_SLEEP_SHUTDOWN == g_keycnt_cmd)) { switch (g_keycnt_cmd) { case KEYCNT_CMD_SLEEP_IDLE: sleep_mode = PM_SLEEP_MODE_IDLE; break; case KEYCNT_CMD_SLEEP_DEEP: sleep_mode = PM_SLEEP_MODE_DEEP; break; case KEYCNT_CMD_SLEEP_STANDBY: sleep_mode = PM_SLEEP_MODE_STANDBY; break; case KEYCNT_CMD_SLEEP_SHUTDOWN: sleep_mode = PM_SLEEP_MODE_SHUTDOWN; break; default: break; } rt_pm_request(sleep_mode); rt_pm_release(PM_SLEEP_MODE_NONE); rt_thread_mdelay(500); } else { rt_thread_mdelay(50); } } } #if defined(HC32F4A0) || defined(HC32F460) || defined(HC32F448) || defined(HC32F4A8) static void pm_run_main(void *parameter) { static rt_uint8_t run_index = 0; char *speed[] = {"low", "high"}; const rt_uint8_t run_mode[] = {PM_RUN_MODE_LOW_SPEED, PM_RUN_MODE_HIGH_SPEED}; GPIO_SetFunc(MCO_PORT, MCO_PIN, MCO_GPIO_FUNC); /* Configure clock output system clock */ CLK_MCOConfig(CLK_MCO1, CLK_MCO_SRC_HCLK, CLK_MCO_DIV8); /* MCO1 output enable */ CLK_MCOCmd(CLK_MCO1, ENABLE); while (1) { rt_pm_run_enter(run_mode[run_index]); rt_thread_mdelay(100); rt_kprintf("system clock switch to %s speed\n\n", speed[run_index]); if (++run_index >= ARRAY_SZ(run_mode)) { run_index = 0; } rt_thread_mdelay(3000); } } #endif static void _keycnt_cmd_init_after_power_on(void) { en_flag_status_t wkup_from_ptwk = PWC_PD_GetWakeupStatus(PWC_PD_WKUP_FLAG_WKUP0); #if defined (HC32F4A0) || defined (HC32F4A8) en_flag_status_t bakram_pd = PWC_BKR_GetStatus(PWC_BACKUP_RAM_FLAG_RAMPDF); uint8_t bkr0 = PWC_BKR_Read(0); if (bakram_pd == RT_TRUE) { g_keycnt_cmd = KEYCNT_CMD_SLEEP_NONE; } else #endif { g_keycnt_cmd = *KEYCNT_BACKUP_ADDR; if (g_keycnt_cmd == KEYCNT_CMD_SLEEP_STANDBY) { if (wkup_from_ptwk) { g_keycnt_cmd++; pm_dbg("g_keycnt_cmd =%d, ", g_keycnt_cmd); rt_kprintf("wakeup from sleep: standby\n\n"); } else { g_keycnt_cmd = KEYCNT_CMD_SLEEP_NONE; } } else if (g_keycnt_cmd >= KEYCNT_CMD_SLEEP_SHUTDOWN) { if ((g_keycnt_cmd == KEYCNT_CMD_SLEEP_SHUTDOWN) && wkup_from_ptwk) { pm_dbg("g_keycnt_cmd =%d \n", KEYCNT_CMD_SLEEP_NONE); rt_kprintf("wakeup from sleep: shutdown\n\n"); } g_keycnt_cmd = KEYCNT_CMD_SLEEP_NONE; } } pm_dbg("KEYCNT_BACKUP_ADDR addr =0x%p,value = %d\n", KEYCNT_BACKUP_ADDR, *KEYCNT_BACKUP_ADDR); pm_dbg("wkup_from_ptwk = %d\n", wkup_from_ptwk); #if defined (HC32F4A0) || defined (HC32F4A8) pm_dbg("bakram_pd = %d\n", bakram_pd); pm_dbg("bkr0 = %d\n", bkr0); #endif } static void _vbat_init(void) { #if defined (HC32F4A0) || defined (HC32F4A8) while (PWC_BKR_GetStatus(PWC_BACKUP_RAM_FLAG_RAMVALID) == RESET) { rt_thread_delay(10); } FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_SRAMB, ENABLE); #elif defined (HC32F448) FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_SRAMB, ENABLE); #elif defined (HC32F460) FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_SRAMRET, ENABLE); #elif defined (HC32F472) FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_SRAMRET, ENABLE); #endif pm_dbg("vbat init success\n"); } int pm_sample_init(void) { pm_dbg("pm_sample_init\n\n"); _keycnt_cmd_init_after_power_on(); _vbat_init(); _key_int_init(); rt_pm_notify_set(_notify_func, NULL); rt_thread_t thread = rt_thread_create("pm_cmd_handler", pm_cmd_handler, RT_NULL, 1024, 25, 10); if (thread != RT_NULL) { rt_thread_startup(thread); } else { rt_kprintf("create pm sample thread failed!\n"); } #if defined(HC32F4A0) || defined(HC32F460) || defined(HC32F448) || defined(HC32F4A8) thread = rt_thread_create("pm_run_main", pm_run_main, RT_NULL, 1024, 25, 10); if (thread != RT_NULL) { rt_thread_startup(thread); } else { rt_kprintf("create pm run thread failed!\n"); } #endif return RT_EOK; } MSH_CMD_EXPORT(pm_sample_init, pm sample init); #endif /* end of BSP_USING_PM */