123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456 |
- /*
- * 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)按下按键K10: MCU进入休眠模式
- * 2)再按下按键K10:MCU退出休眠模式
- * 3)重复上述按键操作,MCU循环进入休眠模式(deep、standby、shutdown、idle)和退出对应的休眠模式。
- * 每次进入休眠模式前,MCU打印 "sleep:" + 休眠模式名称
- * 每次退出休眠模式后,MCU打印 "wake from sleep:" + 休眠模式名称
- * 操作步骤2:
- * 1)支持运行模式切换的芯片循环切换 低速->高速->低速 运行模式,对应时钟输出口输出对应模式下的时钟信号
- */
- #include <rtthread.h>
- #include <rtdevice.h>
- #include <board.h>
- #include <drivers/lptimer.h>
- #if defined(BSP_USING_PM)
- #if defined (HC32F4A0)
- #define PLL_SRC ((CM_CMU->PLLHCFGR & CMU_PLLHCFGR_PLLSRC) >> CMU_PLLHCFGR_PLLSRC_POS)
- #define BSP_KEY_PORT (GPIO_PORT_A) /* Key10 */
- #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 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 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 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)
- #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)
- 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;
- }
- 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)
- 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)
- 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)
- pm_dbg("bakram_pd = %d\n", bakram_pd);
- pm_dbg("bkr0 = %d\n", bkr0);
- #endif
- }
- static void _vbat_init(void)
- {
- #if defined (HC32F4A0)
- 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)
- 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 */
|