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