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