1 /*!
2 \file gd32f3x0_pmu.c
3 \brief PMU driver
4
5 \version 2017-06-06, V1.0.0, firmware for GD32F3x0
6 \version 2019-06-01, V2.0.0, firmware for GD32F3x0
7 \version 2020-09-30, V2.1.0, firmware for GD32F3x0
8 \version 2021-03-30, V1.0.0, firmware for GD32F3x0
9 */
10
11 /*
12 Copyright (c) 2021, GigaDevice Semiconductor Inc.
13
14 Redistribution and use in source and binary forms, with or without modification,
15 are permitted provided that the following conditions are met:
16
17 1. Redistributions of source code must retain the above copyright notice, this
18 list of conditions and the following disclaimer.
19 2. Redistributions in binary form must reproduce the above copyright notice,
20 this list of conditions and the following disclaimer in the documentation
21 and/or other materials provided with the distribution.
22 3. Neither the name of the copyright holder nor the names of its contributors
23 may be used to endorse or promote products derived from this software without
24 specific prior written permission.
25
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
30 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
33 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
35 OF SUCH DAMAGE.
36 */
37
38 #include "gd32f3x0_pmu.h"
39
40
41 /*!
42 \brief reset PMU register
43 \param[in] none
44 \param[out] none
45 \retval none
46 */
pmu_deinit(void)47 void pmu_deinit(void)
48 {
49 /* reset PMU */
50 rcu_periph_reset_enable(RCU_PMURST);
51 rcu_periph_reset_disable(RCU_PMURST);
52 }
53
54 /*!
55 \brief select low voltage detector threshold
56 \param[in] lvdt_n:
57 only one parameter can be selected which is shown as below:
58 \arg PMU_LVDT_0: voltage threshold is 2.1V
59 \arg PMU_LVDT_1: voltage threshold is 2.3V
60 \arg PMU_LVDT_2: voltage threshold is 2.4V
61 \arg PMU_LVDT_3: voltage threshold is 2.6V
62 \arg PMU_LVDT_4: voltage threshold is 2.7V
63 \arg PMU_LVDT_5: voltage threshold is 2.9V
64 \arg PMU_LVDT_6: voltage threshold is 3.0V
65 \arg PMU_LVDT_7: voltage threshold is 3.1V
66 \param[out] none
67 \retval none
68 */
pmu_lvd_select(uint32_t lvdt_n)69 void pmu_lvd_select(uint32_t lvdt_n)
70 {
71 /* disable LVD */
72 PMU_CTL &= ~PMU_CTL_LVDEN;
73 /* clear LVDT bits */
74 PMU_CTL &= ~PMU_CTL_LVDT;
75 /* set LVDT bits according to lvdt_n */
76 PMU_CTL |= lvdt_n;
77 /* enable LVD */
78 PMU_CTL |= PMU_CTL_LVDEN;
79 }
80
81 /*!
82 \brief select LDO output voltage
83 these bits set by software when the main PLL closed
84 \param[in] ldo_output:
85 only one parameter can be selected which is shown as below:
86 \arg PMU_LDOVS_LOW: LDO output voltage low mode
87 \arg PMU_LDOVS_MID: LDO output voltage mid mode
88 \arg PMU_LDOVS_HIGH: LDO output voltage high mode
89 \param[out] none
90 \retval none
91 */
pmu_ldo_output_select(uint32_t ldo_output)92 void pmu_ldo_output_select(uint32_t ldo_output)
93 {
94 PMU_CTL &= ~PMU_CTL_LDOVS;
95 PMU_CTL |= ldo_output;
96 }
97
98 /*!
99 \brief disable PMU lvd
100 \param[in] none
101 \param[out] none
102 \retval none
103 */
pmu_lvd_disable(void)104 void pmu_lvd_disable(void)
105 {
106 /* disable LVD */
107 PMU_CTL &= ~PMU_CTL_LVDEN;
108 }
109
110 /*!
111 \brief enable low-driver mode in deep-sleep mode
112 \param[in] none
113 \param[out] none
114 \retval none
115 */
pmu_lowdriver_mode_enable(void)116 void pmu_lowdriver_mode_enable(void)
117 {
118 PMU_CTL &= ~PMU_CTL_LDEN;
119 PMU_CTL |= PMU_LOWDRIVER_ENABLE;
120 }
121
122 /*!
123 \brief disable low-driver mode in deep-sleep mode
124 \param[in] none
125 \param[out] none
126 \retval none
127 */
pmu_lowdriver_mode_disable(void)128 void pmu_lowdriver_mode_disable(void)
129 {
130 PMU_CTL &= ~PMU_CTL_LDEN;
131 PMU_CTL |= PMU_LOWDRIVER_DISABLE;
132 }
133
134 /*!
135 \brief enable high-driver mode
136 this bit set by software only when IRC8M or HXTAL used as system clock
137 \param[in] none
138 \param[out] none
139 \retval none
140 */
pmu_highdriver_mode_enable(void)141 void pmu_highdriver_mode_enable(void)
142 {
143 PMU_CTL |= PMU_CTL_HDEN;
144 }
145
146 /*!
147 \brief disable high-driver mode
148 \param[in] none
149 \param[out] none
150 \retval none
151 */
pmu_highdriver_mode_disable(void)152 void pmu_highdriver_mode_disable(void)
153 {
154 PMU_CTL &= ~PMU_CTL_HDEN;
155 }
156
157 /*!
158 \brief switch high-driver mode
159 this bit set by software only when IRC8M or HXTAL used as system clock
160 \param[in] highdr_switch:
161 only one parameter can be selected which is shown as below:
162 \arg PMU_HIGHDR_SWITCH_NONE: disable high-driver mode switch
163 \arg PMU_HIGHDR_SWITCH_EN: enable high-driver mode switch
164 \param[out] none
165 \retval none
166 */
pmu_highdriver_switch_select(uint32_t highdr_switch)167 void pmu_highdriver_switch_select(uint32_t highdr_switch)
168 {
169 /* wait for HDRF flag to be set */
170 while(SET != pmu_flag_get(PMU_FLAG_HDR)){
171 }
172 PMU_CTL &= ~PMU_CTL_HDS;
173 PMU_CTL |= highdr_switch;
174 }
175
176 /*!
177 \brief low-driver mode when use low power LDO
178 \param[in] mode:
179 only one parameter can be selected which is shown as below:
180 \arg PMU_NORMALDR_LOWPWR: normal-driver when use low power LDO
181 \arg PMU_LOWDR_LOWPWR: low-driver mode enabled when LDEN is 11 and use low power LDO
182 \param[out] none
183 \retval none
184 */
pmu_lowpower_driver_config(uint32_t mode)185 void pmu_lowpower_driver_config(uint32_t mode)
186 {
187 PMU_CTL &= ~PMU_CTL_LDLP;
188 PMU_CTL |= mode;
189 }
190
191 /*!
192 \brief low-driver mode when use normal power LDO
193 \param[in] mode:
194 only one parameter can be selected which is shown as below:
195 \arg PMU_NORMALDR_NORMALPWR: normal-driver when use low power LDO
196 \arg PMU_LOWDR_NORMALPWR: low-driver mode enabled when LDEN is 11 and use low power LDO
197 \param[out] none
198 \retval none
199 */
pmu_normalpower_driver_config(uint32_t mode)200 void pmu_normalpower_driver_config(uint32_t mode)
201 {
202 PMU_CTL &= ~PMU_CTL_LDNP;
203 PMU_CTL |= mode;
204 }
205
206 /*!
207 \brief PMU work at sleep mode
208 \param[in] sleepmodecmd:
209 only one parameter can be selected which is shown as below:
210 \arg WFI_CMD: use WFI command
211 \arg WFE_CMD: use WFE command
212 \param[out] none
213 \retval none
214 */
pmu_to_sleepmode(uint8_t sleepmodecmd)215 void pmu_to_sleepmode(uint8_t sleepmodecmd)
216 {
217 /* clear sleepdeep bit of Cortex-M4 system control register */
218 SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
219
220 /* select WFI or WFE command to enter sleep mode */
221 if(WFI_CMD == sleepmodecmd){
222 __WFI();
223 }else{
224 __WFE();
225 }
226 }
227
228 /*!
229 \brief PMU work at deepsleep mode
230 \param[in] ldo:
231 only one parameter can be selected which is shown as below:
232 \arg PMU_LDO_NORMAL: LDO operates normally when pmu enter deepsleep mode
233 \arg PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter deepsleep mode
234 \param[in] deepsleepmodecmd:
235 only one parameter can be selected which is shown as below:
236 \arg WFI_CMD: use WFI command
237 \arg WFE_CMD: use WFE command
238 \param[out] none
239 \retval none
240 */
pmu_to_deepsleepmode(uint32_t ldo,uint8_t deepsleepmodecmd)241 void pmu_to_deepsleepmode(uint32_t ldo,uint8_t deepsleepmodecmd)
242 {
243 static uint32_t reg_snap[ 4 ];
244 /* clear stbmod and ldolp bits */
245 PMU_CTL &= ~((uint32_t)(PMU_CTL_STBMOD | PMU_CTL_LDOLP));
246
247 /* set ldolp bit according to pmu_ldo */
248 PMU_CTL |= ldo;
249
250 /* set sleepdeep bit of Cortex-M4 system control register */
251 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
252
253 reg_snap[0] = REG32(0xE000E010U);
254 reg_snap[1] = REG32(0xE000E100U);
255 reg_snap[2] = REG32(0xE000E104U);
256 reg_snap[3] = REG32(0xE000E108U);
257
258 REG32(0xE000E010U) &= 0x00010004U;
259 REG32(0xE000E180U) = 0XB7FFEF19U;
260 REG32(0xE000E184U) = 0XFFFFFBFFU;
261 REG32(0xE000E188U) = 0xFFFFFFFFU;
262
263 /* select WFI or WFE command to enter deepsleep mode */
264 if(WFI_CMD == deepsleepmodecmd){
265 __WFI();
266 }else{
267 __SEV();
268 __WFE();
269 __WFE();
270 }
271
272 REG32(0xE000E010U) = reg_snap[0 ];
273 REG32(0xE000E100U) = reg_snap[1];
274 REG32(0xE000E104U) = reg_snap[2];
275 REG32(0xE000E108U) = reg_snap[3];
276
277 /* reset sleepdeep bit of Cortex-M4 system control register */
278 SCB->SCR &= ~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
279 }
280
281 /*!
282 \brief pmu work at standby mode
283 \param[in] standbymodecmd:
284 only one parameter can be selected which is shown as below:
285 \arg WFI_CMD: use WFI command
286 \arg WFE_CMD: use WFE command
287 \param[out] none
288 \retval none
289 */
pmu_to_standbymode(uint8_t standbymodecmd)290 void pmu_to_standbymode(uint8_t standbymodecmd)
291 {
292 /* set sleepdeep bit of Cortex-M4 system control register */
293 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
294
295 /* set stbmod bit */
296 PMU_CTL |= PMU_CTL_STBMOD;
297
298 /* reset wakeup flag */
299 PMU_CTL |= PMU_CTL_WURST;
300
301 /* select WFI or WFE command to enter standby mode */
302 if(WFI_CMD == standbymodecmd){
303 __WFI();
304 }else{
305 __WFE();
306 __WFE();
307 }
308 }
309
310 /*!
311 \brief enable wakeup pin
312 \param[in] wakeup_pin:
313 one or more parameters can be selected which are shown as below:
314 \arg PMU_WAKEUP_PIN0: WKUP Pin 0 (PA0)
315 \arg PMU_WAKEUP_PIN1: WKUP Pin 1 (PC13)
316 \arg PMU_WAKEUP_PIN4: WKUP Pin 4 (PC5)
317 \arg PMU_WAKEUP_PIN5: WKUP Pin 5 (PB5)
318 \arg PMU_WAKEUP_PIN6: WKUP Pin 6 (PB15)
319 \param[out] none
320 \retval none
321 */
pmu_wakeup_pin_enable(uint32_t wakeup_pin)322 void pmu_wakeup_pin_enable(uint32_t wakeup_pin)
323 {
324 PMU_CS |= wakeup_pin;
325 }
326
327 /*!
328 \brief disable wakeup pin
329 \param[in] wakeup_pin:
330 one or more parameters can be selected which are shown as below:
331 \arg PMU_WAKEUP_PIN0: WKUP Pin 0 (PA0)
332 \arg PMU_WAKEUP_PIN1: WKUP Pin 1 (PC13)
333 \arg PMU_WAKEUP_PIN4: WKUP Pin 4 (PC5)
334 \arg PMU_WAKEUP_PIN5: WKUP Pin 5 (PB5)
335 \arg PMU_WAKEUP_PIN6: WKUP Pin 6 (PB15)
336 \param[out] none
337 \retval none
338 */
pmu_wakeup_pin_disable(uint32_t wakeup_pin)339 void pmu_wakeup_pin_disable(uint32_t wakeup_pin)
340 {
341 PMU_CS &= ~(wakeup_pin);
342 }
343
344 /*!
345 \brief enable backup domain write
346 \param[in] none
347 \param[out] none
348 \retval none
349 */
pmu_backup_write_enable(void)350 void pmu_backup_write_enable(void)
351 {
352 PMU_CTL |= PMU_CTL_BKPWEN;
353 }
354
355 /*!
356 \brief disable backup domain write
357 \param[in] none
358 \param[out] none
359 \retval none
360 */
pmu_backup_write_disable(void)361 void pmu_backup_write_disable(void)
362 {
363 PMU_CTL &= ~PMU_CTL_BKPWEN;
364 }
365
366 /*!
367 \brief clear flag bit
368 \param[in] flag_clear:
369 one or more parameters can be selected which are shown as below:
370 \arg PMU_FLAG_RESET_WAKEUP: reset wakeup flag
371 \arg PMU_FLAG_RESET_STANDBY: reset standby flag
372 \param[out] none
373 \retval none
374 */
pmu_flag_clear(uint32_t flag_clear)375 void pmu_flag_clear(uint32_t flag_clear)
376 {
377 if(RESET != (flag_clear & PMU_FLAG_RESET_WAKEUP)){
378 /* reset wakeup flag */
379 PMU_CTL |= PMU_CTL_WURST;
380 }
381 if(RESET != (flag_clear & PMU_FLAG_RESET_STANDBY)){
382 /* reset standby flag */
383 PMU_CTL |= PMU_CTL_STBRST;
384 }
385 }
386
387 /*!
388 \brief get flag state
389 \param[in] flag:
390 only one parameter can be selected which is shown as below:
391 \arg PMU_FLAG_WAKEUP: wakeup flag
392 \arg PMU_FLAG_STANDBY: standby flag
393 \arg PMU_FLAG_LVD: lvd flag
394 \arg PMU_FLAG_LDOVSR: LDO voltage select ready flag
395 \arg PMU_FLAG_HDR: high-driver ready flag
396 \arg PMU_FLAG_HDSR: high-driver switch ready flag
397 \arg PMU_FLAG_LDR: low-driver mode ready flag
398 \param[out] none
399 \retval FlagStatus SET or RESET
400 */
pmu_flag_get(uint32_t flag)401 FlagStatus pmu_flag_get(uint32_t flag)
402 {
403 FlagStatus ret_status = RESET;
404
405 if(PMU_CS & flag){
406 ret_status = SET;
407 }
408
409 return ret_status;
410 }
411