test_pm.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. /*
  2. * Copyright (c) 2022-2024, Xiaohua Semiconductor Co., Ltd.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2024-12-30 CDT first version
  9. */
  10. /*
  11. * 功能
  12. * 程序清单:这是一个 PM 设备使用例程
  13. * 例程导出了 pm_sample_init 命令到控制终端
  14. * 命令调用格式:pm_sample_init
  15. *
  16. * 展示RTT休眠模式的进入和退出
  17. * hc32 drv_pm 支持的RTT休眠模式包括: idle、deep、standby、shutdown
  18. * 每种休眠模式与芯片低功耗模式的对应关系是:
  19. * RTT | HC32
  20. * -----------------------|----------
  21. * PM_SLEEP_MODE_IDLE | 睡眠模式
  22. * PM_SLEEP_MODE_DEEP | 停止模式
  23. * PM_SLEEP_MODE_STANDBY | 掉电模式1或2(可配,默认配置是模式1)
  24. * PM_SLEEP_MODE_SHUTDOWN | 掉电模式3或4(可配,默认配置是模式3)
  25. *
  26. * 操作步骤1:
  27. * 1)按下按键K10: MCU进入休眠模式
  28. * 2)再按下按键K10:MCU退出休眠模式
  29. * 3)重复上述按键操作,MCU循环进入休眠模式(deep、standby、shutdown、idle)和退出对应的休眠模式。
  30. * 每次进入休眠模式前,MCU打印 "sleep:" + 休眠模式名称
  31. * 每次退出休眠模式后,MCU打印 "wake from sleep:" + 休眠模式名称
  32. * 操作步骤2:
  33. * 1)支持运行模式切换的芯片循环切换 低速->高速->低速 运行模式,对应时钟输出口输出对应模式下的时钟信号
  34. */
  35. #include <rtthread.h>
  36. #include <rtdevice.h>
  37. #include <board.h>
  38. #include <drivers/lptimer.h>
  39. #if defined(BSP_USING_PM)
  40. #if defined (HC32F4A0)
  41. #define PLL_SRC ((CM_CMU->PLLHCFGR & CMU_PLLHCFGR_PLLSRC) >> CMU_PLLHCFGR_PLLSRC_POS)
  42. #define BSP_KEY_PORT (GPIO_PORT_A) /* Key10 */
  43. #define BSP_KEY_PIN (GPIO_PIN_00)
  44. #define BSP_KEY_EXTINT (EXTINT_CH00)
  45. #define BSP_KEY_INT_SRC (INT_SRC_PORT_EIRQ0)
  46. #define BSP_KEY_IRQn (INT001_IRQn)
  47. #define BSP_KEY_INTC_STOP_WKUP_EXTINT (INTC_STOP_WKUP_EXTINT_CH0)
  48. #define BSP_KEY_EVT (EVT_SRC_PORT_EIRQ0)
  49. #define BSP_KEY_PWC_PD_WKUP_TRIG_WKUP (PWC_PD_WKUP_TRIG_WKUP0)
  50. #define BSP_KEY_PWC_PD_WKUP_WKUP (PWC_PD_WKUP_WKUP00)
  51. #define MCO_PORT (GPIO_PORT_A)
  52. #define MCO_PIN (GPIO_PIN_08)
  53. #define MCO_GPIO_FUNC (GPIO_FUNC_1)
  54. #elif defined (HC32F460)
  55. #define PLL_SRC ((CM_CMU->PLLCFGR & CMU_PLLCFGR_PLLSRC) >> CMU_PLLCFGR_PLLSRC_POS)
  56. #define BSP_KEY_PORT (GPIO_PORT_B) /* Key10 */
  57. #define BSP_KEY_PIN (GPIO_PIN_01)
  58. #define BSP_KEY_EXTINT (EXTINT_CH01)
  59. #define BSP_KEY_INT_SRC (INT_SRC_PORT_EIRQ1)
  60. #define BSP_KEY_IRQn (INT001_IRQn)
  61. #define BSP_KEY_INTC_STOP_WKUP_EXTINT (INTC_STOP_WKUP_EXTINT_CH1)
  62. #define BSP_KEY_EVT (EVT_SRC_PORT_EIRQ1)
  63. #define BSP_KEY_PWC_PD_WKUP_TRIG_WKUP (PWC_PD_WKUP_TRIG_WKUP1)
  64. #define BSP_KEY_PWC_PD_WKUP_WKUP (PWC_PD_WKUP_WKUP01)
  65. #define MCO_PORT (GPIO_PORT_A)
  66. #define MCO_PIN (GPIO_PIN_08)
  67. #define MCO_GPIO_FUNC (GPIO_FUNC_1)
  68. #elif defined (HC32F448)
  69. #define PLL_SRC ((CM_CMU->PLLHCFGR & CMU_PLLHCFGR_PLLSRC) >> CMU_PLLHCFGR_PLLSRC_POS)
  70. #define BSP_KEY_PORT (GPIO_PORT_B) /* Key5 */
  71. #define BSP_KEY_PIN (GPIO_PIN_06)
  72. #define BSP_KEY_EXTINT (EXTINT_CH06)
  73. #define BSP_KEY_INT_SRC (INT_SRC_PORT_EIRQ6)
  74. #define BSP_KEY_IRQn (INT001_IRQn)
  75. #define BSP_KEY_INTC_STOP_WKUP_EXTINT (INTC_STOP_WKUP_EXTINT_CH6)
  76. #define BSP_KEY_EVT (EVT_SRC_PORT_EIRQ6)
  77. #define BSP_KEY_PWC_PD_WKUP_TRIG_WKUP (PWC_PD_WKUP_TRIG_WKUP1)
  78. #define BSP_KEY_PWC_PD_WKUP_WKUP (PWC_PD_WKUP_WKUP12)
  79. #define MCO_PORT (GPIO_PORT_A)
  80. #define MCO_PIN (GPIO_PIN_08)
  81. #define MCO_GPIO_FUNC (GPIO_FUNC_1)
  82. #elif defined (HC32F472)
  83. #define PLL_SRC ((CM_CMU->PLLHCFGR & CMU_PLLHCFGR_PLLSRC) >> CMU_PLLHCFGR_PLLSRC_POS)
  84. #define BSP_KEY_PORT (GPIO_PORT_B) /* Key5 */
  85. #define BSP_KEY_PIN (GPIO_PIN_05)
  86. #define BSP_KEY_EXTINT (EXTINT_CH05)
  87. #define BSP_KEY_INT_SRC (INT_SRC_PORT_EIRQ5)
  88. #define BSP_KEY_IRQn (INT001_IRQn)
  89. #define BSP_KEY_INTC_STOP_WKUP_EXTINT (INTC_STOP_WKUP_EXTINT_CH5)
  90. #define BSP_KEY_EVT (EVT_SRC_PORT_EIRQ5)
  91. #define BSP_KEY_PWC_PD_WKUP_TRIG_WKUP (PWC_PD_WKUP_TRIG_WKUP1)
  92. #define BSP_KEY_PWC_PD_WKUP_WKUP (PWC_PD_WKUP_WKUP11)
  93. #endif
  94. #define KEYCNT_BACKUP_ADDR (uint32_t *)(0x200F0010)
  95. #define KEYCNT_CMD_SLEEP_NONE (0)
  96. #define KEYCNT_CMD_SLEEP_IDLE (1)
  97. #define KEYCNT_CMD_SLEEP_DEEP (3)
  98. #define KEYCNT_CMD_SLEEP_STANDBY (5)
  99. #define KEYCNT_CMD_SLEEP_SHUTDOWN (7)
  100. #define PM_DBG
  101. #if defined PM_DBG
  102. #define pm_dbg rt_kprintf
  103. #else
  104. #define pm_dbg
  105. #endif
  106. static volatile uint32_t g_keycnt_cmd;
  107. static volatile rt_bool_t g_wkup_flag = RT_FALSE;
  108. static void KEY_IrqHandler(void)
  109. {
  110. if (SET == EXTINT_GetExtIntStatus(BSP_KEY_EXTINT))
  111. {
  112. EXTINT_ClearExtIntStatus(BSP_KEY_EXTINT);
  113. __DSB();
  114. __ISB();
  115. }
  116. if (g_wkup_flag)
  117. {
  118. g_wkup_flag = RT_FALSE;
  119. return;
  120. }
  121. g_keycnt_cmd++;
  122. pm_dbg("g_keycnt_cmd =%d, ", g_keycnt_cmd);
  123. pm_dbg("recv sleep request\n");
  124. NVIC_DisableIRQ(BSP_KEY_IRQn);
  125. NVIC_ClearPendingIRQ(BSP_KEY_IRQn);
  126. }
  127. static void _key_int_init(void)
  128. {
  129. stc_extint_init_t stcExtIntInit;
  130. stc_irq_signin_config_t stcIrqSignConfig;
  131. stc_gpio_init_t stcGpioInit;
  132. /* configuration structure initialization */
  133. (void)GPIO_StructInit(&stcGpioInit);
  134. stcGpioInit.u16ExtInt = PIN_EXTINT_ON;
  135. stcGpioInit.u16PullUp = PIN_PU_ON;
  136. /* GPIO config */
  137. (void)GPIO_Init(BSP_KEY_PORT, BSP_KEY_PIN, &stcGpioInit);
  138. /* Extint config */
  139. (void)EXTINT_StructInit(&stcExtIntInit);
  140. stcExtIntInit.u32Edge = EXTINT_TRIG_FALLING;
  141. (void)EXTINT_Init(BSP_KEY_EXTINT, &stcExtIntInit);
  142. /* IRQ sign-in */
  143. stcIrqSignConfig.enIntSrc = BSP_KEY_INT_SRC;
  144. stcIrqSignConfig.enIRQn = BSP_KEY_IRQn;
  145. stcIrqSignConfig.pfnCallback = KEY_IrqHandler;
  146. (void)INTC_IrqSignIn(&stcIrqSignConfig);
  147. /* NVIC config */
  148. NVIC_ClearPendingIRQ(stcIrqSignConfig.enIRQn);
  149. NVIC_SetPriority(stcIrqSignConfig.enIRQn, DDL_IRQ_PRIO_DEFAULT);
  150. NVIC_EnableIRQ(stcIrqSignConfig.enIRQn);
  151. }
  152. static void _wkup_cfg_sleep_deep()
  153. {
  154. INTC_WakeupSrcCmd(BSP_KEY_INTC_STOP_WKUP_EXTINT, ENABLE);
  155. }
  156. static void _wkup_cfg_sleep_standby(void)
  157. {
  158. PWC_PD_SetWakeupTriggerEdge(BSP_KEY_PWC_PD_WKUP_TRIG_WKUP, PWC_PD_WKUP_TRIG_FALLING);
  159. PWC_PD_WakeupCmd(BSP_KEY_PWC_PD_WKUP_WKUP, ENABLE);
  160. PWC_PD_ClearWakeupStatus(PWC_PD_WKUP_FLAG_ALL);
  161. }
  162. static void _wkup_cfg_sleep_shutdown(void)
  163. {
  164. PWC_PD_SetWakeupTriggerEdge(BSP_KEY_PWC_PD_WKUP_TRIG_WKUP, PWC_PD_WKUP_TRIG_FALLING);
  165. PWC_PD_WakeupCmd(BSP_KEY_PWC_PD_WKUP_WKUP, ENABLE);
  166. }
  167. static void _sleep_enter_event_idle(void)
  168. {
  169. rt_kprintf("sleep: idle\n");
  170. }
  171. static void _sleep_enter_event_deep(void)
  172. {
  173. _wkup_cfg_sleep_deep();
  174. rt_kprintf("sleep: deep\n");
  175. DDL_DelayMS(50);
  176. }
  177. static void _sleep_enter_event_standby(void)
  178. {
  179. _wkup_cfg_sleep_standby();
  180. #if defined (HC32F4A0)
  181. PWC_BKR_Write(0, g_keycnt_cmd & 0xFF);
  182. #endif
  183. *KEYCNT_BACKUP_ADDR = g_keycnt_cmd;
  184. rt_kprintf("sleep: standby\n");
  185. DDL_DelayMS(50);
  186. }
  187. static void _sleep_enter_event_shutdown(void)
  188. {
  189. _wkup_cfg_sleep_shutdown();
  190. *KEYCNT_BACKUP_ADDR = g_keycnt_cmd;
  191. rt_kprintf("sleep: shutdown\n");
  192. DDL_DelayMS(50);
  193. }
  194. static void _sleep_exit_event_idle(void)
  195. {
  196. rt_pm_release(PM_SLEEP_MODE_IDLE);
  197. rt_pm_request(PM_SLEEP_MODE_NONE);
  198. rt_kprintf("wakeup from sleep: idle\n");
  199. }
  200. static void _sleep_exit_event_deep(void)
  201. {
  202. #if defined (HC32F460)
  203. PWC_STOP_ClockRecover();
  204. #endif
  205. rt_pm_release(PM_SLEEP_MODE_DEEP);
  206. rt_pm_request(PM_SLEEP_MODE_NONE);
  207. rt_kprintf("wakeup from sleep: deep\n");
  208. }
  209. typedef void (*notify)(void);
  210. static notify sleep_enter_func[PM_SLEEP_MODE_MAX] =
  211. {
  212. RT_NULL,
  213. _sleep_enter_event_idle,
  214. RT_NULL,
  215. _sleep_enter_event_deep,
  216. _sleep_enter_event_standby,
  217. _sleep_enter_event_shutdown,
  218. };
  219. static notify sleep_exit_func[PM_SLEEP_MODE_MAX] =
  220. {
  221. RT_NULL,
  222. _sleep_exit_event_idle,
  223. RT_NULL,
  224. _sleep_exit_event_deep,
  225. RT_NULL,
  226. RT_NULL,
  227. };
  228. static void _notify_func(uint8_t event, uint8_t mode, void *data)
  229. {
  230. if (event == RT_PM_ENTER_SLEEP)
  231. {
  232. SysTick_Suspend();
  233. if (sleep_enter_func[mode] == RT_NULL)
  234. {
  235. return;
  236. }
  237. sleep_enter_func[mode]();
  238. }
  239. else
  240. {
  241. SysTick_Resume();
  242. if (sleep_exit_func[mode] != RT_NULL)
  243. {
  244. sleep_exit_func[mode]();
  245. }
  246. g_keycnt_cmd++;
  247. g_wkup_flag = RT_TRUE;
  248. pm_dbg("g_keycnt_cmd =%d, ", g_keycnt_cmd);
  249. NVIC_EnableIRQ(BSP_KEY_IRQn);
  250. }
  251. }
  252. static void pm_cmd_handler(void *parameter)
  253. {
  254. rt_uint8_t sleep_mode = PM_SLEEP_MODE_NONE;
  255. while (1)
  256. {
  257. if ((KEYCNT_CMD_SLEEP_IDLE == g_keycnt_cmd) || (KEYCNT_CMD_SLEEP_DEEP == g_keycnt_cmd) || \
  258. (KEYCNT_CMD_SLEEP_STANDBY == g_keycnt_cmd) || (KEYCNT_CMD_SLEEP_SHUTDOWN == g_keycnt_cmd))
  259. {
  260. switch (g_keycnt_cmd)
  261. {
  262. case KEYCNT_CMD_SLEEP_IDLE:
  263. sleep_mode = PM_SLEEP_MODE_IDLE;
  264. break;
  265. case KEYCNT_CMD_SLEEP_DEEP:
  266. sleep_mode = PM_SLEEP_MODE_DEEP;
  267. break;
  268. case KEYCNT_CMD_SLEEP_STANDBY:
  269. sleep_mode = PM_SLEEP_MODE_STANDBY;
  270. break;
  271. case KEYCNT_CMD_SLEEP_SHUTDOWN:
  272. sleep_mode = PM_SLEEP_MODE_SHUTDOWN;
  273. break;
  274. default:
  275. break;
  276. }
  277. rt_pm_request(sleep_mode);
  278. rt_pm_release(PM_SLEEP_MODE_NONE);
  279. rt_thread_mdelay(500);
  280. }
  281. else
  282. {
  283. rt_thread_mdelay(50);
  284. }
  285. }
  286. }
  287. #if defined(HC32F4A0) || defined(HC32F460) || defined(HC32F448)
  288. static void pm_run_main(void *parameter)
  289. {
  290. static rt_uint8_t run_index = 0;
  291. char *speed[] = {"low", "high"};
  292. const rt_uint8_t run_mode[] = {PM_RUN_MODE_LOW_SPEED, PM_RUN_MODE_HIGH_SPEED};
  293. GPIO_SetFunc(MCO_PORT, MCO_PIN, MCO_GPIO_FUNC);
  294. /* Configure clock output system clock */
  295. CLK_MCOConfig(CLK_MCO1, CLK_MCO_SRC_HCLK, CLK_MCO_DIV8);
  296. /* MCO1 output enable */
  297. CLK_MCOCmd(CLK_MCO1, ENABLE);
  298. while (1)
  299. {
  300. rt_pm_run_enter(run_mode[run_index]);
  301. rt_thread_mdelay(100);
  302. rt_kprintf("system clock switch to %s speed\n\n", speed[run_index]);
  303. if (++run_index >= ARRAY_SZ(run_mode))
  304. {
  305. run_index = 0;
  306. }
  307. rt_thread_mdelay(3000);
  308. }
  309. }
  310. #endif
  311. static void _keycnt_cmd_init_after_power_on(void)
  312. {
  313. en_flag_status_t wkup_from_ptwk = PWC_PD_GetWakeupStatus(PWC_PD_WKUP_FLAG_WKUP0);
  314. #if defined (HC32F4A0)
  315. en_flag_status_t bakram_pd = PWC_BKR_GetStatus(PWC_BACKUP_RAM_FLAG_RAMPDF);
  316. uint8_t bkr0 = PWC_BKR_Read(0);
  317. if (bakram_pd == RT_TRUE)
  318. {
  319. g_keycnt_cmd = KEYCNT_CMD_SLEEP_NONE;
  320. }
  321. else
  322. #endif
  323. {
  324. g_keycnt_cmd = *KEYCNT_BACKUP_ADDR;
  325. if (g_keycnt_cmd == KEYCNT_CMD_SLEEP_STANDBY)
  326. {
  327. if (wkup_from_ptwk)
  328. {
  329. g_keycnt_cmd++;
  330. pm_dbg("g_keycnt_cmd =%d, ", g_keycnt_cmd);
  331. rt_kprintf("wakeup from sleep: standby\n\n");
  332. }
  333. else
  334. {
  335. g_keycnt_cmd = KEYCNT_CMD_SLEEP_NONE;
  336. }
  337. }
  338. else if (g_keycnt_cmd >= KEYCNT_CMD_SLEEP_SHUTDOWN)
  339. {
  340. if ((g_keycnt_cmd == KEYCNT_CMD_SLEEP_SHUTDOWN) && wkup_from_ptwk)
  341. {
  342. pm_dbg("g_keycnt_cmd =%d \n", KEYCNT_CMD_SLEEP_NONE);
  343. rt_kprintf("wakeup from sleep: shutdown\n\n");
  344. }
  345. g_keycnt_cmd = KEYCNT_CMD_SLEEP_NONE;
  346. }
  347. }
  348. pm_dbg("KEYCNT_BACKUP_ADDR addr =0x%p,value = %d\n", KEYCNT_BACKUP_ADDR, *KEYCNT_BACKUP_ADDR);
  349. pm_dbg("wkup_from_ptwk = %d\n", wkup_from_ptwk);
  350. #if defined (HC32F4A0)
  351. pm_dbg("bakram_pd = %d\n", bakram_pd);
  352. pm_dbg("bkr0 = %d\n", bkr0);
  353. #endif
  354. }
  355. static void _vbat_init(void)
  356. {
  357. #if defined (HC32F4A0)
  358. while (PWC_BKR_GetStatus(PWC_BACKUP_RAM_FLAG_RAMVALID) == RESET)
  359. {
  360. rt_thread_delay(10);
  361. }
  362. FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_SRAMB, ENABLE);
  363. #elif defined (HC32F448)
  364. FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_SRAMB, ENABLE);
  365. #elif defined (HC32F460)
  366. FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_SRAMRET, ENABLE);
  367. #elif defined (HC32F472)
  368. FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_SRAMRET, ENABLE);
  369. #endif
  370. pm_dbg("vbat init success\n");
  371. }
  372. int pm_sample_init(void)
  373. {
  374. pm_dbg("pm_sample_init\n\n");
  375. _keycnt_cmd_init_after_power_on();
  376. _vbat_init();
  377. _key_int_init();
  378. rt_pm_notify_set(_notify_func, NULL);
  379. rt_thread_t thread = rt_thread_create("pm_cmd_handler", pm_cmd_handler, RT_NULL, 1024, 25, 10);
  380. if (thread != RT_NULL)
  381. {
  382. rt_thread_startup(thread);
  383. }
  384. else
  385. {
  386. rt_kprintf("create pm sample thread failed!\n");
  387. }
  388. #if defined(HC32F4A0) || defined(HC32F460) || defined(HC32F448)
  389. thread = rt_thread_create("pm_run_main", pm_run_main, RT_NULL, 1024, 25, 10);
  390. if (thread != RT_NULL)
  391. {
  392. rt_thread_startup(thread);
  393. }
  394. else
  395. {
  396. rt_kprintf("create pm run thread failed!\n");
  397. }
  398. #endif
  399. return RT_EOK;
  400. }
  401. MSH_CMD_EXPORT(pm_sample_init, pm sample init);
  402. #endif /* end of BSP_USING_PM */