1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2020-07-27 thread-liu first version
9 */
10
11 #include "board.h"
12 //#define DRV_DEBUG
13 #define LOG_TAG "drv.pwr"
14 #include <drv_log.h>
15
16 extern int lptim_start(void);
17 extern int lptim_stop(void);
18
19 static RCC_ClkInitTypeDef RCC_ClkInit = {0};
20
21 #define __WAIT_EVENT_TIMEOUT(__CONDITION__, __TIMEOUT_VAL__) \
22 do { \
23 __IO uint32_t count = __TIMEOUT_VAL__ * (SystemCoreClock / 20U / 1000U); \
24 do \
25 { \
26 if (count-- == 0U) \
27 { \
28 return HAL_TIMEOUT; \
29 } \
30 } \
31 while (__CONDITION__ == 0U); \
32 } while(0)
33
34 /* Back up clock tree */
backup_cm4_clocks(void)35 static void backup_cm4_clocks(void)
36 {
37 rt_uint32_t *pFLatency = NULL;
38
39 /* Back up MCU clock configuration */
40 HAL_RCC_GetClockConfig(&RCC_ClkInit, pFLatency);
41 }
42
43 /* Restore the CM4 clock source muxer and the CM4 prescaler. */
restore_cm4_clock(void)44 rt_err_t restore_cm4_clock(void)
45 {
46 /* Update SystemCoreClock variable */
47 SystemCoreClock = HAL_RCC_GetSystemCoreClockFreq();
48
49 /* Enable PLL3 if needed */
50 if (RCC_ClkInit.MCUInit.MCU_Clock == RCC_MCUSSOURCE_PLL3)
51 {
52 /* Enable PLL3 */
53 __HAL_RCC_PLL3_ENABLE();
54
55 /* Wait till PLL3 is ready */
56 __WAIT_EVENT_TIMEOUT(__HAL_RCC_GET_FLAG(RCC_FLAG_PLL3RDY), CLOCKSWITCH_TIMEOUT_VALUE);
57
58 /* Enable PLL3 outputs */
59 __HAL_RCC_PLL3CLKOUT_ENABLE(RCC_PLL3_DIVP | RCC_PLL3_DIVQ | RCC_PLL3_DIVR);
60 }
61
62 /* Configure MCU clock only */
63 __HAL_RCC_MCU_SOURCE(RCC_ClkInit.MCUInit.MCU_Clock);
64
65 /* Wait till MCU is ready */
66 __WAIT_EVENT_TIMEOUT(__HAL_RCC_GET_FLAG(RCC_FLAG_MCUSSRCRDY),
67 CLOCKSWITCH_TIMEOUT_VALUE);
68
69 /* Update SystemCoreClock variable */
70 SystemCoreClock = HAL_RCC_GetSystemCoreClockFreq();
71
72 /* Reconfigure Systick */
73 if (HAL_InitTick(uwTickPrio) != HAL_OK)
74 {
75 return -RT_ERROR;
76 }
77
78 /* Set MCU division factor */
79 __HAL_RCC_MCU_DIV(RCC_ClkInit.MCUInit.MCU_Div);
80
81 /* Wait till MCUDIV is ready */
82 __WAIT_EVENT_TIMEOUT(__HAL_RCC_GET_FLAG(RCC_FLAG_MCUDIVRDY),
83 CLOCKSWITCH_TIMEOUT_VALUE);
84
85 /* Update SystemCoreClock variable */
86 SystemCoreClock = HAL_RCC_GetSystemCoreClockFreq();
87
88 /* Reconfigure Systick */
89 if (HAL_InitTick(uwTickPrio) != HAL_OK)
90 {
91 return -RT_ERROR;
92 }
93
94 return RT_EOK;
95 }
96
RCC_WAKEUP_IRQHandler(void)97 void RCC_WAKEUP_IRQHandler(void)
98 {
99 /* enter interrupt */
100 rt_interrupt_enter();
101
102 HAL_RCC_WAKEUP_IRQHandler();
103
104 /* leave interrupt */
105 rt_interrupt_leave();
106 }
107
HAL_RCC_WAKEUP_Callback()108 void HAL_RCC_WAKEUP_Callback()
109 {
110 if (__HAL_PWR_GET_FLAG(PWR_FLAG_STOP) == 1U)
111 {
112 __HAL_PWR_CLEAR_FLAG(PWR_FLAG_STOP);
113 }
114
115 restore_cm4_clock();
116 /* All level of ITs can interrupt */
117 __set_BASEPRI(0U);
118
119 rt_kprintf("system exit stop mode success!\n");
120 }
121
enter_sleep_mode(void)122 static void enter_sleep_mode(void)
123 {
124 __set_BASEPRI((1) << (8 - __NVIC_PRIO_BITS));
125
126 lptim_start();
127
128 HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);
129 }
130
enter_stop_mode(void)131 static void enter_stop_mode(void)
132 {
133 /*
134 * Only the IT with the highest priority (0 value) can interrupt.
135 * RCC_WAKEUP_IRQn IT is intended to have the highest priority and to be the
136 * only one IT having this value
137 * RCC_WAKEUP_IRQn is generated only when RCC is completely resumed from
138 * CSTOP (protection mechanism)
139 */
140 __set_BASEPRI((1) << (8 - __NVIC_PRIO_BITS));
141
142 __HAL_PWR_CLEAR_FLAG(PWR_FLAG_STOP);
143 backup_cm4_clocks();
144 HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
145 }
146
pm_wackup_key_init(void)147 static void pm_wackup_key_init(void)
148 {
149 GPIO_InitTypeDef GPIO_InitStruct = {0};
150
151 __HAL_RCC_GPIOA_CLK_ENABLE();
152
153 GPIO_InitStruct.Pin = GPIO_PIN_13;
154 GPIO_InitStruct.Pull = GPIO_PULLUP;
155 GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
156 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
157 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
158
159 HAL_NVIC_SetPriority(EXTI13_IRQn, 0x01, 0);
160 HAL_NVIC_EnableIRQ(EXTI13_IRQn);
161 }
162
drv_pm_hw_init(void)163 int drv_pm_hw_init(void)
164 {
165 pm_wackup_key_init();
166
167 return RT_EOK;
168 }
169 INIT_BOARD_EXPORT(drv_pm_hw_init);
170
pwr_sample(int argc,char * argv[])171 static int pwr_sample(int argc, char *argv[])
172 {
173 if (argc > 1)
174 {
175 if (!rt_strcmp(argv[1], "stop"))
176 {
177 rt_kprintf("system will enter stop mode! you can press USER2 button to exit this mode\n");
178 enter_stop_mode();
179 return RT_EOK;
180
181 }
182 else if (!rt_strcmp(argv[1], "sleep"))
183 {
184 rt_kprintf("system will enter sleep mode! lptim1 will wake up the system\n");
185 enter_sleep_mode();
186 return RT_EOK;
187 }
188 else
189 {
190 goto _exit;
191 }
192 }
193 _exit:
194 {
195 rt_kprintf("Usage:\n");
196 rt_kprintf("pwr_sample stop - system enter stop mode\n");
197 rt_kprintf("pwr_sample sleep - system enter sleep mode\n");
198 }
199
200 return -RT_ERROR;
201 }
202 MSH_CMD_EXPORT(pwr_sample, enter low power mode sample);
203