1 /*!
2 \file gd32f3x0_rcu.c
3 \brief RCU 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 */
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 "gd32f3x0_rcu.h"
38
39 /* define clock source */
40 #define SEL_IRC8M ((uint32_t)0x00000000U)
41 #define SEL_HXTAL ((uint32_t)0x00000001U)
42 #define SEL_PLL ((uint32_t)0x00000002U)
43
44 /* define startup timeout count */
45 #define OSC_STARTUP_TIMEOUT ((uint32_t)0x000FFFFFU)
46 #define LXTAL_STARTUP_TIMEOUT ((uint32_t)0x03FFFFFFU)
47
48 /*!
49 \brief deinitialize the RCU
50 \param[in] none
51 \param[out] none
52 \retval none
53 */
rcu_deinit(void)54 void rcu_deinit(void)
55 {
56 /* enable IRC8M */
57 RCU_CTL0 |= RCU_CTL0_IRC8MEN;
58 while(0U == (RCU_CTL0 & RCU_CTL0_IRC8MSTB)){
59 }
60 /* reset RCU */
61 RCU_CFG0 &= ~(RCU_CFG0_SCS | RCU_CFG0_AHBPSC | RCU_CFG0_APB1PSC | RCU_CFG0_APB2PSC |\
62 RCU_CFG0_ADCPSC | RCU_CFG0_CKOUTSEL | RCU_CFG0_CKOUTDIV | RCU_CFG0_PLLDV);
63 RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PLLMF | RCU_CFG0_PLLMF4 | RCU_CFG0_PLLDV);
64 #if (defined(GD32F350))
65 RCU_CFG0 &= ~(RCU_CFG0_USBFSPSC);
66 RCU_CFG2 &= ~(RCU_CFG2_CECSEL | RCU_CFG2_USBFSPSC2);
67 #endif /* GD32F350 */
68 RCU_CTL0 &= ~(RCU_CTL0_HXTALEN | RCU_CTL0_CKMEN | RCU_CTL0_PLLEN | RCU_CTL0_HXTALBPS);
69 RCU_CFG1 &= ~(RCU_CFG1_PREDV | RCU_CFG1_PLLMF5 | RCU_CFG1_PLLPRESEL);
70 RCU_CFG2 &= ~(RCU_CFG2_USART0SEL | RCU_CFG2_ADCSEL);
71 RCU_CFG2 &= ~RCU_CFG2_IRC28MDIV;
72 RCU_CFG2 &= ~RCU_CFG2_ADCPSC2;
73 RCU_CTL1 &= ~RCU_CTL1_IRC28MEN;
74 RCU_ADDCTL &= ~RCU_ADDCTL_IRC48MEN;
75 RCU_INT = 0x00000000U;
76 RCU_ADDINT = 0x00000000U;
77 }
78
79 /*!
80 \brief enable the peripherals clock
81 \param[in] periph: RCU peripherals, refer to rcu_periph_enum
82 only one parameter can be selected which is shown as below:
83 \arg RCU_GPIOx (x=A,B,C,D,F): GPIO ports clock
84 \arg RCU_DMA: DMA clock
85 \arg RCU_CRC: CRC clock
86 \arg RCU_TSI: TSI clock
87 \arg RCU_CFGCMP: CFGCMP clock
88 \arg RCU_ADC: ADC clock
89 \arg RCU_TIMERx (x=0,1,2,5,13,14,15,16): TIMER clock (RCU_TIMER5 only for GD32F350)
90 \arg RCU_SPIx (x=0,1): SPI clock
91 \arg RCU_USARTx (x=0,1): USART clock
92 \arg RCU_WWDGT: WWDGT clock
93 \arg RCU_I2Cx (x=0,1): I2C clock
94 \arg RCU_USBFS: USBFS clock (only for GD32F350)
95 \arg RCU_PMU: PMU clock
96 \arg RCU_DAC: DAC clock (only for GD32F350)
97 \arg RCU_CEC: CEC clock (only for GD32F350)
98 \arg RCU_CTC: CTC clock
99 \arg RCU_RTC: RTC clock
100 \param[out] none
101 \retval none
102 */
rcu_periph_clock_enable(rcu_periph_enum periph)103 void rcu_periph_clock_enable(rcu_periph_enum periph)
104 {
105 RCU_REG_VAL(periph) |= BIT(RCU_BIT_POS(periph));
106 }
107
108 /*!
109 \brief disable the peripherals clock
110 \param[in] periph: RCU peripherals, refer to rcu_periph_enum
111 only one parameter can be selected which is shown as below:
112 \arg RCU_GPIOx (x=A,B,C,D,F): GPIO ports clock
113 \arg RCU_DMA: DMA clock
114 \arg RCU_CRC: CRC clock
115 \arg RCU_TSI: TSI clock
116 \arg RCU_CFGCMP: CFGCMP clock
117 \arg RCU_ADC: ADC clock
118 \arg RCU_TIMERx (x=0,1,2,5,13,14,15,16): TIMER clock (RCU_TIMER5 only for GD32F350)
119 \arg RCU_SPIx (x=0,1): SPI clock
120 \arg RCU_USARTx (x=0,1): USART clock
121 \arg RCU_WWDGT: WWDGT clock
122 \arg RCU_I2Cx (x=0,1): I2C clock
123 \arg RCU_USBFS: USBFS clock (only for GD32F350)
124 \arg RCU_PMU: PMU clock
125 \arg RCU_DAC: DAC clock (only for GD32F350)
126 \arg RCU_CEC: CEC clock (only for GD32F350)
127 \arg RCU_CTC: CTC clock
128 \arg RCU_RTC: RTC clock
129 \param[out] none
130 \retval none
131 */
rcu_periph_clock_disable(rcu_periph_enum periph)132 void rcu_periph_clock_disable(rcu_periph_enum periph)
133 {
134 RCU_REG_VAL(periph) &= ~BIT(RCU_BIT_POS(periph));
135 }
136
137 /*!
138 \brief enable the peripherals clock when sleep mode
139 \param[in] periph: RCU peripherals, refer to rcu_periph_sleep_enum
140 only one parameter can be selected which is shown as below:
141 \arg RCU_FMC_SLP: FMC clock
142 \arg RCU_SRAM_SLP: SRAM clock
143 \param[out] none
144 \retval none
145 */
rcu_periph_clock_sleep_enable(rcu_periph_sleep_enum periph)146 void rcu_periph_clock_sleep_enable(rcu_periph_sleep_enum periph)
147 {
148 RCU_REG_VAL(periph) |= BIT(RCU_BIT_POS(periph));
149 }
150
151 /*!
152 \brief disable the peripherals clock when sleep mode
153 \param[in] periph: RCU peripherals, refer to rcu_periph_sleep_enum
154 only one parameter can be selected which is shown as below:
155 \arg RCU_FMC_SLP: FMC clock
156 \arg RCU_SRAM_SLP: SRAM clock
157 \param[out] none
158 \retval none
159 */
rcu_periph_clock_sleep_disable(rcu_periph_sleep_enum periph)160 void rcu_periph_clock_sleep_disable(rcu_periph_sleep_enum periph)
161 {
162 RCU_REG_VAL(periph) &= ~BIT(RCU_BIT_POS(periph));
163 }
164 /*!
165 \brief reset the peripherals
166 \param[in] periph_reset: RCU peripherals reset, refer to rcu_periph_reset_enum
167 only one parameter can be selected which is shown as below:
168 \arg RCU_GPIOxRST (x=A,B,C,D,F): reset GPIO ports
169 \arg RCU_TSIRST: reset TSI
170 \arg RCU_CFGCMPRST: reset CFGCMP
171 \arg RCU_ADCRST: reset ADC
172 \arg RCU_TIMERxRST (x=0,1,2,5,13,14,15,16): reset TIMER (RCU_TIMER5 only for GD32F350)
173 \arg RCU_SPIxRST (x=0,1): reset SPI
174 \arg RCU_USARTxRST (x=0,1): reset USART
175 \arg RCU_WWDGTRST: reset WWDGT
176 \arg RCU_I2CxRST (x=0,1): reset I2C
177 \arg RCU_USBFSRST: reset USBFS (only for GD32F350)
178 \arg RCU_PMURST: reset PMU
179 \arg RCU_DACRST: reset DAC (only for GD32F350)
180 \arg RCU_CECRST: reset CEC (only for GD32F350)
181 \arg RCU_CTCRST: reset CTC
182 \param[out] none
183 \retval none
184 */
rcu_periph_reset_enable(rcu_periph_reset_enum periph_reset)185 void rcu_periph_reset_enable(rcu_periph_reset_enum periph_reset)
186 {
187 RCU_REG_VAL(periph_reset) |= BIT(RCU_BIT_POS(periph_reset));
188 }
189
190 /*!
191 \brief disable reset the peripheral
192 \param[in] periph_reset: RCU peripherals reset, refer to rcu_periph_reset_enum
193 only one parameter can be selected which is shown as below:
194 \arg RCU_GPIOxRST (x=A,B,C,D,F): reset GPIO ports
195 \arg RCU_TSIRST: reset TSI
196 \arg RCU_CFGCMPRST: reset CFGCMP
197 \arg RCU_ADCRST: reset ADC
198 \arg RCU_TIMERxRST (x=0,1,2,5,13,14,15,16): reset TIMER (RCU_TIMER5 only for GD32F350)
199 \arg RCU_SPIxRST (x=0,1,2): reset SPI
200 \arg RCU_USARTxRST (x=0,1): reset USART
201 \arg RCU_WWDGTRST: reset WWDGT
202 \arg RCU_I2CxRST (x=0,1,2): reset I2C
203 \arg RCU_USBFSRST: reset USBFS (only for GD32F350)
204 \arg RCU_PMURST: reset PMU
205 \arg RCU_DACRST: reset DAC (only for GD32F350)
206 \arg RCU_CECRST: reset CEC (only for GD32F350)
207 \arg RCU_CTCRST: reset CTC
208 \param[out] none
209 \retval none
210 */
rcu_periph_reset_disable(rcu_periph_reset_enum periph_reset)211 void rcu_periph_reset_disable(rcu_periph_reset_enum periph_reset)
212 {
213 RCU_REG_VAL(periph_reset) &= ~BIT(RCU_BIT_POS(periph_reset));
214 }
215
216 /*!
217 \brief reset the BKP
218 \param[in] none
219 \param[out] none
220 \retval none
221 */
rcu_bkp_reset_enable(void)222 void rcu_bkp_reset_enable(void)
223 {
224 RCU_BDCTL |= RCU_BDCTL_BKPRST;
225 }
226
227 /*!
228 \brief disable the BKP reset
229 \param[in] none
230 \param[out] none
231 \retval none
232 */
rcu_bkp_reset_disable(void)233 void rcu_bkp_reset_disable(void)
234 {
235 RCU_BDCTL &= ~RCU_BDCTL_BKPRST;
236 }
237
238 /*!
239 \brief configure the system clock source
240 \param[in] ck_sys: system clock source select
241 only one parameter can be selected which is shown as below:
242 \arg RCU_CKSYSSRC_IRC8M: select CK_IRC8M as the CK_SYS source
243 \arg RCU_CKSYSSRC_HXTAL: select CK_HXTAL as the CK_SYS source
244 \arg RCU_CKSYSSRC_PLL: select CK_PLL as the CK_SYS source
245 \param[out] none
246 \retval none
247 */
rcu_system_clock_source_config(uint32_t ck_sys)248 void rcu_system_clock_source_config(uint32_t ck_sys)
249 {
250 uint32_t cksys_source = 0U;
251 cksys_source = RCU_CFG0;
252 /* reset the SCS bits and set according to ck_sys */
253 cksys_source &= ~RCU_CFG0_SCS;
254 RCU_CFG0 = (ck_sys | cksys_source);
255 }
256
257 /*!
258 \brief get the system clock source
259 \param[in] none
260 \param[out] none
261 \retval which clock is selected as CK_SYS source
262 only one parameter can be selected which is shown as below:
263 \arg RCU_SCSS_IRC8M: select CK_IRC8M as the CK_SYS source
264 \arg RCU_SCSS_HXTAL: select CK_HXTAL as the CK_SYS source
265 \arg RCU_SCSS_PLL: select CK_PLL as the CK_SYS source
266 */
rcu_system_clock_source_get(void)267 uint32_t rcu_system_clock_source_get(void)
268 {
269 return (RCU_CFG0 & RCU_CFG0_SCSS);
270 }
271
272 /*!
273 \brief configure the AHB clock prescaler selection
274 \param[in] ck_ahb: AHB clock prescaler selection
275 only one parameter can be selected which is shown as below:
276 \arg RCU_AHB_CKSYS_DIVx, x=1, 2, 4, 8, 16, 64, 128, 256, 512
277 \param[out] none
278 \retval none
279 */
rcu_ahb_clock_config(uint32_t ck_ahb)280 void rcu_ahb_clock_config(uint32_t ck_ahb)
281 {
282 uint32_t ahbpsc = 0U;
283 ahbpsc = RCU_CFG0;
284 /* reset the AHBPSC bits and set according to ck_ahb */
285 ahbpsc &= ~RCU_CFG0_AHBPSC;
286 RCU_CFG0 = (ck_ahb | ahbpsc);
287 }
288
289 /*!
290 \brief configure the APB1 clock prescaler selection
291 \param[in] ck_apb1: APB1 clock prescaler selection
292 only one parameter can be selected which is shown as below:
293 \arg RCU_APB1_CKAHB_DIV1: select CK_AHB as CK_APB1
294 \arg RCU_APB1_CKAHB_DIV2: select CK_AHB/2 as CK_APB1
295 \arg RCU_APB1_CKAHB_DIV4: select CK_AHB/4 as CK_APB1
296 \arg RCU_APB1_CKAHB_DIV8: select CK_AHB/8 as CK_APB1
297 \arg RCU_APB1_CKAHB_DIV16: select CK_AHB/16 as CK_APB1
298 \param[out] none
299 \retval none
300 */
rcu_apb1_clock_config(uint32_t ck_apb1)301 void rcu_apb1_clock_config(uint32_t ck_apb1)
302 {
303 uint32_t apb1psc = 0U;
304 apb1psc = RCU_CFG0;
305 /* reset the APB1PSC and set according to ck_apb1 */
306 apb1psc &= ~RCU_CFG0_APB1PSC;
307 RCU_CFG0 = (ck_apb1 | apb1psc);
308 }
309
310 /*!
311 \brief configure the APB2 clock prescaler selection
312 \param[in] ck_apb2: APB2 clock prescaler selection
313 only one parameter can be selected which is shown as below:
314 \arg RCU_APB2_CKAHB_DIV1: select CK_AHB as CK_APB2
315 \arg RCU_APB2_CKAHB_DIV2: select CK_AHB/2 as CK_APB2
316 \arg RCU_APB2_CKAHB_DIV4: select CK_AHB/4 as CK_APB2
317 \arg RCU_APB2_CKAHB_DIV8: select CK_AHB/8 as CK_APB2
318 \arg RCU_APB2_CKAHB_DIV16: select CK_AHB/16 as CK_APB2
319 \param[out] none
320 \retval none
321 */
rcu_apb2_clock_config(uint32_t ck_apb2)322 void rcu_apb2_clock_config(uint32_t ck_apb2)
323 {
324 uint32_t apb2psc = 0U;
325 apb2psc = RCU_CFG0;
326 /* reset the APB2PSC and set according to ck_apb2 */
327 apb2psc &= ~RCU_CFG0_APB2PSC;
328 RCU_CFG0 = (ck_apb2 | apb2psc);
329 }
330
331 /*!
332 \brief configure the ADC clock prescaler selection
333 \param[in] ck_adc: ADC clock prescaler selection, refer to rcu_adc_clock_enum
334 only one parameter can be selected which is shown as below:
335 \arg RCU_ADCCK_IRC28M_DIV2: select CK_IRC28M/2 as CK_ADC
336 \arg RCU_ADCCK_IRC28M: select CK_IRC28M as CK_ADC
337 \arg RCU_ADCCK_APB2_DIV2: select CK_APB2/2 as CK_ADC
338 \arg RCU_ADCCK_AHB_DIV3: select CK_AHB/3 as CK_ADC
339 \arg RCU_ADCCK_APB2_DIV4: select CK_APB2/4 as CK_ADC
340 \arg RCU_ADCCK_AHB_DIV5: select CK_AHB/5 as CK_ADC
341 \arg RCU_ADCCK_APB2_DIV6: select CK_APB2/6 as CK_ADC
342 \arg RCU_ADCCK_AHB_DIV7: select CK_AHB/7 as CK_ADC
343 \arg RCU_ADCCK_APB2_DIV8: select CK_APB2/8 as CK_ADC
344 \arg RCU_ADCCK_AHB_DIV9: select CK_AHB/9 as CK_ADC
345 \param[out] none
346 \retval none
347 */
rcu_adc_clock_config(rcu_adc_clock_enum ck_adc)348 void rcu_adc_clock_config(rcu_adc_clock_enum ck_adc)
349 {
350 /* reset the ADCPSC, ADCSEL, IRC28MDIV bits */
351 RCU_CFG0 &= ~RCU_CFG0_ADCPSC;
352 RCU_CFG2 &= ~(RCU_CFG2_ADCSEL | RCU_CFG2_IRC28MDIV | RCU_CFG2_ADCPSC2);
353
354 /* set the ADC clock according to ck_adc */
355 switch(ck_adc){
356 case RCU_ADCCK_IRC28M_DIV2:
357 RCU_CFG2 &= ~RCU_CFG2_IRC28MDIV;
358 RCU_CFG2 &= ~RCU_CFG2_ADCSEL;
359 break;
360 case RCU_ADCCK_IRC28M:
361 RCU_CFG2 |= RCU_CFG2_IRC28MDIV;
362 RCU_CFG2 &= ~RCU_CFG2_ADCSEL;
363 break;
364 case RCU_ADCCK_APB2_DIV2:
365 RCU_CFG0 |= RCU_ADC_CKAPB2_DIV2;
366 RCU_CFG2 |= RCU_CFG2_ADCSEL;
367 break;
368 case RCU_ADCCK_AHB_DIV3:
369 RCU_CFG0 |= RCU_ADC_CKAPB2_DIV2;
370 RCU_CFG2 |= RCU_CFG2_ADCPSC2;
371 RCU_CFG2 |= RCU_CFG2_ADCSEL;
372 break;
373 case RCU_ADCCK_APB2_DIV4:
374 RCU_CFG0 |= RCU_ADC_CKAPB2_DIV4;
375 RCU_CFG2 |= RCU_CFG2_ADCSEL;
376 break;
377 case RCU_ADCCK_AHB_DIV5:
378 RCU_CFG0 |= RCU_ADC_CKAPB2_DIV4;
379 RCU_CFG2 |= RCU_CFG2_ADCPSC2;
380 RCU_CFG2 |= RCU_CFG2_ADCSEL;
381 break;
382 case RCU_ADCCK_APB2_DIV6:
383 RCU_CFG0 |= RCU_ADC_CKAPB2_DIV6;
384 RCU_CFG2 |= RCU_CFG2_ADCSEL;
385 break;
386 case RCU_ADCCK_AHB_DIV7:
387 RCU_CFG0 |= RCU_ADC_CKAPB2_DIV6;
388 RCU_CFG2 |= RCU_CFG2_ADCPSC2;
389 RCU_CFG2 |= RCU_CFG2_ADCSEL;
390 break;
391 case RCU_ADCCK_APB2_DIV8:
392 RCU_CFG0 |= RCU_ADC_CKAPB2_DIV8;
393 RCU_CFG2 |= RCU_CFG2_ADCSEL;
394 break;
395 case RCU_ADCCK_AHB_DIV9:
396 RCU_CFG0 |= RCU_ADC_CKAPB2_DIV8;
397 RCU_CFG2 |= RCU_CFG2_ADCPSC2;
398 RCU_CFG2 |= RCU_CFG2_ADCSEL;
399 break;
400 default:
401 break;
402 }
403 }
404
405 /*!
406 \brief configure the USBFS clock prescaler selection
407 \param[in] ck_usbfs: USBFS clock prescaler selection
408 only one parameter can be selected which is shown as below:
409 \arg RCU_USBFS_CKPLL_DIV1_5: select CK_PLL/1.5 as CK_USBFS
410 \arg RCU_USBFS_CKPLL_DIV1: select CK_PLL as CK_USBFS
411 \arg RCU_USBFS_CKPLL_DIV2_5: select CK_PLL/2.5 as CK_USBFS
412 \arg RCU_USBFS_CKPLL_DIV2: select CK_PLL/2 as CK_USBFS
413 \arg RCU_USBFS_CKPLL_DIV3: select CK_PLL/3 as CK_USBFS
414 \arg RCU_USBFS_CKPLL_DIV3_5: select CK_PLL/3.5 as CK_USBFS
415 \param[out] none
416 \retval none
417 */
rcu_usbfs_clock_config(uint32_t ck_usbfs)418 void rcu_usbfs_clock_config(uint32_t ck_usbfs)
419 {
420 /* reset the USBFSPSC bits and set according to ck_usbfs */
421 RCU_CFG0 &= ~RCU_CFG0_USBFSPSC;
422 RCU_CFG2 &= ~RCU_CFG2_USBFSPSC2;
423
424 RCU_CFG0 |= (ck_usbfs & (~RCU_CFG2_USBFSPSC2));
425 RCU_CFG2 |= (ck_usbfs & RCU_CFG2_USBFSPSC2);
426 }
427
428 /*!
429 \brief configure the CK_OUT clock source and divider
430 \param[in] ckout_src: CK_OUT clock source selection
431 only one parameter can be selected which is shown as below:
432 \arg RCU_CKOUTSRC_NONE: no clock selected
433 \arg RCU_CKOUTSRC_IRC28M: IRC28M selected
434 \arg RCU_CKOUTSRC_IRC40K: IRC40K selected
435 \arg RCU_CKOUTSRC_LXTAL: LXTAL selected
436 \arg RCU_CKOUTSRC_CKSYS: CKSYS selected
437 \arg RCU_CKOUTSRC_IRC8M: IRC8M selected
438 \arg RCU_CKOUTSRC_HXTAL: HXTAL selected
439 \arg RCU_CKOUTSRC_CKPLL_DIV1: CK_PLL selected
440 \arg RCU_CKOUTSRC_CKPLL_DIV2: CK_PLL/2 selected
441 \param[in] ckout_div: CK_OUT divider
442 \arg RCU_CKOUT_DIVx(x=1,2,4,8,16,32,64,128): CK_OUT is divided by x
443 \param[out] none
444 \retval none
445 */
rcu_ckout_config(uint32_t ckout_src,uint32_t ckout_div)446 void rcu_ckout_config(uint32_t ckout_src, uint32_t ckout_div)
447 {
448 uint32_t ckout = 0U;
449 ckout = RCU_CFG0;
450 /* reset the CKOUTSEL, CKOUTDIV and PLLDV bits and set according to ckout_src and ckout_div */
451 ckout &= ~(RCU_CFG0_CKOUTSEL | RCU_CFG0_CKOUTDIV | RCU_CFG0_PLLDV);
452 RCU_CFG0 = (ckout | ckout_src | ckout_div);
453 }
454
455 /*!
456 \brief configure the PLL clock source preselection
457 \param[in] pll_presel: PLL clock source preselection
458 only one parameter can be selected which is shown as below:
459 \arg RCU_PLLPRESEL_IRC48M: select IRC48M as PLL preselection clock
460 \arg RCU_PLLPRESEL_HXTAL: select HXTAL as PLL preselection clock
461 \param[out] none
462 \retval none
463 */
rcu_pll_preselection_config(uint32_t pll_presel)464 void rcu_pll_preselection_config(uint32_t pll_presel)
465 {
466 RCU_CFG1 &= ~(RCU_CFG1_PLLPRESEL);
467 RCU_CFG1 |= pll_presel;
468 }
469
470 /*!
471 \brief configure the PLL clock source selection and PLL multiply factor
472 \param[in] pll_src: PLL clock source selection
473 only one parameter can be selected which is shown as below:
474 \arg RCU_PLLSRC_IRC8M_DIV2: select CK_IRC8M/2 as PLL source clock
475 \arg RCU_PLLSRC_HXTAL_IRC48M: select HXTAL or IRC48M as PLL source clock
476 \param[in] pll_mul: PLL multiply factor
477 only one parameter can be selected which is shown as below:
478 \arg RCU_PLL_MULx(x=2..64): PLL source clock * x
479 \param[out] none
480 \retval none
481 */
rcu_pll_config(uint32_t pll_src,uint32_t pll_mul)482 void rcu_pll_config(uint32_t pll_src, uint32_t pll_mul)
483 {
484 RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PLLMF | RCU_CFG0_PLLMF4);
485 RCU_CFG1 &= ~(RCU_CFG1_PLLMF5);
486 RCU_CFG0 |= (pll_src | (pll_mul & (~RCU_CFG1_PLLMF5)));
487 RCU_CFG1 |= (pll_mul & RCU_CFG1_PLLMF5);
488 }
489
490 /*!
491 \brief configure the USART clock source selection
492 \param[in] ck_usart: USART clock source selection
493 only one parameter can be selected which is shown as below:
494 \arg RCU_USART0SRC_CKAPB2: CK_USART0 select CK_APB2
495 \arg RCU_USART0SRC_CKSYS: CK_USART0 select CK_SYS
496 \arg RCU_USART0SRC_LXTAL: CK_USART0 select CK_LXTAL
497 \arg RCU_USART0SRC_IRC8M: CK_USART0 select CK_IRC8M
498 \param[out] none
499 \retval none
500 */
rcu_usart_clock_config(uint32_t ck_usart)501 void rcu_usart_clock_config(uint32_t ck_usart)
502 {
503 /* reset the USART0SEL bits and set according to ck_usart */
504 RCU_CFG2 &= ~RCU_CFG2_USART0SEL;
505 RCU_CFG2 |= ck_usart;
506 }
507
508 /*!
509 \brief configure the CEC clock source selection
510 \param[in] ck_cec: CEC clock source selection
511 only one parameter can be selected which is shown as below:
512 \arg RCU_CECSRC_IRC8M_DIV244: CK_CEC select CK_IRC8M/244
513 \arg RCU_CECSRC_LXTAL: CK_CEC select CK_LXTAL
514 \param[out] none
515 \retval none
516 */
rcu_cec_clock_config(uint32_t ck_cec)517 void rcu_cec_clock_config(uint32_t ck_cec)
518 {
519 /* reset the CECSEL bit and set according to ck_cec */
520 RCU_CFG2 &= ~RCU_CFG2_CECSEL;
521 RCU_CFG2 |= ck_cec;
522 }
523
524 /*!
525 \brief configure the RTC clock source selection
526 \param[in] rtc_clock_source: RTC clock source selection
527 only one parameter can be selected which is shown as below:
528 \arg RCU_RTCSRC_NONE: no clock selected
529 \arg RCU_RTCSRC_LXTAL: CK_LXTAL selected as RTC source clock
530 \arg RCU_RTCSRC_IRC40K: CK_IRC40K selected as RTC source clock
531 \arg RCU_RTCSRC_HXTAL_DIV32: CK_HXTAL/32 selected as RTC source clock
532 \param[out] none
533 \retval none
534 */
rcu_rtc_clock_config(uint32_t rtc_clock_source)535 void rcu_rtc_clock_config(uint32_t rtc_clock_source)
536 {
537 /* reset the RTCSRC bits and set according to rtc_clock_source */
538 RCU_BDCTL &= ~RCU_BDCTL_RTCSRC;
539 RCU_BDCTL |= rtc_clock_source;
540 }
541
542 /*!
543 \brief configure the CK48M clock source selection
544 \param[in] ck48m_clock_source: CK48M clock source selection
545 only one parameter can be selected which is shown as below:
546 \arg RCU_CK48MSRC_PLL48M: CK_PLL48M selected as CK48M source clock
547 \arg RCU_CK48MSRC_IRC48M: CK_IRC48M selected as CK48M source clock
548 \param[out] none
549 \retval none
550 */
rcu_ck48m_clock_config(uint32_t ck48m_clock_source)551 void rcu_ck48m_clock_config(uint32_t ck48m_clock_source)
552 {
553 uint32_t reg;
554
555 reg = RCU_ADDCTL;
556 /* reset the CK48MSEL bit and set according to ck48m_clock_source */
557 reg &= ~RCU_ADDCTL_CK48MSEL;
558 RCU_ADDCTL = (reg | ck48m_clock_source);
559 }
560
561 /*!
562 \brief configure the HXTAL divider used as input of PLL
563 \param[in] hxtal_prediv: HXTAL divider used as input of PLL
564 only one parameter can be selected which is shown as below:
565 \arg RCU_PLL_PREDVx(x=1..16): HXTAL or IRC48M divided x used as input of PLL
566 \param[out] none
567 \retval none
568 */
rcu_hxtal_prediv_config(uint32_t hxtal_prediv)569 void rcu_hxtal_prediv_config(uint32_t hxtal_prediv)
570 {
571 uint32_t prediv = 0U;
572 prediv = RCU_CFG1;
573 /* reset the HXTALPREDV bits and set according to hxtal_prediv */
574 prediv &= ~RCU_CFG1_PREDV;
575 RCU_CFG1 = (prediv | hxtal_prediv);
576 }
577
578 /*!
579 \brief configure the LXTAL drive capability
580 \param[in] lxtal_dricap: drive capability of LXTAL
581 only one parameter can be selected which is shown as below:
582 \arg RCU_LXTAL_LOWDRI: lower driving capability
583 \arg RCU_LXTAL_MED_LOWDRI: medium low driving capability
584 \arg RCU_LXTAL_MED_HIGHDRI: medium high driving capability
585 \arg RCU_LXTAL_HIGHDRI: higher driving capability
586 \param[out] none
587 \retval none
588 */
rcu_lxtal_drive_capability_config(uint32_t lxtal_dricap)589 void rcu_lxtal_drive_capability_config(uint32_t lxtal_dricap)
590 {
591 /* reset the LXTALDRI bits and set according to lxtal_dricap */
592 RCU_BDCTL &= ~RCU_BDCTL_LXTALDRI;
593 RCU_BDCTL |= lxtal_dricap;
594 }
595
596 /*!
597 \brief get the clock stabilization and periphral reset flags
598 \param[in] flag: the clock stabilization and periphral reset flags, refer to rcu_flag_enum
599 only one parameter can be selected which is shown as below:
600 \arg RCU_FLAG_IRC40KSTB: IRC40K stabilization flag
601 \arg RCU_FLAG_LXTALSTB: LXTAL stabilization flag
602 \arg RCU_FLAG_IRC8MSTB: IRC8M stabilization flag
603 \arg RCU_FLAG_HXTALSTB: HXTAL stabilization flag
604 \arg RCU_FLAG_PLLSTB: PLL stabilization flag
605 \arg RCU_FLAG_IRC28MSTB: IRC28M stabilization flag
606 \arg RCU_FLAG_IRC48MSTB: IRC48M stabilization flag
607 \arg RCU_FLAG_V12RST: V12 domain power reset flag
608 \arg RCU_FLAG_OBLRST: option byte loader reset flag
609 \arg RCU_FLAG_EPRST: external pin reset flag
610 \arg RCU_FLAG_PORRST: power reset flag
611 \arg RCU_FLAG_SWRST: software reset flag
612 \arg RCU_FLAG_FWDGTRST: free watchdog timer reset flag
613 \arg RCU_FLAG_WWDGTRST: window watchdog timer reset flag
614 \arg RCU_FLAG_LPRST: low-power reset flag
615 \param[out] none
616 \retval FlagStatus: SET or RESET
617 */
rcu_flag_get(rcu_flag_enum flag)618 FlagStatus rcu_flag_get(rcu_flag_enum flag)
619 {
620 if(RESET != (RCU_REG_VAL(flag) & BIT(RCU_BIT_POS(flag)))){
621 return SET;
622 }else{
623 return RESET;
624 }
625 }
626
627 /*!
628 \brief clear the reset flag
629 \param[in] none
630 \param[out] none
631 \retval none
632 */
rcu_all_reset_flag_clear(void)633 void rcu_all_reset_flag_clear(void)
634 {
635 RCU_RSTSCK |= RCU_RSTSCK_RSTFC;
636 }
637
638 /*!
639 \brief get the clock stabilization interrupt and ckm flags
640 \param[in] int_flag: interrupt and ckm flags, refer to rcu_int_flag_enum
641 only one parameter can be selected which is shown as below:
642 \arg RCU_INT_FLAG_IRC40KSTB: IRC40K stabilization interrupt flag
643 \arg RCU_INT_FLAG_LXTALSTB: LXTAL stabilization interrupt flag
644 \arg RCU_INT_FLAG_IRC8MSTB: IRC8M stabilization interrupt flag
645 \arg RCU_INT_FLAG_HXTALSTB: HXTAL stabilization interrupt flag
646 \arg RCU_INT_FLAG_PLLSTB: PLL stabilization interrupt flag
647 \arg RCU_INT_FLAG_IRC28MSTB: IRC28M stabilization interrupt flag
648 \arg RCU_INT_FLAG_IRC48MSTB: IRC48M stabilization interrupt flag
649 \arg RCU_INT_FLAG_CKM: HXTAL clock stuck interrupt flag
650 \param[out] none
651 \retval FlagStatus: SET or RESET
652 */
rcu_interrupt_flag_get(rcu_int_flag_enum int_flag)653 FlagStatus rcu_interrupt_flag_get(rcu_int_flag_enum int_flag)
654 {
655 if(RESET != (RCU_REG_VAL(int_flag) & BIT(RCU_BIT_POS(int_flag)))){
656 return SET;
657 }else{
658 return RESET;
659 }
660 }
661
662 /*!
663 \brief clear the interrupt flags
664 \param[in] int_flag_clear: clock stabilization and stuck interrupt flags clear, refer to rcu_int_flag_clear_enum
665 only one parameter can be selected which is shown as below:
666 \arg RCU_INT_FLAG_IRC40KSTB_CLR: IRC40K stabilization interrupt flag clear
667 \arg RCU_INT_FLAG_LXTALSTB_CLR: LXTAL stabilization interrupt flag clear
668 \arg RCU_INT_FLAG_IRC8MSTB_CLR: IRC8M stabilization interrupt flag clear
669 \arg RCU_INT_FLAG_HXTALSTB_CLR: HXTAL stabilization interrupt flag clear
670 \arg RCU_INT_FLAG_PLLSTB_CLR: PLL stabilization interrupt flag clear
671 \arg RCU_INT_FLAG_IRC28MSTB_CLR: IRC28M stabilization interrupt flag clear
672 \arg RCU_INT_FLAG_IRC48MSTB_CLR: IRC48M stabilization interrupt flag clear
673 \arg RCU_INT_FLAG_CKM_CLR: clock stuck interrupt flag clear
674 \param[out] none
675 \retval none
676 */
rcu_interrupt_flag_clear(rcu_int_flag_clear_enum int_flag_clear)677 void rcu_interrupt_flag_clear(rcu_int_flag_clear_enum int_flag_clear)
678 {
679 RCU_REG_VAL(int_flag_clear) |= BIT(RCU_BIT_POS(int_flag_clear));
680 }
681
682 /*!
683 \brief enable the stabilization interrupt
684 \param[in] stab_int: clock stabilization interrupt, refer to rcu_int_enum
685 only one parameter can be selected which is shown as below:
686 \arg RCU_INT_IRC40KSTB: IRC40K stabilization interrupt enable
687 \arg RCU_INT_LXTALSTB: LXTAL stabilization interrupt enable
688 \arg RCU_INT_IRC8MSTB: IRC8M stabilization interrupt enable
689 \arg RCU_INT_HXTALSTB: HXTAL stabilization interrupt enable
690 \arg RCU_INT_PLLSTB: PLL stabilization interrupt enable
691 \arg RCU_INT_IRC28MSTB: IRC28M stabilization interrupt enable
692 \arg RCU_INT_IRC48MSTB: IRC48M stabilization interrupt enable
693 \param[out] none
694 \retval none
695 */
rcu_interrupt_enable(rcu_int_enum stab_int)696 void rcu_interrupt_enable(rcu_int_enum stab_int)
697 {
698 RCU_REG_VAL(stab_int) |= BIT(RCU_BIT_POS(stab_int));
699 }
700
701
702 /*!
703 \brief disable the stabilization interrupt
704 \param[in] stab_int: clock stabilization interrupt, refer to rcu_int_enum
705 only one parameter can be selected which is shown as below:
706 \arg RCU_INT_IRC40KSTB: IRC40K stabilization interrupt disable
707 \arg RCU_INT_LXTALSTB: LXTAL stabilization interrupt disable
708 \arg RCU_INT_IRC8MSTB: IRC8M stabilization interrupt disable
709 \arg RCU_INT_HXTALSTB: HXTAL stabilization interrupt disable
710 \arg RCU_INT_PLLSTB: PLL stabilization interrupt disable
711 \arg RCU_INT_IRC28MSTB: IRC28M stabilization interrupt disable
712 \arg RCU_INT_IRC48MSTB: IRC48M stabilization interrupt disable
713 \param[out] none
714 \retval none
715 */
rcu_interrupt_disable(rcu_int_enum stab_int)716 void rcu_interrupt_disable(rcu_int_enum stab_int)
717 {
718 RCU_REG_VAL(stab_int) &= ~BIT(RCU_BIT_POS(stab_int));
719 }
720
721 /*!
722 \brief wait until oscillator stabilization flags is SET
723 \param[in] osci: oscillator types, refer to rcu_osci_type_enum
724 only one parameter can be selected which is shown as below:
725 \arg RCU_HXTAL: HXTAL
726 \arg RCU_LXTAL: LXTAL
727 \arg RCU_IRC8M: IRC8M
728 \arg RCU_IRC28M: IRC28M
729 \arg RCU_IRC48M: IRC48M
730 \arg RCU_IRC40K: IRC40K
731 \arg RCU_PLL_CK: PLL
732 \param[out] none
733 \retval ErrStatus: SUCCESS or ERROR
734 */
rcu_osci_stab_wait(rcu_osci_type_enum osci)735 ErrStatus rcu_osci_stab_wait(rcu_osci_type_enum osci)
736 {
737 uint32_t stb_cnt = 0U;
738 ErrStatus reval = ERROR;
739 FlagStatus osci_stat = RESET;
740 switch(osci){
741 case RCU_HXTAL:
742 /* wait until HXTAL is stabilization and osci_stat is not more than timeout */
743 while((RESET == osci_stat) && (HXTAL_STARTUP_TIMEOUT != stb_cnt)){
744 osci_stat = rcu_flag_get(RCU_FLAG_HXTALSTB);
745 stb_cnt++;
746 }
747 if(RESET != rcu_flag_get(RCU_FLAG_HXTALSTB)){
748 reval = SUCCESS;
749 }
750 break;
751 /* wait LXTAL stable */
752 case RCU_LXTAL:
753 while((RESET == osci_stat) && (LXTAL_STARTUP_TIMEOUT != stb_cnt)){
754 osci_stat = rcu_flag_get(RCU_FLAG_LXTALSTB);
755 stb_cnt++;
756 }
757
758 /* check whether flag is set or not */
759 if(RESET != rcu_flag_get(RCU_FLAG_LXTALSTB)){
760 reval = SUCCESS;
761 }
762 break;
763
764 /* wait IRC8M stable */
765 case RCU_IRC8M:
766 while((RESET == osci_stat) && (IRC8M_STARTUP_TIMEOUT != stb_cnt)){
767 osci_stat = rcu_flag_get(RCU_FLAG_IRC8MSTB);
768 stb_cnt++;
769 }
770
771 /* check whether flag is set or not */
772 if(RESET != rcu_flag_get(RCU_FLAG_IRC8MSTB)){
773 reval = SUCCESS;
774 }
775 break;
776
777 /* wait IRC28M stable */
778 case RCU_IRC28M:
779 while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)){
780 osci_stat = rcu_flag_get(RCU_FLAG_IRC28MSTB);
781 stb_cnt++;
782 }
783
784 /* check whether flag is set or not */
785 if(RESET != rcu_flag_get(RCU_FLAG_IRC28MSTB)){
786 reval = SUCCESS;
787 }
788 break;
789 /* wait IRC48M stable */
790 case RCU_IRC48M:
791 while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)){
792 osci_stat = rcu_flag_get(RCU_FLAG_IRC48MSTB);
793 stb_cnt++;
794 }
795
796 /* check whether flag is set or not */
797 if (RESET != rcu_flag_get(RCU_FLAG_IRC48MSTB)){
798 reval = SUCCESS;
799 }
800 break;
801
802 /* wait IRC40K stable */
803 case RCU_IRC40K:
804 while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)){
805 osci_stat = rcu_flag_get(RCU_FLAG_IRC40KSTB);
806 stb_cnt++;
807 }
808
809 /* check whether flag is set or not */
810 if(RESET != rcu_flag_get(RCU_FLAG_IRC40KSTB)){
811 reval = SUCCESS;
812 }
813 break;
814
815 /* wait PLL stable */
816 case RCU_PLL_CK:
817 while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)){
818 osci_stat = rcu_flag_get(RCU_FLAG_PLLSTB);
819 stb_cnt++;
820 }
821
822 /* check whether flag is set or not */
823 if(RESET != rcu_flag_get(RCU_FLAG_PLLSTB)){
824 reval = SUCCESS;
825 }
826 break;
827
828 default:
829 break;
830 }
831 /* return value */
832 return reval;
833 }
834
835 /*!
836 \brief turn on the oscillator
837 \param[in] osci: oscillator types, refer to rcu_osci_type_enum
838 only one parameter can be selected which is shown as below:
839 \arg RCU_HXTAL: HXTAL
840 \arg RCU_LXTAL: LXTAL
841 \arg RCU_IRC8M: IRC8M
842 \arg RCU_IRC28M: IRC28M
843 \arg RCU_IRC48M: IRC48M
844 \arg RCU_IRC40K: IRC40K
845 \arg RCU_PLL_CK: PLL
846 \param[out] none
847 \retval none
848 */
rcu_osci_on(rcu_osci_type_enum osci)849 void rcu_osci_on(rcu_osci_type_enum osci)
850 {
851 RCU_REG_VAL(osci) |= BIT(RCU_BIT_POS(osci));
852 }
853
854 /*!
855 \brief turn off the oscillator
856 \param[in] osci: oscillator types, refer to rcu_osci_type_enum
857 only one parameter can be selected which is shown as below:
858 \arg RCU_HXTAL: HXTAL
859 \arg RCU_LXTAL: LXTAL
860 \arg RCU_IRC8M: IRC8M
861 \arg RCU_IRC28M: IRC28M
862 \arg RCU_IRC48M: IRC48M
863 \arg RCU_IRC40K: IRC40K
864 \arg RCU_PLL_CK: PLL
865 \param[out] none
866 \retval none
867 */
rcu_osci_off(rcu_osci_type_enum osci)868 void rcu_osci_off(rcu_osci_type_enum osci)
869 {
870 RCU_REG_VAL(osci) &= ~BIT(RCU_BIT_POS(osci));
871 }
872
873 /*!
874 \brief enable the oscillator bypass mode, HXTALEN or LXTALEN must be reset before it
875 \param[in] osci: oscillator types, refer to rcu_osci_type_enum
876 only one parameter can be selected which is shown as below:
877 \arg RCU_HXTAL: HXTAL
878 \arg RCU_LXTAL: LXTAL
879 \param[out] none
880 \retval none
881 */
rcu_osci_bypass_mode_enable(rcu_osci_type_enum osci)882 void rcu_osci_bypass_mode_enable(rcu_osci_type_enum osci)
883 {
884 uint32_t reg;
885 switch(osci){
886 case RCU_HXTAL:
887 /* HXTALEN must be reset before enable the oscillator bypass mode */
888 reg = RCU_CTL0;
889 RCU_CTL0 &= ~RCU_CTL0_HXTALEN;
890 RCU_CTL0 = (reg | RCU_CTL0_HXTALBPS);
891 break;
892 case RCU_LXTAL:
893 /* LXTALEN must be reset before enable the oscillator bypass mode */
894 reg = RCU_BDCTL;
895 RCU_BDCTL &= ~RCU_BDCTL_LXTALEN;
896 RCU_BDCTL = (reg | RCU_BDCTL_LXTALBPS);
897 break;
898 case RCU_IRC8M:
899 case RCU_IRC28M:
900 case RCU_IRC48M:
901 case RCU_IRC40K:
902 case RCU_PLL_CK:
903 break;
904 default:
905 break;
906 }
907 }
908
909 /*!
910 \brief disable the oscillator bypass mode, HXTALEN or LXTALEN must be reset before it
911 \param[in] osci: oscillator types, refer to rcu_osci_type_enum
912 only one parameter can be selected which is shown as below:
913 \arg RCU_HXTAL: HXTAL
914 \arg RCU_LXTAL: LXTAL
915 \param[out] none
916 \retval none
917 */
rcu_osci_bypass_mode_disable(rcu_osci_type_enum osci)918 void rcu_osci_bypass_mode_disable(rcu_osci_type_enum osci)
919 {
920 uint32_t reg;
921 switch(osci){
922 case RCU_HXTAL:
923 /* HXTALEN must be reset before disable the oscillator bypass mode */
924 reg = RCU_CTL0;
925 RCU_CTL0 &= ~RCU_CTL0_HXTALEN;
926 RCU_CTL0 = (reg & (~RCU_CTL0_HXTALBPS));
927 break;
928 case RCU_LXTAL:
929 /* LXTALEN must be reset before disable the oscillator bypass mode */
930 reg = RCU_BDCTL;
931 RCU_BDCTL &= ~RCU_BDCTL_LXTALEN;
932 RCU_BDCTL = (reg & (~RCU_BDCTL_LXTALBPS));
933 break;
934 case RCU_IRC8M:
935 case RCU_IRC28M:
936 case RCU_IRC48M:
937 case RCU_IRC40K:
938 case RCU_PLL_CK:
939 break;
940 default:
941 break;
942 }
943 }
944
945 /*!
946 \brief enable the HXTAL clock monitor
947 \param[in] none
948 \param[out] none
949 \retval none
950 */
rcu_hxtal_clock_monitor_enable(void)951 void rcu_hxtal_clock_monitor_enable(void)
952 {
953 RCU_CTL0 |= RCU_CTL0_CKMEN;
954 }
955
956 /*!
957 \brief disable the HXTAL clock monitor
958 \param[in] none
959 \param[out] none
960 \retval none
961 */
rcu_hxtal_clock_monitor_disable(void)962 void rcu_hxtal_clock_monitor_disable(void)
963 {
964 RCU_CTL0 &= ~RCU_CTL0_CKMEN;
965 }
966
967 /*!
968 \brief set the IRC8M adjust value
969 \param[in] irc8m_adjval: IRC8M adjust value, must be between 0 and 0x1F
970 \param[out] none
971 \retval none
972 */
rcu_irc8m_adjust_value_set(uint8_t irc8m_adjval)973 void rcu_irc8m_adjust_value_set(uint8_t irc8m_adjval)
974 {
975 uint32_t adjust = 0U;
976 adjust = RCU_CTL0;
977 /* reset the IRC8MADJ bits and set according to irc8m_adjval */
978 adjust &= ~RCU_CTL0_IRC8MADJ;
979 RCU_CTL0 = (adjust | (((uint32_t)irc8m_adjval)<<3));
980 }
981
982 /*!
983 \brief set the IRC28M adjust value
984 \param[in] irc28m_adjval: IRC28M adjust value, must be between 0 and 0x1F
985 \param[out] none
986 \retval none
987 */
rcu_irc28m_adjust_value_set(uint8_t irc28m_adjval)988 void rcu_irc28m_adjust_value_set(uint8_t irc28m_adjval)
989 {
990 uint32_t adjust = 0U;
991 adjust = RCU_CTL1;
992 /* reset the IRC28MADJ bits and set according to irc28m_adjval */
993 adjust &= ~RCU_CTL1_IRC28MADJ;
994 RCU_CTL1 = (adjust | (((uint32_t)irc28m_adjval)<<3));
995 }
996
997 /*!
998 \brief unlock the voltage key
999 \param[in] none
1000 \param[out] none
1001 \retval none
1002 */
rcu_voltage_key_unlock(void)1003 void rcu_voltage_key_unlock(void)
1004 {
1005 /* reset the KEY bits and set 0x1A2B3C4D */
1006 RCU_VKEY &= ~RCU_VKEY_KEY;
1007 RCU_VKEY |= RCU_VKEY_UNLOCK;
1008 }
1009
1010 /*!
1011 \brief set voltage in deep sleep mode
1012 \param[in] dsvol: deep sleep mode voltage
1013 only one parameter can be selected which is shown as below:
1014 \arg RCU_DEEPSLEEP_V_1_0: the core voltage is 1.0V
1015 \arg RCU_DEEPSLEEP_V_0_9: the core voltage is 0.9V(customers are not recommended to use it)
1016 \arg RCU_DEEPSLEEP_V_0_8: the core voltage is 0.8V(customers are not recommended to use it)
1017 \arg RCU_DEEPSLEEP_V_0_7: the core voltage is 0.7V(customers are not recommended to use it)
1018 \param[out] none
1019 \retval none
1020 */
rcu_deepsleep_voltage_set(uint32_t dsvol)1021 void rcu_deepsleep_voltage_set(uint32_t dsvol)
1022 {
1023 /* reset the DSLPVS bits and set according to dsvol */
1024 RCU_DSV &= ~RCU_DSV_DSLPVS;
1025 RCU_DSV |= dsvol;
1026 }
1027
1028 /*!
1029 \brief get the system clock, bus and peripheral clock frequency
1030 \param[in] clock: the clock frequency which to get
1031 only one parameter can be selected which is shown as below:
1032 \arg CK_SYS: system clock frequency
1033 \arg CK_AHB: AHB clock frequency
1034 \arg CK_APB1: APB1 clock frequency
1035 \arg CK_APB2: APB2 clock frequency
1036 \arg CK_ADC: ADC clock frequency
1037 \arg CK_CEC: CEC clock frequency
1038 \arg CK_USART: USART clock frequency
1039 \param[out] none
1040 \retval clock frequency of system, AHB, APB1, APB2, ADC, CEC or USRAT
1041 */
rcu_clock_freq_get(rcu_clock_freq_enum clock)1042 uint32_t rcu_clock_freq_get(rcu_clock_freq_enum clock)
1043 {
1044 uint32_t sws = 0U, adcps = 0U, adcps2 = 0U, ck_freq = 0U;
1045 uint32_t cksys_freq = 0U, ahb_freq = 0U, apb1_freq = 0U, apb2_freq = 0U;
1046 uint32_t adc_freq = 0U, cec_freq = 0U, usart_freq = 0U;
1047 uint32_t pllmf = 0U, pllmf4 = 0U, pllmf5 = 0U, pllsel = 0U, pllpresel = 0U, prediv = 0U, idx = 0U, clk_exp = 0U;
1048 /* exponent of AHB, APB1 and APB2 clock divider */
1049 const uint8_t ahb_exp[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
1050 const uint8_t apb1_exp[8] = {0, 0, 0, 0, 1, 2, 3, 4};
1051 const uint8_t apb2_exp[8] = {0, 0, 0, 0, 1, 2, 3, 4};
1052
1053 sws = GET_BITS(RCU_CFG0, 2, 3);
1054 switch(sws){
1055 /* IRC8M is selected as CK_SYS */
1056 case SEL_IRC8M:
1057 cksys_freq = IRC8M_VALUE;
1058 break;
1059 /* HXTAL is selected as CK_SYS */
1060 case SEL_HXTAL:
1061 cksys_freq = HXTAL_VALUE;
1062 break;
1063 /* PLL is selected as CK_SYS */
1064 case SEL_PLL:
1065 /* get the value of PLLMF[3:0] */
1066 pllmf = GET_BITS(RCU_CFG0, 18, 21);
1067 pllmf4 = GET_BITS(RCU_CFG0, 27, 27);
1068 pllmf5 = GET_BITS(RCU_CFG1, 31, 31);
1069 /* high 16 bits */
1070 /* high 16 bits */
1071 if((0U == pllmf4)&&(0U == pllmf5)){
1072 pllmf += 2U;
1073 }
1074 if((1U == pllmf4)&&(0U == pllmf5)){
1075 pllmf += 17U;
1076 }
1077 if((0U == pllmf4)&&(1U == pllmf5)){
1078 pllmf += 33U;
1079 }
1080 if((1U == pllmf4)&&(1U == pllmf5)){
1081 pllmf += 49U;
1082 }
1083
1084 /* PLL clock source selection, HXTAL or IRC48M or IRC8M/2 */
1085 pllsel = GET_BITS(RCU_CFG0, 16, 16);
1086 pllpresel = GET_BITS(RCU_CFG1, 30, 30);
1087 if(0U != pllsel){
1088 prediv = (GET_BITS(RCU_CFG1,0, 3) + 1U);
1089 if(0U == pllpresel){
1090 cksys_freq = (HXTAL_VALUE / prediv) * pllmf;
1091 }else{
1092 cksys_freq = (IRC48M_VALUE / prediv) * pllmf;
1093 }
1094 }else{
1095 cksys_freq = (IRC8M_VALUE >> 1) * pllmf;
1096 }
1097 break;
1098 /* IRC8M is selected as CK_SYS */
1099 default:
1100 cksys_freq = IRC8M_VALUE;
1101 break;
1102 }
1103 /* calculate AHB clock frequency */
1104 idx = GET_BITS(RCU_CFG0, 4, 7);
1105 clk_exp = ahb_exp[idx];
1106 ahb_freq = cksys_freq >> clk_exp;
1107
1108 /* calculate APB1 clock frequency */
1109 idx = GET_BITS(RCU_CFG0, 8, 10);
1110 clk_exp = apb1_exp[idx];
1111 apb1_freq = ahb_freq >> clk_exp;
1112
1113 /* calculate APB2 clock frequency */
1114 idx = GET_BITS(RCU_CFG0, 11, 13);
1115 clk_exp = apb2_exp[idx];
1116 apb2_freq = ahb_freq >> clk_exp;
1117
1118 /* return the clocks frequency */
1119 switch(clock){
1120 case CK_SYS:
1121 ck_freq = cksys_freq;
1122 break;
1123 case CK_AHB:
1124 ck_freq = ahb_freq;
1125 break;
1126 case CK_APB1:
1127 ck_freq = apb1_freq;
1128 break;
1129 case CK_APB2:
1130 ck_freq = apb2_freq;
1131 break;
1132 case CK_ADC:
1133 /* calculate ADC clock frequency */
1134 if(RCU_ADCSRC_AHB_APB2DIV != (RCU_CFG2 & RCU_CFG2_ADCSEL)){
1135 if(RCU_ADC_IRC28M_DIV1 != (RCU_CFG2 & RCU_CFG2_IRC28MDIV)){
1136 adc_freq = IRC28M_VALUE >> 1;
1137 }else{
1138 adc_freq = IRC28M_VALUE;
1139 }
1140 }else{
1141 /* ADC clock select CK_APB2 divided by 2/4/6/8 or CK_AHB divided by 3/5/7/9 */
1142 adcps = GET_BITS(RCU_CFG0, 14, 15);
1143 adcps2 = GET_BITS(RCU_CFG2, 31, 31);
1144 switch(adcps){
1145 case 0:
1146 if(0U == adcps2){
1147 adc_freq = apb2_freq / 2U;
1148 }else{
1149 adc_freq = ahb_freq / 3U;
1150 }
1151 break;
1152 case 1:
1153 if(0U == adcps2){
1154 adc_freq = apb2_freq / 4U;
1155 }else{
1156 adc_freq = ahb_freq / 5U;
1157 }
1158 break;
1159 case 2:
1160 if(0U == adcps2){
1161 adc_freq = apb2_freq / 6U;
1162 }else{
1163 adc_freq = ahb_freq / 7U;
1164 }
1165 break;
1166 case 3:
1167 if(0U == adcps2){
1168 adc_freq = apb2_freq / 8U;
1169 }else{
1170 adc_freq = ahb_freq / 9U;
1171 }
1172 break;
1173 default:
1174 break;
1175 }
1176 }
1177 ck_freq = adc_freq;
1178 break;
1179 case CK_CEC:
1180 /* calculate CEC clock frequency */
1181 if(RCU_CECSRC_LXTAL != (RCU_CFG2 & RCU_CFG2_CECSEL)){
1182 cec_freq = IRC8M_VALUE / 244U;
1183 }else{
1184 cec_freq = LXTAL_VALUE;
1185 }
1186 ck_freq = cec_freq;
1187 break;
1188 case CK_USART:
1189 /* calculate USART clock frequency */
1190 if(RCU_USART0SRC_CKAPB2 == (RCU_CFG2 & RCU_CFG2_USART0SEL)){
1191 usart_freq = apb2_freq;
1192 }else if(RCU_USART0SRC_CKSYS == (RCU_CFG2 & RCU_CFG2_USART0SEL)){
1193 usart_freq = cksys_freq;
1194 }else if(RCU_USART0SRC_LXTAL == (RCU_CFG2 & RCU_CFG2_USART0SEL)){
1195 usart_freq = LXTAL_VALUE;
1196 }else if(RCU_USART0SRC_IRC8M == (RCU_CFG2 & RCU_CFG2_USART0SEL)){
1197 usart_freq = IRC8M_VALUE;
1198 }else{
1199 }
1200 ck_freq = usart_freq;
1201 break;
1202 default:
1203 break;
1204 }
1205 return ck_freq;
1206 }
1207