1 /*!
2     \file    gd32e50x_rcu.c
3     \brief   RCU driver
4 
5     \version 2020-03-10, V1.0.0, firmware for GD32E50X
6     \version 2020-08-26, V1.1.0, firmware for GD32E50x
7     \version 2020-09-20, V1.1.1, firmware for GD32E50x
8     \version 2021-03-23, V1.2.0, firmware for GD32E50x
9 */
10 
11 /*
12     Copyright (c) 2021, GigaDevice Semiconductor Inc.
13 
14     All rights reserved.
15 
16     Redistribution and use in source and binary forms, with or without modification,
17 are permitted provided that the following conditions are met:
18 
19     1. Redistributions of source code must retain the above copyright notice, this
20        list of conditions and the following disclaimer.
21     2. Redistributions in binary form must reproduce the above copyright notice,
22        this list of conditions and the following disclaimer in the documentation
23        and/or other materials provided with the distribution.
24     3. Neither the name of the copyright holder nor the names of its contributors
25        may be used to endorse or promote products derived from this software without
26        specific prior written permission.
27 
28     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
31 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
32 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
33 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
35 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
37 OF SUCH DAMAGE.
38 */
39 
40 #include "gd32e50x_rcu.h"
41 
42 /* define clock source */
43 #define SEL_IRC8M                   ((uint16_t)0U)  /* IRC8M is selected as CK_SYS */
44 #define SEL_HXTAL                   ((uint16_t)1U)  /* HXTAL is selected as CK_SYS */
45 #define SEL_PLL                     ((uint16_t)2U)  /* PLL is selected as CK_SYS */
46 
47 /* define startup timeout count */
48 #define OSC_STARTUP_TIMEOUT         ((uint32_t)0x000FFFFFU)
49 #define LXTAL_STARTUP_TIMEOUT       ((uint32_t)0x03FFFFFFU)
50 
51 /* ADC clock prescaler offset */
52 #define RCU_ADC_PSC_OFFSET          ((uint32_t)14U)
53 
54 /* RCU IRC8M adjust value mask and offset*/
55 #define RCU_IRC8M_ADJUST_MASK       ((uint8_t)0x1FU)
56 #define RCU_IRC8M_ADJUST_OFFSET     ((uint32_t)3U)
57 
58 /* RCU PLL1 clock multiplication factor offset */
59 #define RCU_CFG1_PLL1MF_OFFSET      ((uint32_t)8U)
60 /* RCU PREDV1 division factor offset*/
61 #define RCU_CFG1_PREDV1_OFFSET      ((uint32_t)4U)
62 
63 /*!
64     \brief      deinitialize the RCU
65     \param[in]  none
66     \param[out] none
67     \retval     none
68 */
rcu_deinit(void)69 void rcu_deinit(void)
70 {
71     /* enable IRC8M */
72     RCU_CTL |= RCU_CTL_IRC8MEN;
73     while(0U == (RCU_CTL & RCU_CTL_IRC8MSTB)){
74     }
75     RCU_CFG0 &= ~RCU_CFG0_SCS;
76     /* reset CTL register */
77     RCU_CTL &= ~(RCU_CTL_HXTALEN | RCU_CTL_CKMEN | RCU_CTL_PLLEN);
78     RCU_CTL &= ~RCU_CTL_HXTALBPS;
79 #if defined(GD32E50X_CL) || defined(GD32EPRT) || defined(GD32E508)
80     RCU_CTL &= ~(RCU_CTL_PLL1EN | RCU_CTL_PLL2EN);
81 #endif /* GD32E50X_CL and GD32EPRT and GD32E508 */
82     /* reset CFG0 register */
83 #if defined(GD32E50X_HD) || defined(GD32E50X_XD)
84     RCU_CFG0 &= ~(RCU_CFG0_SCS | RCU_CFG0_AHBPSC | RCU_CFG0_APB1PSC | RCU_CFG0_APB2PSC |
85                   RCU_CFG0_ADCPSC | RCU_CFG0_PLLSEL | RCU_CFG0_PREDV0 | RCU_CFG0_PLLMF |
86                   RCU_CFG0_USBDPSC | RCU_CFG0_CKOUT0SEL | RCU_CFG0_PLLMF_4 | RCU_CFG0_ADCPSC_2 | RCU_CFG0_PLLMF_5 | RCU_CFG0_USBDPSC_2);
87 #elif defined(GD32E50X_CL) || defined(GD32E508)
88     RCU_CFG0 &= ~(RCU_CFG0_SCS | RCU_CFG0_AHBPSC | RCU_CFG0_APB1PSC | RCU_CFG0_APB2PSC |
89                   RCU_CFG0_ADCPSC | RCU_CFG0_PLLSEL | RCU_CFG0_PREDV0_LSB | RCU_CFG0_PLLMF |
90                   RCU_CFG0_USBHSPSC | RCU_CFG0_CKOUT0SEL | RCU_CFG0_ADCPSC_2 | RCU_CFG0_PLLMF_4 | RCU_CFG0_PLLMF_5 | RCU_CFG0_USBHSPSC_2);
91 #elif defined(GD32EPRT)
92     RCU_CFG0 &= ~(RCU_CFG0_SCS | RCU_CFG0_AHBPSC | RCU_CFG0_APB1PSC | RCU_CFG0_APB2PSC |
93                   RCU_CFG0_ADCPSC | RCU_CFG0_PLLSEL | RCU_CFG0_PREDV0_LSB | RCU_CFG0_PLLMF |
94                   RCU_CFG0_USBDPSC | RCU_CFG0_CKOUT0SEL | RCU_CFG0_ADCPSC_2 | RCU_CFG0_PLLMF_4 | RCU_CFG0_PLLMF_5 | RCU_CFG0_USBDPSC_2);
95 #endif /* GD32E50X_HD and GD32E50X_XD */
96 
97     /* reset INT and CFG1 register */
98 #if defined(GD32E50X_HD) || defined(GD32E50X_XD)
99     RCU_INT = 0x009f0000U;
100     RCU_CFG1 &= ~(RCU_CFG1_ADCPSC_3 | RCU_CFG1_PLLPRESEL);
101     RCU_CFG2 &= ~(RCU_CFG2_USART5SEL | RCU_CFG2_I2C2SEL);
102 #elif defined(GD32E50X_CL) || defined(GD32E508)
103     RCU_INT = 0x00ff0000U;
104     RCU_ADDINT = 0x00C00000U;
105     RCU_ADDCTL &= ~(RCU_ADDCTL_CK48MSEL | RCU_ADDCTL_USBHSSEL | RCU_ADDCTL_USBHSDV | RCU_ADDCTL_USBSWEN | RCU_ADDCTL_PLLUSBEN | RCU_ADDCTL_IRC48MEN);
106     RCU_ADDCFG &= ~(RCU_ADDCFG_PLLUSBPREDV | RCU_ADDCFG_PLLUSBPRESEL | RCU_ADDCFG_PLLUSBPREDVSEL | RCU_ADDCFG_PLLUSBMF);
107 
108     RCU_CFG1 &= ~(RCU_CFG1_PREDV0 | RCU_CFG1_PREDV1 | RCU_CFG1_PLL1MF | RCU_CFG1_PLL2MF |
109                   RCU_CFG1_PREDV0SEL | RCU_CFG1_I2S1SEL | RCU_CFG1_I2S2SEL | RCU_CFG1_SHRTIMERSEL | RCU_CFG1_PLL2MF_5 | RCU_CFG1_ADCPSC_3 |
110                   RCU_CFG1_PLLPRESEL | RCU_CFG1_PLL2MF_4);
111     RCU_CFG2 &= ~(RCU_CFG2_USART5SEL | RCU_CFG2_I2C2SEL);
112 #elif defined(GD32EPRT)
113     RCU_INT = 0x00ff0000U;
114     RCU_ADDINT &= ~ (RCU_ADDINT_IRC48MSTBIC);
115     RCU_ADDCTL &= ~(RCU_ADDCTL_CK48MSEL | RCU_ADDCTL_IRC48MEN);
116 
117     RCU_CFG1 &= ~(RCU_CFG1_PREDV0 | RCU_CFG1_PREDV1 | RCU_CFG1_PLL1MF | RCU_CFG1_PLL2MF |
118                   RCU_CFG1_PREDV0SEL | RCU_CFG1_I2S1SEL | RCU_CFG1_I2S2SEL | RCU_CFG1_PLL2MF_5 | RCU_CFG1_ADCPSC_3 |
119                   RCU_CFG1_PLLPRESEL | RCU_CFG1_PLL2MF_4);
120     RCU_CFG2 &= ~(RCU_CFG2_USART5SEL | RCU_CFG2_I2C2SEL);
121 
122 #endif /* GD32E50X_HD and GD32E50X_XD */
123 }
124 
125 /*!
126     \brief      enable the peripherals clock
127     \param[in]  periph: RCU peripherals, refer to rcu_periph_enum
128                 only one parameter can be selected which is shown as below:
129       \arg        RCU_GPIOx (x=A,B,C,D,E,F,G): GPIO ports clock
130       \arg        RCU_AF : alternate function clock
131       \arg        RCU_CRC: CRC clock
132       \arg        RCU_DMAx (x=0,1): DMA clock
133       \arg        RCU_ENET: ENET clock(EPRT and CL series available)
134       \arg        RCU_ENETTX: ENETTX clock(EPRT and CL series available)
135       \arg        RCU_ENETRX: ENETRX clock(EPRT and CL series available)
136       \arg        RCU_USBD: USBD clock(HD,XD and EPRT series available)
137       \arg        RCU_USBHS: USBHS clock(CL series available)
138       \arg        RCU_TMU: TMU clock
139       \arg        RCU_SQPI: SQPI clock
140       \arg        RCU_EXMC: EXMC clock
141       \arg        RCU_TIMERx (x=0,1,2,3,4,5,6,7,8,9,10,11,12,13,TIMER8..13 are not available for EPRT series): TIMER clock
142       \arg        RCU_WWDGT: WWDGT clock
143       \arg        RCU_SPIx (x=0,1,2): SPI clock
144       \arg        RCU_USARTx (x=0,1,2,5): USART clock
145       \arg        RCU_UARTx (x=3,4): UART clock
146       \arg        RCU_I2Cx (x=0,1,2): I2C clock
147       \arg        RCU_CANx (x=0,1,2,CAN2 is only available for CL series,CANx is not avaliable for GD32EPRT): CAN clock
148       \arg        RCU_PMU: PMU clock
149       \arg        RCU_DAC: DAC clock
150       \arg        RCU_RTC: RTC clock
151       \arg        RCU_ADCx (x=0,1,2,ADC2 is not available for CL series): ADC clock
152       \arg        RCU_SDIO: SDIO clock(not available for CL and EPRT series)
153       \arg        RCU_CTC: CTC clock
154       \arg        RCU_BKPI: BKP interface clock
155       \arg        RCU_SHRTIMER: (not available for EPRT series):SHRTIMER clock
156       \arg        RCU_CMP(CMP is only available for CL series):CMP clock
157     \param[out] none
158     \retval     none
159 */
rcu_periph_clock_enable(rcu_periph_enum periph)160 void rcu_periph_clock_enable(rcu_periph_enum periph)
161 {
162     RCU_REG_VAL(periph) |= BIT(RCU_BIT_POS(periph));
163 }
164 
165 /*!
166     \brief      disable the peripherals clock
167     \param[in]  periph: RCU peripherals, refer to rcu_periph_enum
168                 only one parameter can be selected which is shown as below:
169       \arg        RCU_GPIOx (x=A,B,C,D,E,F,G): GPIO ports clock
170       \arg        RCU_AF : alternate function clock
171       \arg        RCU_CRC: CRC clock
172       \arg        RCU_DMAx (x=0,1): DMA clock
173       \arg        RCU_ENET: ENET clock(EPRT and CL series available)
174       \arg        RCU_ENETTX: ENETTX clock(EPRT and CL series available)
175       \arg        RCU_ENETRX: ENETRX clock(EPRT and CL series available)
176       \arg        RCU_USBD: USBD clock(HD,XD and EPRT series available)
177       \arg        RCU_USBHS: USBHS clock(CL series available)
178       \arg        RCU_TMU: TMU clock
179       \arg        RCU_SQPI: SQPI clock
180       \arg        RCU_EXMC: EXMC clock
181       \arg        RCU_TIMERx (x=0,1,2,3,4,5,6,7,8,9,10,11,12,13,TIMER8..13 are not available for EPRT series): TIMER clock
182       \arg        RCU_WWDGT: WWDGT clock
183       \arg        RCU_SPIx (x=0,1,2): SPI clock
184       \arg        RCU_USARTx (x=0,1,2,5): USART clock
185       \arg        RCU_UARTx (x=3,4): UART clock
186       \arg        RCU_I2Cx (x=0,1,2): I2C clock
187       \arg        RCU_CANx (x=0,1,2,CAN2 is only available for CL series,CANx is not avaliable for GD32EPRT): CAN clock
188       \arg        RCU_PMU: PMU clock
189       \arg        RCU_DAC: DAC clock
190       \arg        RCU_RTC: RTC clock
191       \arg        RCU_ADCx (x=0,1,2,ADC2 is not available for CL series): ADC clock
192       \arg        RCU_SDIO: SDIO clock(not available for CL and EPRT series)
193       \arg        RCU_CTC: CTC clock
194       \arg        RCU_BKPI: BKP interface clock
195       \arg        RCU_SHRTIMER: (not available for EPRT series): SHRTIMER clock
196       \arg        RCU_CMP(CMP is only available for CL series):CMP clock
197     \param[out] none
198     \retval     none
199 */
rcu_periph_clock_disable(rcu_periph_enum periph)200 void rcu_periph_clock_disable(rcu_periph_enum periph)
201 {
202     RCU_REG_VAL(periph) &= ~BIT(RCU_BIT_POS(periph));
203 }
204 
205 /*!
206     \brief      enable the peripherals clock when sleep mode
207     \param[in]  periph: RCU peripherals, refer to rcu_periph_sleep_enum
208                 only one parameter can be selected which is shown as below:
209       \arg        RCU_FMC_SLP: FMC clock
210       \arg        RCU_SRAM_SLP: SRAM clock
211     \param[out] none
212     \retval     none
213 */
rcu_periph_clock_sleep_enable(rcu_periph_sleep_enum periph)214 void rcu_periph_clock_sleep_enable(rcu_periph_sleep_enum periph)
215 {
216     RCU_REG_VAL(periph) |= BIT(RCU_BIT_POS(periph));
217 }
218 
219 /*!
220     \brief      disable the peripherals clock when sleep mode
221     \param[in]  periph: RCU peripherals, refer to rcu_periph_sleep_enum
222                 only one parameter can be selected which is shown as below:
223       \arg        RCU_FMC_SLP: FMC clock
224       \arg        RCU_SRAM_SLP: SRAM clock
225     \param[out] none
226     \retval     none
227 */
rcu_periph_clock_sleep_disable(rcu_periph_sleep_enum periph)228 void rcu_periph_clock_sleep_disable(rcu_periph_sleep_enum periph)
229 {
230     RCU_REG_VAL(periph) &= ~BIT(RCU_BIT_POS(periph));
231 }
232 
233 /*!
234     \brief      reset the peripherals
235     \param[in]  periph_reset: RCU peripherals reset, refer to rcu_periph_reset_enum
236                 only one parameter can be selected which is shown as below:
237       \arg        RCU_GPIOxRST (x=A,B,C,D,E,F,G): reset GPIO ports
238       \arg        RCU_AFRST : reset alternate function clock
239       \arg        RCU_ENETRST: reset ENET(EPRT and CL series available)
240       \arg        RCU_USBDRST: reset USBD(HD,XD and EPRT series available)
241       \arg        RCU_USBHSRST: reset USBHS(CL series available)
242       \arg        RCU_TMURST: reset TMU
243       \arg        RCU_SQPIRST: reset SQPI
244       \arg        RCU_TIMERxRST (x=0,1,2,3,4,5,6,7,8,9,10,11,12,13,TIMER8..13 are not available for EPRT series): reset TIMER
245       \arg        RCU_WWDGTRST: reset WWDGT
246       \arg        RCU_SPIxRST (x=0,1,2): reset SPI
247       \arg        RCU_USARTxRST (x=0,1,2,5): reset USART
248       \arg        RCU_UARTxRST (x=3,4): reset UART
249       \arg        RCU_I2CxRST (x=0,1): reset I2C
250       \arg        RCU_PMURST: reset PMU
251       \arg        RCU_DACRST: reset DAC
252       \arg        RCU_ADCRST (x=0,1,2,ADC2 is not available for CL series): reset ADC
253       \arg        RCU_CTCRST: reset CTC
254       \arg        RCU_BKPIRST: reset BKPI
255       \arg        RCU_SHRTIMERRST: (not available for EPRT series):reset SHRTIMERRST
256       \arg        RCU_CMPRST(CMP is only available for CL series): reset CMP
257     \param[out] none
258     \retval     none
259 */
rcu_periph_reset_enable(rcu_periph_reset_enum periph_reset)260 void rcu_periph_reset_enable(rcu_periph_reset_enum periph_reset)
261 {
262     RCU_REG_VAL(periph_reset) |= BIT(RCU_BIT_POS(periph_reset));
263 }
264 
265 /*!
266     \brief      disable reset the peripheral
267     \param[in]  periph_reset: RCU peripherals reset, refer to rcu_periph_reset_enum
268                 only one parameter can be selected which is shown as below:
269       \arg        RCU_GPIOxRST (x=A,B,C,D,E,F,G): reset GPIO ports
270       \arg        RCU_AFRST : reset alternate function clock
271       \arg        RCU_ENETRST: reset ENET(CL series available)
272       \arg        RCU_USBDRST: reset USBD(HD,XD and EPRT series available)
273       \arg        RCU_USBHSRST: reset USBHS(CL series available)
274       \arg        RCU_TMURST: reset TMU
275       \arg        RCU_SQPIRST: reset SQPI
276       \arg        RCU_TIMERxRST (x=0,1,2,3,4,5,6,7,8,9,10,11,12,13,TIMER8..13 are not available for EPRT series): reset TIMER
277       \arg        RCU_WWDGTRST: reset WWDGT
278       \arg        RCU_SPIxRST (x=0,1,2): reset SPI
279       \arg        RCU_USARTxRST (x=0,1,2,5): reset USART
280       \arg        RCU_UARTxRST (x=3,4): reset UART
281       \arg        RCU_I2CxRST (x=0,1): reset I2C
282       \arg        RCU_PMURST: reset PMU
283       \arg        RCU_DACRST: reset DAC
284       \arg        RCU_ADCRST (x=0,1,2,ADC2 is not available for CL series): reset ADC
285       \arg        RCU_CTCRST: reset CTC
286       \arg        RCU_BKPIRST: reset BKPI
287       \arg        RCU_SHRTIMERRST: (not available for EPRT series):reset SHRTIMERRST
288       \arg        RCU_CMPRST(CMP is only available for CL series): reset CMP
289     \param[out] none
290     \retval     none
291 */
rcu_periph_reset_disable(rcu_periph_reset_enum periph_reset)292 void rcu_periph_reset_disable(rcu_periph_reset_enum periph_reset)
293 {
294     RCU_REG_VAL(periph_reset) &= ~BIT(RCU_BIT_POS(periph_reset));
295 }
296 
297 /*!
298     \brief      reset the BKP domain
299     \param[in]  none
300     \param[out] none
301     \retval     none
302 */
rcu_bkp_reset_enable(void)303 void rcu_bkp_reset_enable(void)
304 {
305     RCU_BDCTL |= RCU_BDCTL_BKPRST;
306 }
307 
308 /*!
309     \brief      disable the BKP domain reset
310     \param[in]  none
311     \param[out] none
312     \retval     none
313 */
rcu_bkp_reset_disable(void)314 void rcu_bkp_reset_disable(void)
315 {
316     RCU_BDCTL &= ~RCU_BDCTL_BKPRST;
317 }
318 
319 /*!
320     \brief      configure the system clock source
321     \param[in]  ck_sys: system clock source select
322                 only one parameter can be selected which is shown as below:
323       \arg        RCU_CKSYSSRC_IRC8M: select CK_IRC8M as the CK_SYS source
324       \arg        RCU_CKSYSSRC_HXTAL: select CK_HXTAL as the CK_SYS source
325       \arg        RCU_CKSYSSRC_PLL: select CK_PLL as the CK_SYS source
326     \param[out] none
327     \retval     none
328 */
rcu_system_clock_source_config(uint32_t ck_sys)329 void rcu_system_clock_source_config(uint32_t ck_sys)
330 {
331     uint32_t reg;
332 
333     reg = RCU_CFG0;
334     /* reset the SCS bits and set according to ck_sys */
335     reg &= ~RCU_CFG0_SCS;
336     RCU_CFG0 = (reg | ck_sys);
337 }
338 
339 /*!
340     \brief      get the system clock source
341     \param[in]  none
342     \param[out] none
343     \retval     which clock is selected as CK_SYS source
344       \arg        RCU_SCSS_IRC8M: CK_IRC8M is selected as the CK_SYS source
345       \arg        RCU_SCSS_HXTAL: CK_HXTAL is selected as the CK_SYS source
346       \arg        RCU_SCSS_PLL: CK_PLL is selected as the CK_SYS source
347 */
rcu_system_clock_source_get(void)348 uint32_t rcu_system_clock_source_get(void)
349 {
350     return (RCU_CFG0 & RCU_CFG0_SCSS);
351 }
352 
353 /*!
354     \brief      configure the AHB clock prescaler selection
355     \param[in]  ck_ahb: AHB clock prescaler selection
356                 only one parameter can be selected which is shown as below:
357       \arg        RCU_AHB_CKSYS_DIVx, x=1, 2, 4, 8, 16, 64, 128, 256, 512
358     \param[out] none
359     \retval     none
360 */
rcu_ahb_clock_config(uint32_t ck_ahb)361 void rcu_ahb_clock_config(uint32_t ck_ahb)
362 {
363     uint32_t reg;
364 
365     reg = RCU_CFG0;
366 
367     /* reset the AHBPSC bits and set according to ck_ahb */
368     reg &= ~RCU_CFG0_AHBPSC;
369     RCU_CFG0 = (reg | ck_ahb);
370 }
371 
372 /*!
373     \brief      configure the APB1 clock prescaler selection
374     \param[in]  ck_apb1: APB1 clock prescaler selection
375                 only one parameter can be selected which is shown as below:
376       \arg        RCU_APB1_CKAHB_DIV1: select CK_AHB as CK_APB1
377       \arg        RCU_APB1_CKAHB_DIV2: select CK_AHB/2 as CK_APB1
378       \arg        RCU_APB1_CKAHB_DIV4: select CK_AHB/4 as CK_APB1
379       \arg        RCU_APB1_CKAHB_DIV8: select CK_AHB/8 as CK_APB1
380       \arg        RCU_APB1_CKAHB_DIV16: select CK_AHB/16 as CK_APB1
381     \param[out] none
382     \retval     none
383 */
rcu_apb1_clock_config(uint32_t ck_apb1)384 void rcu_apb1_clock_config(uint32_t ck_apb1)
385 {
386     uint32_t reg;
387 
388     reg = RCU_CFG0;
389 
390     /* reset the APB1PSC and set according to ck_apb1 */
391     reg &= ~RCU_CFG0_APB1PSC;
392     RCU_CFG0 = (reg | ck_apb1);
393 }
394 
395 /*!
396     \brief      configure the APB2 clock prescaler selection
397     \param[in]  ck_apb2: APB2 clock prescaler selection
398                 only one parameter can be selected which is shown as below:
399       \arg        RCU_APB2_CKAHB_DIV1: select CK_AHB as CK_APB2
400       \arg        RCU_APB2_CKAHB_DIV2: select CK_AHB/2 as CK_APB2
401       \arg        RCU_APB2_CKAHB_DIV4: select CK_AHB/4 as CK_APB2
402       \arg        RCU_APB2_CKAHB_DIV8: select CK_AHB/8 as CK_APB2
403       \arg        RCU_APB2_CKAHB_DIV16: select CK_AHB/16 as CK_APB2
404     \param[out] none
405     \retval     none
406 */
rcu_apb2_clock_config(uint32_t ck_apb2)407 void rcu_apb2_clock_config(uint32_t ck_apb2)
408 {
409     uint32_t reg;
410 
411     reg = RCU_CFG0;
412 
413     /* reset the APB2PSC and set according to ck_apb2 */
414     reg &= ~RCU_CFG0_APB2PSC;
415     RCU_CFG0 = (reg | ck_apb2);
416 }
417 
418 /*!
419     \brief      configure the CK_OUT0 clock source
420     \param[in]  ckout0_src: CK_OUT0 clock source selection
421                 only one parameter can be selected which is shown as below:
422       \arg        RCU_CKOUT0SRC_NONE: no clock selected
423       \arg        RCU_CKOUT0SRC_CKSYS: system clock selected
424       \arg        RCU_CKOUT0SRC_IRC8M: high speed 8M internal oscillator clock selected
425       \arg        RCU_CKOUT0SRC_HXTAL: HXTAL selected
426       \arg        RCU_CKOUT0SRC_CKPLL_DIV2: CK_PLL/2 selected
427       \arg        RCU_CKOUT0SRC_CKPLL1: CK_PLL1 selected (only available for CL and EPRT series)
428       \arg        RCU_CKOUT0SRC_CKPLL2_DIV2: CK_PLL2/2 selected (only available for CL and EPRT series)
429       \arg        RCU_CKOUT0SRC_EXT1: EXT1 selected (only available for CL and EPRT series)
430       \arg        RCU_CKOUT0SRC_CKPLL2: CK_PLL2 clock selected (only available for CL and EPRT series)
431       \arg        RCU_CKOUT0SRC_CKIRC48M: CK_IRC48M clock selected (only available for CL and EPRT series)
432       \arg        RCU_CKOUT0SRC_CKIRC48M_DIV8: CK_IRC48M/8 clock selected (only available for CL and EPRT series)
433       \arg        RCU_CKOUT0SRC_CKPLLUSB_DIV32: CK_PLLUSB/32 clock selected (only available for CL series)
434     \param[out] none
435     \retval     none
436 */
rcu_ckout0_config(uint32_t ckout0_src)437 void rcu_ckout0_config(uint32_t ckout0_src)
438 {
439     uint32_t reg;
440 
441     reg = RCU_CFG0;
442 
443     /* reset the CKOUT0SRC, set according to ckout0_src */
444     reg &= ~RCU_CFG0_CKOUT0SEL;
445     RCU_CFG0 = (reg | ckout0_src);
446 }
447 
448 /*!
449     \brief      configure the main PLL clock
450     \param[in]  pll_src: PLL clock source selection
451                 only one parameter can be selected which is shown as below:
452       \arg        RCU_PLLSRC_IRC8M_DIV2: IRC8M/2 clock selected as source clock of PLL
453       \arg        RCU_PLLSRC_HXTAL_IRC48M: HXTAL or IRC48M selected as source clock of PLL
454     \param[in]  pll_mul: PLL clock multiplication factor
455                 only one parameter can be selected which is shown as below:
456       \arg        RCU_PLL_MULx (XD series x = 2..63, CL series x = 2..14, 16..64, 6.5)
457     \param[out] none
458     \retval     none
459 */
rcu_pll_config(uint32_t pll_src,uint32_t pll_mul)460 void rcu_pll_config(uint32_t pll_src, uint32_t pll_mul)
461 {
462     uint32_t reg = 0U;
463 
464     reg = RCU_CFG0;
465 
466     /* PLL clock source and multiplication factor configuration */
467     reg &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4 | RCU_CFG0_PLLMF_5);
468     reg |= (pll_src | pll_mul);
469 
470     RCU_CFG0 = reg;
471 }
472 
473 /*!
474     \brief      configure the PLL clock source preselection
475     \param[in]  pll_presel: PLL clock source preselection
476                 only one parameter can be selected which is shown as below:
477       \arg        RCU_PLLPRESRC_HXTAL: HXTAL selected as PLL source clock
478       \arg        RCU_PLLPRESRC_IRC48M: CK_PLL selected as PREDV0 input source clock
479     \param[out] none
480     \retval     none
481 */
rcu_pllpresel_config(uint32_t pll_presel)482 void rcu_pllpresel_config(uint32_t pll_presel)
483 {
484     uint32_t reg = 0U;
485 
486     reg = RCU_CFG1;
487 
488     /* PLL clock source preselection */
489     reg &= ~RCU_CFG1_PLLPRESEL;
490     reg |= pll_presel;
491 
492     RCU_CFG1 = reg;
493 }
494 
495 #if defined(GD32E50X_HD) || defined(GD32E50X_XD)
496 /*!
497     \brief      configure the PREDV0 division factor
498     \param[in]  predv0_div: PREDV0 division factor
499       \arg        RCU_PREDV0_DIVx, x = 1,2
500     \param[out] none
501     \retval     none
502 */
rcu_predv0_config(uint32_t predv0_div)503 void rcu_predv0_config(uint32_t predv0_div)
504 {
505     uint32_t reg = 0U;
506 
507     reg = RCU_CFG0;
508     /* reset PREDV0 bit */
509     reg &= ~RCU_CFG0_PREDV0;
510     if(RCU_PREDV0_DIV2 == predv0_div){
511         /* set the PREDV0 bit */
512         reg |= RCU_CFG0_PREDV0;
513     }
514 
515     RCU_CFG0 = reg;
516 }
517 #elif defined(GD32E50X_CL) || defined(GD32EPRT) || defined(GD32E508)
518 /*!
519     \brief      configure the PREDV0 division factor and clock source
520     \param[in]  predv0_source: PREDV0 input clock source selection
521                 only one parameter can be selected which is shown as below:
522       \arg        RCU_PREDV0SRC_HXTAL_IRC48M: HXTAL or IRC48M selected as PREDV0 input source clock
523       \arg        RCU_PREDV0SRC_CKPLL1: CK_PLL1 selected as PREDV0 input source clock
524     \param[in]  predv0_div: PREDV0 division factor
525                 only one parameter can be selected which is shown as below:
526       \arg        RCU_PREDV0_DIVx, x = 1..16
527     \param[out] none
528     \retval     none
529 */
rcu_predv0_config(uint32_t predv0_source,uint32_t predv0_div)530 void rcu_predv0_config(uint32_t predv0_source, uint32_t predv0_div)
531 {
532     uint32_t reg = 0U;
533 
534     reg = RCU_CFG1;
535     /* reset PREDV0SEL and PREDV0 bits */
536     reg &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PREDV0);
537     /* set the PREDV0SEL and PREDV0 division factor */
538     reg |= (predv0_source | predv0_div);
539 
540     RCU_CFG1 = reg;
541 }
542 
543 /*!
544     \brief      configure the PREDV1 division factor
545     \param[in]  predv1_div: PREDV1 division factor
546                 only one parameter can be selected which is shown as below:
547       \arg        RCU_PREDV1_DIVx, x = 1..16
548     \param[out] none
549     \retval     none
550 */
rcu_predv1_config(uint32_t predv1_div)551 void rcu_predv1_config(uint32_t predv1_div)
552 {
553     uint32_t reg = 0U;
554 
555     reg = RCU_CFG1;
556     /* reset the PREDV1 bits */
557     reg &= ~RCU_CFG1_PREDV1;
558     /* set the PREDV1 division factor */
559     reg |= predv1_div;
560 
561     RCU_CFG1 = reg;
562 }
563 
564 /*!
565     \brief      configure the PLL1 clock
566     \param[in]  pll_mul: PLL clock multiplication factor
567                 only one parameter can be selected which is shown as below:
568       \arg        RCU_PLL1_MULx (x = 8..14,16,20)
569     \param[out] none
570     \retval     none
571 */
rcu_pll1_config(uint32_t pll_mul)572 void rcu_pll1_config(uint32_t pll_mul)
573 {
574     RCU_CFG1 &= ~RCU_CFG1_PLL1MF;
575     RCU_CFG1 |= pll_mul;
576 }
577 
578 /*!
579     \brief      configure the PLL2 clock
580     \param[in]  pll_mul: PLL clock multiplication factor
581                 only one parameter can be selected which is shown as below:
582       \arg        RCU_PLL2_MULx (x = 8..14,16,20,18..32,40,34..64,80)
583     \param[out] none
584     \retval     none
585 */
rcu_pll2_config(uint32_t pll_mul)586 void rcu_pll2_config(uint32_t pll_mul)
587 {
588     RCU_CFG1 &= ~RCU_CFG1_PLL2MF;
589     RCU_CFG1 |= pll_mul;
590 }
591 #endif /* GD32E50X_HD and GD32E50X_XD */
592 
593 #if defined(GD32E50X_CL) || defined(GD32E508)
594 /*!
595     \brief      configure the PLLUSB clock source preselection
596     \param[in]  pllusb_presel: PLLUSB clock source preselection
597                 only one parameter can be selected which is shown as below:
598       \arg        RCU_PLLUSBPRESRC_HXTAL: HXTAL selected as PLLUSB source clock
599       \arg        RCU_PLLUSBPRESRC_IRC48M: IRC48M clock selected as PLLUSB source clock
600     \param[out] none
601     \retval     none
602 */
rcu_pllusbpresel_config(uint32_t pllusb_presel)603 void rcu_pllusbpresel_config(uint32_t pllusb_presel)
604 {
605     uint32_t reg = 0U;
606 
607     reg = RCU_ADDCFG;
608 
609     /* PLLUSB clock source preselection */
610     reg &= ~RCU_ADDCFG_PLLUSBPRESEL;
611     reg |= pllusb_presel;
612 
613     RCU_ADDCFG = reg;
614 }
615 
616 /*!
617     \brief      configure the PLLUSBPREDV division factor and clock source
618     \param[in]  pllusbpredv_source: PLLUSBPREDV input clock source selection
619                 only one parameter can be selected which is shown as below:
620       \arg        RCU_PLLUSBPREDVSRC_HXTAL_IRC48M: HXTAL or IRC48M selected as PLLUSBPREDV input source clock
621       \arg        RCU_PLLUSBPREDVSRC_CKPLL1: CK_PLL1 selected as PLLUSBPREDV input source clock
622     \param[in]  pllusbpredv_div: PLLUSBPREDV division factor
623                 only one parameter can be selected which is shown as below:
624       \arg        RCU_PLLUSBPREDV_DIVx, x = 1..15
625     \param[out] none
626     \retval     none
627 */
rcu_pllusbpredv_config(uint32_t pllusbpredv_source,uint32_t pllusbpredv_div)628 void rcu_pllusbpredv_config(uint32_t pllusbpredv_source, uint32_t pllusbpredv_div)
629 {
630     uint32_t reg = 0U;
631 
632     reg = RCU_ADDCFG;
633     /* reset PLLUSBPRESEL and PLLUSBPREDV bits */
634     reg &= ~(RCU_ADDCFG_PLLUSBPREDVSEL | RCU_ADDCFG_PLLUSBPREDV);
635     /* set the PLLUSBPRESEL and PLLUSBPREDV division factor */
636     reg |= (pllusbpredv_source | pllusbpredv_div);
637 
638     RCU_ADDCFG = reg;
639 }
640 
641 /*!
642     \brief      configure the PLLUSB clock
643     \param[in]  pllusb_mul: PLLUSB clock multiplication factor
644                 only one parameter can be selected which is shown as below:
645       \arg        RCU_PLLUSB_MULx (x = 16,17..127)
646     \param[out] none
647     \retval     none
648 */
rcu_pllusb_config(uint32_t pllusb_mul)649 void rcu_pllusb_config(uint32_t pllusb_mul)
650 {
651     RCU_ADDCFG &= ~RCU_ADDCFG_PLLUSBMF;
652     RCU_ADDCFG |= pllusb_mul;
653 }
654 
655 #endif /* GD32E50X_CL and GD32E508 */
656 
657 /*!
658     \brief      configure the ADC prescaler factor
659     \param[in]  adc_psc: ADC prescaler factor
660                 only one parameter can be selected which is shown as below:
661       \arg        RCU_CKADC_CKAPB2_DIV2: ADC prescaler select CK_APB2/2
662       \arg        RCU_CKADC_CKAPB2_DIV4: ADC prescaler select CK_APB2/4
663       \arg        RCU_CKADC_CKAPB2_DIV6: ADC prescaler select CK_APB2/6
664       \arg        RCU_CKADC_CKAPB2_DIV8: ADC prescaler select CK_APB2/8
665       \arg        RCU_CKADC_CKAPB2_DIV12: ADC prescaler select CK_APB2/12
666       \arg        RCU_CKADC_CKAPB2_DIV16: ADC prescaler select CK_APB2/16
667       \arg        RCU_CKADC_CKAHB_DIV5: ADC prescaler select CK_AHB/5
668       \arg        RCU_CKADC_CKAHB_DIV6: ADC prescaler select CK_AHB/6
669       \arg        RCU_CKADC_CKAHB_DIV10: ADC prescaler select CK_AHB/10
670       \arg        RCU_CKADC_CKAHB_DIV20: ADC prescaler select CK_AHB/20
671     \param[out] none
672     \retval     none
673 */
rcu_adc_clock_config(uint32_t adc_psc)674 void rcu_adc_clock_config(uint32_t adc_psc)
675 {
676     uint32_t reg0,reg1;
677 
678     /* reset the ADCPSC bits */
679     reg0 = RCU_CFG0;
680     reg0 &= ~(RCU_CFG0_ADCPSC_2 | RCU_CFG0_ADCPSC);
681     reg1 = RCU_CFG1;
682     reg1 &= ~RCU_CFG1_ADCPSC_3;
683 
684     /* set the ADC prescaler factor */
685     switch(adc_psc){
686         case RCU_CKADC_CKAPB2_DIV2:
687         case RCU_CKADC_CKAPB2_DIV4:
688         case RCU_CKADC_CKAPB2_DIV6:
689         case RCU_CKADC_CKAPB2_DIV8:
690             reg0 |= (adc_psc << RCU_ADC_PSC_OFFSET);
691             break;
692 
693         case RCU_CKADC_CKAPB2_DIV12:
694         case RCU_CKADC_CKAPB2_DIV16:
695             adc_psc &= ~BIT(2);
696             reg0 |= ((adc_psc << RCU_ADC_PSC_OFFSET) | RCU_CFG0_ADCPSC_2);
697             break;
698 
699         case RCU_CKADC_CKAHB_DIV5:
700         case RCU_CKADC_CKAHB_DIV6:
701         case RCU_CKADC_CKAHB_DIV10:
702         case RCU_CKADC_CKAHB_DIV20:
703             adc_psc &= ~BITS(2,3);
704             reg0 |= (adc_psc << RCU_ADC_PSC_OFFSET);
705             reg1 |= RCU_CFG1_ADCPSC_3;
706             break;
707 
708         default:
709             break;
710     }
711 
712     /* set the register */
713     RCU_CFG0 = reg0;
714     RCU_CFG1 = reg1;
715 }
716 
717 /*!
718     \brief      configure the USBD/USBHS prescaler factor
719     \param[in]  usb_psc: USB prescaler factor
720                 only one parameter can be selected which is shown as below:
721       \arg        RCU_CKUSB_CKPLL_DIV1_5: USBD/USBHS prescaler select CK_PLL/1.5
722       \arg        RCU_CKUSB_CKPLL_DIV1: USBD/USBHS prescaler select CK_PLL/1
723       \arg        RCU_CKUSB_CKPLL_DIV2_5: USBD/USBHS prescaler select CK_PLL/2.5
724       \arg        RCU_CKUSB_CKPLL_DIV2: USBD/USBHS prescaler select CK_PLL/2
725       \arg        RCU_CKUSB_CKPLL_DIV3: USBD/USBHS prescaler select CK_PLL/3
726       \arg        RCU_CKUSB_CKPLL_DIV3_5: USBD/USBHS prescaler select CK_PLL/3.5
727       \arg        RCU_CKUSB_CKPLL_DIV4: USBD/USBHS prescaler select CK_PLL/4
728     \param[out] none
729     \retval     none
730 */
rcu_usb_clock_config(uint32_t usb_psc)731 void rcu_usb_clock_config(uint32_t usb_psc)
732 {
733     uint32_t reg;
734 
735     reg = RCU_CFG0;
736 
737     /* configure the USBD/USBHS prescaler factor */
738 #if (defined(GD32E50X_HD) || defined(GD32E50X_XD)||defined(GD32EPRT))
739     reg &= ~RCU_CFG0_USBDPSC;
740 #elif defined(GD32E50X_CL) || defined(GD32E508)
741     reg &= ~RCU_CFG0_USBHSPSC;
742 #endif /* GD32E50X_HD and GD32E50X_XD and GD32EPRT */
743 
744     RCU_CFG0 = (reg | usb_psc);
745 }
746 
747 /*!
748     \brief      configure the RTC clock source selection
749     \param[in]  rtc_clock_source: RTC clock source selection
750                 only one parameter can be selected which is shown as below:
751       \arg        RCU_RTCSRC_NONE: no clock selected
752       \arg        RCU_RTCSRC_LXTAL: CK_LXTAL selected as RTC source clock
753       \arg        RCU_RTCSRC_IRC40K: CK_IRC40K selected as RTC source clock
754       \arg        RCU_RTCSRC_HXTAL_DIV_128: CK_HXTAL/128 selected as RTC source clock
755     \param[out] none
756     \retval     none
757 */
rcu_rtc_clock_config(uint32_t rtc_clock_source)758 void rcu_rtc_clock_config(uint32_t rtc_clock_source)
759 {
760     uint32_t reg;
761 
762     reg = RCU_BDCTL;
763     /* reset the RTCSRC bits and set according to rtc_clock_source */
764     reg &= ~RCU_BDCTL_RTCSRC;
765     RCU_BDCTL = (reg | rtc_clock_source);
766 }
767 
768 #ifndef GD32EPRT
769 /*!
770     \brief      configure the SHRTIMER clock source selection
771     \param[in]  shrtimer_clock_source: SHRTIMER clock source selection
772                 only one parameter can be selected which is shown as below:
773       \arg        RCU_SHRTIMERSRC_CKAPB2: APB2 clock selected as SHRTIMER source clock
774       \arg        RCU_SHRTIMERSRC_CKSYS: system clock selected as SHRTIMER source clock
775     \param[out] none
776     \retval     none
777 */
rcu_shrtimer_clock_config(uint32_t shrtimer_clock_source)778 void rcu_shrtimer_clock_config(uint32_t shrtimer_clock_source)
779 {
780     uint32_t reg;
781 
782     reg = RCU_CFG1;
783     /* reset the I2S1SEL bit and set according to shrtimer_clock_source */
784     reg &= ~RCU_CFG1_SHRTIMERSEL;
785     RCU_CFG1 = (reg | shrtimer_clock_source);
786 }
787 #endif /* GD32EPRT */
788 
789 /*!
790     \brief      configure the USART5 clock source selection
791     \param[in]  usart5_clock_source: USART5 clock source selection
792                 only one parameter can be selected which is shown as below:
793       \arg        RCU_USART5SRC_CKAPB2: APB2 clock selected as USART5 source clock
794       \arg        RCU_USART5SRC_CKSYS: system clock selected as USART5 source clock
795       \arg        RCU_USART5SRC_LXTAL: LXTAL clock selected as USART5 source clock
796       \arg        RCU_USART5SRC_IRC8M: IRC8M clock selected as USART5 source clock
797     \param[out] none
798     \retval     none
799 */
rcu_usart5_clock_config(uint32_t usart5_clock_source)800 void rcu_usart5_clock_config(uint32_t usart5_clock_source)
801 {
802     uint32_t reg;
803     reg = RCU_CFG2;
804     /* reset the I2S1SEL bit and set according to usart5_clock_source */
805     reg &= ~RCU_CFG2_USART5SEL;
806     RCU_CFG2 = (reg | usart5_clock_source);
807 }
808 
809 /*!
810     \brief      configure the I2C2 clock source selection
811     \param[in]  i2c2_clock_source: I2C2 clock source selection
812                 only one parameter can be selected which is shown as below:
813       \arg        RCU_I2C2SRC_CKAPB1: APB1 clock selected as I2C2 source clock
814       \arg        RCU_I2C2SRC_CKSYS: System clock selected as I2C2 source clock
815       \arg        RCU_I2C2SRCSRC_CKIRC8M: CK_IRC8M clock selected as I2C2 source clock
816     \param[out] none
817     \retval     none
818 */
rcu_i2c2_clock_config(uint32_t i2c2_clock_source)819 void rcu_i2c2_clock_config(uint32_t i2c2_clock_source)
820 {
821     uint32_t reg;
822 
823     reg = RCU_CFG2;
824     /* reset the I2S1SEL bit and set according to i2c2_clock_source */
825     reg &= ~RCU_CFG2_I2C2SEL;
826     RCU_CFG2 = (reg | i2c2_clock_source);
827 }
828 
829 /*!
830     \brief      configure the CK48M clock source selection
831     \param[in]  ck48m_clock_source: CK48M clock source selection
832                 only one parameter can be selected which is shown as below:
833       \arg        RCU_CK48MSRC_CKPLL: CK_PLL selected as CK48M source clock
834       \arg        RCU_CK48MSRC_IRC48M: CK_IRC48M selected as CK48M source clock
835       \arg        RCU_CK48MSRC_CKPLLUSB: (not available for EPRT series): CKPLLUSB selected as CK48M source clock
836       \arg        RCU_CK48MSRC_CKPLL2: CKPLL2 selected as CK48M source clock
837     \param[out] none
838     \retval     none
839 */
rcu_ck48m_clock_config(uint32_t ck48m_clock_source)840 void rcu_ck48m_clock_config(uint32_t ck48m_clock_source)
841 {
842     uint32_t reg;
843 
844     reg = RCU_ADDCTL;
845     /* reset the CK48MSEL bit and set according to ck48m_clock_source */
846     reg &= ~RCU_ADDCTL_CK48MSEL;
847     RCU_ADDCTL = (reg | ck48m_clock_source);
848 }
849 
850 #if defined(GD32E50X_CL) || defined(GD32EPRT) || defined(GD32E508)
851 /*!
852     \brief      configure the I2S1 clock source selection
853     \param[in]  i2s_clock_source: I2S1 clock source selection
854                 only one parameter can be selected which is shown as below:
855       \arg        RCU_I2S1SRC_CKSYS: System clock selected as I2S1 source clock
856       \arg        RCU_I2S1SRC_CKPLL2_MUL2: CK_PLL2x2 selected as I2S1 source clock
857     \param[out] none
858     \retval     none
859 */
rcu_i2s1_clock_config(uint32_t i2s_clock_source)860 void rcu_i2s1_clock_config(uint32_t i2s_clock_source)
861 {
862     uint32_t reg;
863 
864     reg = RCU_CFG1;
865     /* reset the I2S1SEL bit and set according to i2s_clock_source */
866     reg &= ~RCU_CFG1_I2S1SEL;
867     RCU_CFG1 = (reg | i2s_clock_source);
868 }
869 
870 /*!
871     \brief      configure the I2S2 clock source selection
872     \param[in]  i2s_clock_source: I2S2 clock source selection
873                 only one parameter can be selected which is shown as below:
874       \arg        RCU_I2S2SRC_CKSYS: system clock selected as I2S2 source clock
875       \arg        RCU_I2S2SRC_CKPLL2_MUL2: CK_PLL2x2 selected as I2S2 source clock
876     \param[out] none
877     \retval     none
878 */
rcu_i2s2_clock_config(uint32_t i2s_clock_source)879 void rcu_i2s2_clock_config(uint32_t i2s_clock_source)
880 {
881     uint32_t reg;
882 
883     reg = RCU_CFG1;
884     /* reset the I2S2SEL bit and set according to i2s_clock_source */
885     reg &= ~RCU_CFG1_I2S2SEL;
886     RCU_CFG1 = (reg | i2s_clock_source);
887 }
888 #endif /* GD32E50X_CL and GD32E50X_EPRT and GD32E508 */
889 
890 #if defined(GD32E50X_CL) || defined(GD32E508)
891 /*!
892     \brief      configure the USBHSSEL source clock selection
893     \param[in]  usbhssel_clock_source: USBHSSEL clock source selection
894                 only one parameter can be selected which is shown as below:
895       \arg        RCU_USBHSSRC_48M: 48M clock selected as USBHS source clock
896       \arg        RCU_CK48MSRC_60M: 60M clock selected as USBHS source clock
897     \param[out] none
898     \retval     none
899 */
rcu_usbhssel_config(uint32_t usbhssel_clock_source)900 void rcu_usbhssel_config(uint32_t usbhssel_clock_source)
901 {
902     uint32_t reg = 0U;
903 
904     reg = RCU_ADDCTL;
905 
906     /* USBHS clock source selection */
907     reg &= ~RCU_ADDCTL_USBHSSEL;
908     reg |= usbhssel_clock_source;
909 
910     RCU_ADDCTL = reg;
911 }
912 
913 /*!
914     \brief      configure the USBHSDV division factor
915     \param[in]  usbhs_dv: USBHSDV division factor
916                 only one parameter can be selected which is shown as below:
917       \arg        RCU_USBHSDV_DIV2:   USBHSDV input source clock divided by 2
918       \arg        RCU_USBHSDV_DIV4:   USBHSDV input source clock divided by 4
919       \arg        RCU_USBHSDV_DIV6:   USBHSDV input source clock divided by 6
920       \arg        RCU_USBHSDV_DIV8:   USBHSDV input source clock divided by 8
921       \arg        RCU_USBHSDV_DIV10:  USBHSDV input source clock divided by 10
922       \arg        RCU_USBHSDV_DIV12:  USBHSDV input source clock divided by 12
923       \arg        RCU_USBHSDV_DIV14:  USBHSDV input source clock divided by 14
924       \arg        RCU_USBHSDV_DIV16:  USBHSDV input source clock divided by 16
925     \param[out] none
926     \retval     none
927 */
rcu_usbdv_config(uint32_t usbhs_dv)928 void rcu_usbdv_config(uint32_t usbhs_dv)
929 {
930     uint32_t reg = 0U;
931 
932     reg = RCU_ADDCTL;
933 
934     /* usbhs input clock source division factor */
935     reg &= ~RCU_ADDCTL_USBHSDV;
936     reg |= usbhs_dv;
937 
938     RCU_ADDCTL = reg;
939 }
940 #endif /* GD32E50X_CL and GD32E508 */
941 
942 /*!
943     \brief      get the clock stabilization and periphral reset flags
944     \param[in]  flag: the clock stabilization and periphral reset flags, refer to rcu_flag_enum
945                 only one parameter can be selected which is shown as below:
946       \arg        RCU_FLAG_IRC8MSTB: IRC8M stabilization flag
947       \arg        RCU_FLAG_HXTALSTB: HXTAL stabilization flag
948       \arg        RCU_FLAG_PLLSTB: PLL stabilization flag
949       \arg        RCU_FLAG_PLLUSBSTB: PLLUSB stabilization flag(CL series only)
950       \arg        RCU_FLAG_PLL1STB: PLL1 stabilization flag(CL series only)
951       \arg        RCU_FLAG_PLL2STB: PLL2 stabilization flag(CL series only)
952       \arg        RCU_FLAG_LXTALSTB: LXTAL stabilization flag
953       \arg        RCU_FLAG_IRC40KSTB: IRC40K stabilization flag
954       \arg        RCU_FLAG_IRC48MSTB: IRC48M stabilization flag
955       \arg        RCU_FLAG_BORRST: BOR reset flag
956       \arg        RCU_FLAG_EPRST: external PIN reset flag
957       \arg        RCU_FLAG_PORRST: power reset flag
958       \arg        RCU_FLAG_SWRST: software reset flag
959       \arg        RCU_FLAG_FWDGTRST: free watchdog timer reset flag
960       \arg        RCU_FLAG_WWDGTRST: window watchdog timer reset flag
961       \arg        RCU_FLAG_LPRST: low-power reset flag
962     \param[out] none
963     \retval     none
964 */
rcu_flag_get(rcu_flag_enum flag)965 FlagStatus rcu_flag_get(rcu_flag_enum flag)
966 {
967     /* get the rcu flag */
968     if(RESET != (RCU_REG_VAL(flag) & BIT(RCU_BIT_POS(flag)))){
969         return SET;
970     }else{
971         return RESET;
972     }
973 }
974 
975 /*!
976     \brief      clear all the reset flag
977     \param[in]  none
978     \param[out] none
979     \retval     none
980 */
rcu_all_reset_flag_clear(void)981 void rcu_all_reset_flag_clear(void)
982 {
983     RCU_RSTSCK |= RCU_RSTSCK_RSTFC;
984 }
985 
986 /*!
987     \brief      get the clock stabilization interrupt and ckm flags
988     \param[in]  int_flag: interrupt and ckm flags, refer to rcu_int_flag_enum
989                 only one parameter can be selected which is shown as below:
990       \arg        RCU_INT_FLAG_IRC40KSTB: IRC40K stabilization interrupt flag
991       \arg        RCU_INT_FLAG_LXTALSTB: LXTAL stabilization interrupt flag
992       \arg        RCU_INT_FLAG_IRC8MSTB: IRC8M stabilization interrupt flag
993       \arg        RCU_INT_FLAG_HXTALSTB: HXTAL stabilization interrupt flag
994       \arg        RCU_INT_FLAG_PLLSTB: PLL stabilization interrupt flag
995       \arg        RCU_INT_FLAG_PLL1STB: PLL1 stabilization interrupt flag(CL series only)
996       \arg        RCU_INT_FLAG_PLL2STB: PLL2 stabilization interrupt flag(CL series only)
997       \arg        RCU_INT_FLAG_PLLUSBSTB: PLLUSB stabilization interrupt flag(CL series only)
998       \arg        RCU_INT_FLAG_CKM: HXTAL clock stuck interrupt flag
999       \arg        RCU_INT_FLAG_IRC48MSTB: IRC48M stabilization interrupt flag
1000     \param[out] none
1001     \retval     FlagStatus: SET or RESET
1002 */
rcu_interrupt_flag_get(rcu_int_flag_enum int_flag)1003 FlagStatus rcu_interrupt_flag_get(rcu_int_flag_enum int_flag)
1004 {
1005     /* get the rcu interrupt flag */
1006     if(RESET != (RCU_REG_VAL(int_flag) & BIT(RCU_BIT_POS(int_flag)))){
1007         return SET;
1008     }else{
1009         return RESET;
1010     }
1011 }
1012 
1013 /*!
1014     \brief      clear the interrupt flags
1015     \param[in]  int_flag: clock stabilization and stuck interrupt flags clear, refer to rcu_int_flag_clear_enum
1016                 only one parameter can be selected which is shown as below:
1017       \arg        RCU_INT_FLAG_IRC40KSTB_CLR: IRC40K stabilization interrupt flag clear
1018       \arg        RCU_INT_FLAG_LXTALSTB_CLR: LXTAL stabilization interrupt flag clear
1019       \arg        RCU_INT_FLAG_IRC8MSTB_CLR: IRC8M stabilization interrupt flag clear
1020       \arg        RCU_INT_FLAG_HXTALSTB_CLR: HXTAL stabilization interrupt flag clear
1021       \arg        RCU_INT_FLAG_PLLSTB_CLR: PLL stabilization interrupt flag clear
1022       \arg        RCU_INT_FLAG_PLL1STB_CLR: PLL1 stabilization interrupt flag clear(CL series only)
1023       \arg        RCU_INT_FLAG_PLL2STB_CLR: PLL2 stabilization interrupt flag clear(CL series only)
1024       \arg        RCU_INT_FLAG_PLLUSBSTB_CLR: PLLUS stabilization interrupt flag clear(CL series only)
1025       \arg        RCU_INT_FLAG_CKM_CLR: clock stuck interrupt flag clear
1026       \arg        RCU_INT_FLAG_IRC48MSTB_CLR: IRC48M stabilization interrupt flag clear
1027     \param[out] none
1028     \retval     none
1029 */
rcu_interrupt_flag_clear(rcu_int_flag_clear_enum int_flag)1030 void rcu_interrupt_flag_clear(rcu_int_flag_clear_enum int_flag)
1031 {
1032     RCU_REG_VAL(int_flag) |= BIT(RCU_BIT_POS(int_flag));
1033 }
1034 
1035 /*!
1036     \brief      enable the stabilization interrupt
1037     \param[in]  interrupt clock stabilization interrupt, refer to rcu_int_enum
1038                 only one parameter can be selected which is shown as below:
1039       \arg        RCU_INT_IRC40KSTB: IRC40K stabilization interrupt enable
1040       \arg        RCU_INT_LXTALSTB: LXTAL stabilization interrupt enable
1041       \arg        RCU_INT_IRC8MSTB: IRC8M stabilization interrupt enable
1042       \arg        RCU_INT_HXTALSTB: HXTAL stabilization interrupt enable
1043       \arg        RCU_INT_PLLSTB: PLL stabilization interrupt enable
1044       \arg        RCU_INT_PLL1STB: PLL1 stabilization interrupt enable(CL series only)
1045       \arg        RCU_INT_PLL2STB: PLL2 stabilization interrupt enable(CL series only)
1046       \arg        RCU_INT_PLLUSBSTB: PLLUSB stabilization interrupt enable(CL series only)
1047       \arg        RCU_INT_IRC48MSTB: IRC48M stabilization interrupt enable
1048     \param[out] none
1049     \retval     none
1050 */
rcu_interrupt_enable(rcu_int_enum interrupt)1051 void rcu_interrupt_enable(rcu_int_enum interrupt)
1052 {
1053     RCU_REG_VAL(interrupt) |= BIT(RCU_BIT_POS(interrupt));
1054 }
1055 
1056 /*!
1057     \brief      disable the stabilization interrupt
1058     \param[in]  interrupt clock stabilization interrupt, refer to rcu_int_enum
1059                 only one parameter can be selected which is shown as below:
1060       \arg        RCU_INT_IRC40KSTB: IRC40K stabilization interrupt enable
1061       \arg        RCU_INT_LXTALSTB: LXTAL stabilization interrupt enable
1062       \arg        RCU_INT_IRC8MSTB: IRC8M stabilization interrupt enable
1063       \arg        RCU_INT_HXTALSTB: HXTAL stabilization interrupt enable
1064       \arg        RCU_INT_PLLSTB: PLL stabilization interrupt enable
1065       \arg        RCU_INT_PLL1STB: PLL1 stabilization interrupt enable(CL series only)
1066       \arg        RCU_INT_PLL2STB: PLL2 stabilization interrupt enable(CL series only)
1067       \arg        RCU_INT_PLLUSBSTB: PLLUSB stabilization interrupt enable(CL series only)
1068       \arg        RCU_INT_IRC48MSTB: IRC48M stabilization interrupt enable
1069     \param[out] none
1070     \retval     none
1071 */
rcu_interrupt_disable(rcu_int_enum interrupt)1072 void rcu_interrupt_disable(rcu_int_enum interrupt)
1073 {
1074     RCU_REG_VAL(interrupt) &= ~BIT(RCU_BIT_POS(interrupt));
1075 }
1076 
1077 /*!
1078     \brief      configure the LXTAL drive capability
1079     \param[in]  lxtal_dricap: drive capability of LXTAL
1080                 only one parameter can be selected which is shown as below:
1081       \arg        RCU_LXTAL_LOWDRI: lower driving capability
1082       \arg        RCU_LXTAL_MED_LOWDRI: medium low driving capability
1083       \arg        RCU_LXTAL_MED_HIGHDRI: medium high driving capability
1084       \arg        RCU_LXTAL_HIGHDRI: higher driving capability
1085     \param[out] none
1086     \retval     none
1087 */
rcu_lxtal_drive_capability_config(uint32_t lxtal_dricap)1088 void rcu_lxtal_drive_capability_config(uint32_t lxtal_dricap)
1089 {
1090     uint32_t reg;
1091 
1092     reg = RCU_BDCTL;
1093 
1094     /* reset the LXTALDRI bits and set according to lxtal_dricap */
1095     reg &= ~RCU_BDCTL_LXTALDRI;
1096     RCU_BDCTL = (reg | lxtal_dricap);
1097 }
1098 
1099 /*!
1100     \brief      wait for oscillator stabilization flags is SET or oscillator startup is timeout
1101     \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
1102                 only one parameter can be selected which is shown as below:
1103       \arg        RCU_HXTAL: high speed crystal oscillator(HXTAL)
1104       \arg        RCU_LXTAL: low speed crystal oscillator(LXTAL)
1105       \arg        RCU_IRC8M: internal 8M RC oscillators(IRC8M)
1106       \arg        RCU_IRC48M: internal 48M RC oscillators(IRC48M)
1107       \arg        RCU_IRC40K: internal 40K RC oscillator(IRC40K)
1108       \arg        RCU_PLL_CK: phase locked loop(PLL)
1109       \arg        RCU_PLL1_CK: phase locked loop 1(CL series only)
1110       \arg        RCU_PLL2_CK: phase locked loop 2(CL series only)
1111       \arg        RCU_PLLUSB_CK: phase locked loop USB(CL series only)
1112     \param[out] none
1113     \retval     ErrStatus: SUCCESS or ERROR
1114 */
rcu_osci_stab_wait(rcu_osci_type_enum osci)1115 ErrStatus rcu_osci_stab_wait(rcu_osci_type_enum osci)
1116 {
1117     uint32_t stb_cnt = 0U;
1118     ErrStatus reval = ERROR;
1119     FlagStatus osci_stat = RESET;
1120 
1121     switch(osci){
1122     /* wait HXTAL stable */
1123     case RCU_HXTAL:
1124         while((RESET == osci_stat) && (HXTAL_STARTUP_TIMEOUT != stb_cnt)){
1125             osci_stat = rcu_flag_get(RCU_FLAG_HXTALSTB);
1126             stb_cnt++;
1127         }
1128 
1129         /* check whether flag is set or not */
1130         if(RESET != rcu_flag_get(RCU_FLAG_HXTALSTB)){
1131             reval = SUCCESS;
1132         }
1133         break;
1134 
1135     /* wait LXTAL stable */
1136     case RCU_LXTAL:
1137         while((RESET == osci_stat) && (LXTAL_STARTUP_TIMEOUT != stb_cnt)){
1138             osci_stat = rcu_flag_get(RCU_FLAG_LXTALSTB);
1139             stb_cnt++;
1140         }
1141 
1142         /* check whether flag is set or not */
1143         if(RESET != rcu_flag_get(RCU_FLAG_LXTALSTB)){
1144             reval = SUCCESS;
1145         }
1146         break;
1147 
1148     /* wait IRC8M stable */
1149     case RCU_IRC8M:
1150         while((RESET == osci_stat) && (IRC8M_STARTUP_TIMEOUT != stb_cnt)){
1151             osci_stat = rcu_flag_get(RCU_FLAG_IRC8MSTB);
1152             stb_cnt++;
1153         }
1154 
1155         /* check whether flag is set or not */
1156         if(RESET != rcu_flag_get(RCU_FLAG_IRC8MSTB)){
1157             reval = SUCCESS;
1158         }
1159         break;
1160 
1161     /* wait IRC48M stable */
1162     case RCU_IRC48M:
1163         while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)){
1164             osci_stat = rcu_flag_get(RCU_FLAG_IRC48MSTB);
1165             stb_cnt++;
1166         }
1167 
1168         /* check whether flag is set or not */
1169         if (RESET != rcu_flag_get(RCU_FLAG_IRC48MSTB)){
1170             reval = SUCCESS;
1171         }
1172         break;
1173 
1174     /* wait IRC40K stable */
1175     case RCU_IRC40K:
1176         while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)){
1177             osci_stat = rcu_flag_get(RCU_FLAG_IRC40KSTB);
1178             stb_cnt++;
1179         }
1180 
1181         /* check whether flag is set or not */
1182         if(RESET != rcu_flag_get(RCU_FLAG_IRC40KSTB)){
1183             reval = SUCCESS;
1184         }
1185         break;
1186 
1187     /* wait PLL stable */
1188     case RCU_PLL_CK:
1189         while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)){
1190             osci_stat = rcu_flag_get(RCU_FLAG_PLLSTB);
1191             stb_cnt++;
1192         }
1193 
1194         /* check whether flag is set or not */
1195         if(RESET != rcu_flag_get(RCU_FLAG_PLLSTB)){
1196             reval = SUCCESS;
1197         }
1198         break;
1199 
1200 #if defined(GD32E50X_CL)  || defined(GD32EPRT) || defined(GD32E508)
1201     /* wait PLL1 stable */
1202     case RCU_PLL1_CK:
1203         while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)){
1204             osci_stat = rcu_flag_get(RCU_FLAG_PLL1STB);
1205             stb_cnt++;
1206         }
1207 
1208         /* check whether flag is set or not */
1209         if(RESET != rcu_flag_get(RCU_FLAG_PLL1STB)){
1210             reval = SUCCESS;
1211         }
1212         break;
1213     /* wait PLL2 stable */
1214     case RCU_PLL2_CK:
1215         while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)){
1216             osci_stat = rcu_flag_get(RCU_FLAG_PLL2STB);
1217             stb_cnt++;
1218         }
1219 
1220         /* check whether flag is set or not */
1221         if(RESET != rcu_flag_get(RCU_FLAG_PLL2STB)){
1222             reval = SUCCESS;
1223         }
1224         break;
1225 #endif /* GD32E50X_CL and GD32E50X_EPRT and GD32E508 */
1226 #if defined(GD32E50X_CL) || defined(GD32E508)
1227     case RCU_PLLUSB_CK:
1228         while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)){
1229             osci_stat = rcu_flag_get(RCU_FLAG_PLLUSBSTB);
1230             stb_cnt++;
1231         }
1232 
1233         /* check whether flag is set or not */
1234         if(RESET != rcu_flag_get(RCU_FLAG_PLLUSBSTB)){
1235             reval = SUCCESS;
1236         }
1237         break;
1238 #endif /* GD32E50X_CL and GD32E508 */
1239 
1240     default:
1241         break;
1242     }
1243 
1244     /* return value */
1245     return reval;
1246 }
1247 
1248 /*!
1249     \brief      turn on the oscillator
1250     \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
1251                 only one parameter can be selected which is shown as below:
1252       \arg        RCU_HXTAL: high speed crystal oscillator(HXTAL)
1253       \arg        RCU_LXTAL: low speed crystal oscillator(LXTAL)
1254       \arg        RCU_IRC8M: internal 8M RC oscillators(IRC8M)
1255       \arg        RCU_IRC48M: internal 48M RC oscillators(IRC48M)
1256       \arg        RCU_IRC40K: internal 40K RC oscillator(IRC40K)
1257       \arg        RCU_PLL_CK: phase locked loop(PLL)
1258       \arg        RCU_PLL1_CK: phase locked loop 1(CL and EPRT series only)
1259       \arg        RCU_PLL2_CK: phase locked loop 2(CL and EPRT series only)
1260       \arg        RCU_PLLUSB_CK: phase locked loop USB(CL series only)
1261     \param[out] none
1262     \retval     none
1263 */
rcu_osci_on(rcu_osci_type_enum osci)1264 void rcu_osci_on(rcu_osci_type_enum osci)
1265 {
1266     RCU_REG_VAL(osci) |= BIT(RCU_BIT_POS(osci));
1267 }
1268 
1269 /*!
1270     \brief      turn off the oscillator
1271     \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
1272                 only one parameter can be selected which is shown as below:
1273       \arg        RCU_HXTAL: high speed crystal oscillator(HXTAL)
1274       \arg        RCU_LXTAL: low speed crystal oscillator(LXTAL)
1275       \arg        RCU_IRC8M: internal 8M RC oscillators(IRC8M)
1276       \arg        RCU_IRC48M: internal 48M RC oscillators(IRC48M)
1277       \arg        RCU_IRC40K: internal 40K RC oscillator(IRC40K)
1278       \arg        RCU_PLL_CK: phase locked loop(PLL)
1279       \arg        RCU_PLL1_CK: phase locked loop 1(CL and EPRT series only)
1280       \arg        RCU_PLL2_CK: phase locked loop 2(CL and EPRT series only)
1281       \arg        RCU_PLLUSB_CK: phase locked loop USB(CL series only)
1282     \param[out] none
1283     \retval     none
1284 */
rcu_osci_off(rcu_osci_type_enum osci)1285 void rcu_osci_off(rcu_osci_type_enum osci)
1286 {
1287     RCU_REG_VAL(osci) &= ~BIT(RCU_BIT_POS(osci));
1288 }
1289 
1290 /*!
1291     \brief      enable the oscillator bypass mode, HXTALEN or LXTALEN must be reset before it
1292     \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
1293                 only one parameter can be selected which is shown as below:
1294       \arg        RCU_HXTAL: high speed crystal oscillator(HXTAL)
1295       \arg        RCU_LXTAL: low speed crystal oscillator(LXTAL)
1296     \param[out] none
1297     \retval     none
1298 */
rcu_osci_bypass_mode_enable(rcu_osci_type_enum osci)1299 void rcu_osci_bypass_mode_enable(rcu_osci_type_enum osci)
1300 {
1301     uint32_t reg;
1302 
1303     switch(osci){
1304     /* enable HXTAL to bypass mode */
1305     case RCU_HXTAL:
1306         reg = RCU_CTL;
1307         RCU_CTL &= ~RCU_CTL_HXTALEN;
1308         RCU_CTL = (reg | RCU_CTL_HXTALBPS);
1309         break;
1310     /* enable LXTAL to bypass mode */
1311     case RCU_LXTAL:
1312         reg = RCU_BDCTL;
1313         RCU_BDCTL &= ~RCU_BDCTL_LXTALEN;
1314         RCU_BDCTL = (reg | RCU_BDCTL_LXTALBPS);
1315         break;
1316     case RCU_IRC8M:
1317     case RCU_IRC48M:
1318     case RCU_IRC40K:
1319     case RCU_PLL_CK:
1320 #if defined(GD32E50X_CL) || defined(GD32EPRT) || defined(GD32E508)
1321     case RCU_PLL1_CK:
1322     case RCU_PLL2_CK:
1323 #endif /* GD32E50X_CL and GD32EPRT and GD32E508 */
1324         break;
1325     default:
1326         break;
1327     }
1328 }
1329 
1330 /*!
1331     \brief      disable the oscillator bypass mode, HXTALEN or LXTALEN must be reset before it
1332     \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
1333                 only one parameter can be selected which is shown as below:
1334       \arg        RCU_HXTAL: high speed crystal oscillator(HXTAL)
1335       \arg        RCU_LXTAL: low speed crystal oscillator(LXTAL)
1336     \param[out] none
1337     \retval     none
1338 */
rcu_osci_bypass_mode_disable(rcu_osci_type_enum osci)1339 void rcu_osci_bypass_mode_disable(rcu_osci_type_enum osci)
1340 {
1341     uint32_t reg;
1342 
1343     switch(osci){
1344     /* disable HXTAL to bypass mode */
1345     case RCU_HXTAL:
1346         reg = RCU_CTL;
1347         RCU_CTL &= ~RCU_CTL_HXTALEN;
1348         RCU_CTL = (reg & ~RCU_CTL_HXTALBPS);
1349         break;
1350     /* disable LXTAL to bypass mode */
1351     case RCU_LXTAL:
1352         reg = RCU_BDCTL;
1353         RCU_BDCTL &= ~RCU_BDCTL_LXTALEN;
1354         RCU_BDCTL = (reg & ~RCU_BDCTL_LXTALBPS);
1355         break;
1356     case RCU_IRC8M:
1357     case RCU_IRC48M:
1358     case RCU_IRC40K:
1359     case RCU_PLL_CK:
1360 #if defined(GD32E50X_CL) || defined(GD32EPRT) || defined(GD32E508)
1361     case RCU_PLL1_CK:
1362     case RCU_PLL2_CK:
1363 #endif /* GD32E50X_CL and GD32EPRT and GD32E508 */
1364         break;
1365     default:
1366         break;
1367     }
1368 }
1369 
1370 /*!
1371     \brief      enable the HXTAL clock monitor
1372     \param[in]  none
1373     \param[out] none
1374     \retval     none
1375 */
1376 
rcu_hxtal_clock_monitor_enable(void)1377 void rcu_hxtal_clock_monitor_enable(void)
1378 {
1379     RCU_CTL |= RCU_CTL_CKMEN;
1380 }
1381 
1382 /*!
1383     \brief      disable the HXTAL clock monitor
1384     \param[in]  none
1385     \param[out] none
1386     \retval     none
1387 */
rcu_hxtal_clock_monitor_disable(void)1388 void rcu_hxtal_clock_monitor_disable(void)
1389 {
1390     RCU_CTL &= ~RCU_CTL_CKMEN;
1391 }
1392 
1393 /*!
1394     \brief      set the IRC8M adjust value
1395     \param[in]  irc8m_adjval: IRC8M adjust value, must be between 0 and 0x1F
1396       \arg        0x00 - 0x1F
1397     \param[out] none
1398     \retval     none
1399 */
rcu_irc8m_adjust_value_set(uint32_t irc8m_adjval)1400 void rcu_irc8m_adjust_value_set(uint32_t irc8m_adjval)
1401 {
1402     uint32_t reg;
1403 
1404     reg = RCU_CTL;
1405     /* reset the IRC8MADJ bits and set according to irc8m_adjval */
1406     reg &= ~RCU_CTL_IRC8MADJ;
1407     RCU_CTL = (reg | ((irc8m_adjval & RCU_IRC8M_ADJUST_MASK) << RCU_IRC8M_ADJUST_OFFSET));
1408 }
1409 
1410 /*!
1411     \brief      deep-sleep mode voltage select
1412     \param[in]  dsvol: deep sleep mode voltage
1413                 only one parameter can be selected which is shown as below:
1414       \arg        RCU_DEEPSLEEP_V_1_0: the core voltage is 1.0V
1415       \arg        RCU_DEEPSLEEP_V_0_9: the core voltage is 0.9V
1416       \arg        RCU_DEEPSLEEP_V_0_8: the core voltage is 0.8V
1417       \arg        RCU_DEEPSLEEP_V_0_7: the core voltage is 0.7V
1418     \param[out] none
1419     \retval     none
1420 */
rcu_deepsleep_voltage_set(uint32_t dsvol)1421 void rcu_deepsleep_voltage_set(uint32_t dsvol)
1422 {
1423     dsvol &= RCU_DSV_DSLPVS;
1424     RCU_DSV = dsvol;
1425 }
1426 
1427 /*!
1428     \brief      get the system clock, bus and peripheral clock frequency
1429     \param[in]  clock: the clock frequency which to get
1430                 only one parameter can be selected which is shown as below:
1431       \arg        CK_SYS: system clock frequency
1432       \arg        CK_AHB: AHB clock frequency
1433       \arg        CK_APB1: APB1 clock frequency
1434       \arg        CK_APB2: APB2 clock frequency
1435       \arg        CK_USART: USART5 clock frequency
1436     \param[out] none
1437     \retval     clock frequency of system, AHB, APB1, APB2
1438 */
rcu_clock_freq_get(rcu_clock_freq_enum clock)1439 uint32_t rcu_clock_freq_get(rcu_clock_freq_enum clock)
1440 {
1441     uint32_t sws, ck_freq = 0U;
1442     uint32_t cksys_freq, ahb_freq, apb1_freq, apb2_freq;
1443     uint32_t usart_freq = 0U;
1444     uint32_t pllsel, pllpresel, predv0sel, pllmf,ck_src, idx, clk_exp;
1445 #if defined(GD32E50X_CL) || defined(GD32EPRT) || defined(GD32E508)
1446     uint32_t predv0, predv1, pll1mf;
1447 #endif /* GD32E50X_CL and GD32EPRT and GD32E508*/
1448 
1449     /* exponent of AHB, APB1 and APB2 clock divider */
1450     uint8_t ahb_exp[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
1451     uint8_t apb1_exp[8] = {0, 0, 0, 0, 1, 2, 3, 4};
1452     uint8_t apb2_exp[8] = {0, 0, 0, 0, 1, 2, 3, 4};
1453 
1454     sws = GET_BITS(RCU_CFG0, 2, 3);
1455     switch(sws){
1456     /* IRC8M is selected as CK_SYS */
1457     case SEL_IRC8M:
1458         cksys_freq = IRC8M_VALUE;
1459         break;
1460     /* HXTAL is selected as CK_SYS */
1461     case SEL_HXTAL:
1462         cksys_freq = HXTAL_VALUE;
1463         break;
1464     /* PLL is selected as CK_SYS */
1465     case SEL_PLL:
1466         /* PLL clock source selection, HXTAL, IRC48M or IRC8M/2 */
1467         pllsel = (RCU_CFG0 & RCU_CFG0_PLLSEL);
1468 
1469         if(RCU_PLLSRC_HXTAL_IRC48M == pllsel) {
1470             /* PLL clock source is HXTAL or IRC48M */
1471             pllpresel = (RCU_CFG1 & RCU_CFG1_PLLPRESEL);
1472 
1473             if(RCU_PLLPRESRC_HXTAL == pllpresel){
1474                 /* PLL clock source is HXTAL */
1475                 ck_src = HXTAL_VALUE;
1476             }else{
1477                 /* PLL clock source is IRC48 */
1478                 ck_src = IRC48M_VALUE;
1479             }
1480 
1481 #if defined(GD32E50X_HD) || defined(GD32E50X_XD)
1482             predv0sel = (RCU_CFG0 & RCU_CFG0_PREDV0);
1483             /* PREDV0 input source clock divided by 2 */
1484             if(RCU_CFG0_PREDV0 == predv0sel){
1485                 ck_src = HXTAL_VALUE/2U;
1486             }
1487 #elif defined(GD32E50X_CL) || defined(GD32EPRT) || defined(GD32E508)
1488             predv0sel = (RCU_CFG1 & RCU_CFG1_PREDV0SEL);
1489             /* source clock use PLL1 */
1490             if(RCU_PREDV0SRC_CKPLL1 == predv0sel){
1491                 predv1 = ((RCU_CFG1 & RCU_CFG1_PREDV1) >> RCU_CFG1_PREDV1_OFFSET) + 1U;
1492                 pll1mf = (uint32_t)((RCU_CFG1 & RCU_CFG1_PLL1MF) >> RCU_CFG1_PLL1MF_OFFSET) + 2U;
1493                 if(15U == pll1mf){
1494                     pll1mf = 20U;
1495                 }
1496                 ck_src = (ck_src/predv1)*pll1mf;
1497             }
1498             predv0 = (RCU_CFG1 & RCU_CFG1_PREDV0) + 1U;
1499             ck_src /= predv0;
1500 #endif /* GD32E50X_HD and GD32E50X_XD */
1501         }else{
1502             /* PLL clock source is IRC8M/2 */
1503             ck_src = IRC8M_VALUE/2U;
1504         }
1505 
1506         /* PLL multiplication factor */
1507         pllmf = GET_BITS(RCU_CFG0, 18, 21);
1508         if((RCU_CFG0 & RCU_CFG0_PLLMF_4)){
1509             pllmf |= 0x10U;
1510         }
1511         if((RCU_CFG0 & RCU_CFG0_PLLMF_5)){
1512             pllmf |= 0x20U;
1513         }
1514         if(pllmf < 15U){
1515             pllmf += 2U;
1516         }else if((pllmf >= 15U) && (pllmf <= 64U)){
1517             pllmf += 1U;
1518         }
1519         cksys_freq = ck_src*pllmf;
1520 #if defined(GD32E50X_CL) || defined(GD32EPRT) || defined(GD32E508)
1521         if(15U == pllmf){
1522             cksys_freq = ck_src*6U + ck_src/2U;
1523         }
1524 #endif /* GD32E50X_CL and GD32EPRT and GD32E508 */
1525 
1526         break;
1527     /* IRC8M is selected as CK_SYS */
1528     default:
1529         cksys_freq = IRC8M_VALUE;
1530         break;
1531     }
1532 
1533     /* calculate AHB clock frequency */
1534     idx = GET_BITS(RCU_CFG0, 4, 7);
1535     clk_exp = ahb_exp[idx];
1536     ahb_freq = cksys_freq >> clk_exp;
1537 
1538     /* calculate APB1 clock frequency */
1539     idx = GET_BITS(RCU_CFG0, 8, 10);
1540     clk_exp = apb1_exp[idx];
1541     apb1_freq = ahb_freq >> clk_exp;
1542 
1543     /* calculate APB2 clock frequency */
1544     idx = GET_BITS(RCU_CFG0, 11, 13);
1545     clk_exp = apb2_exp[idx];
1546     apb2_freq = ahb_freq >> clk_exp;
1547 
1548     /* return the clocks frequency */
1549     switch(clock){
1550     case CK_SYS:
1551         ck_freq = cksys_freq;
1552         break;
1553     case CK_AHB:
1554         ck_freq = ahb_freq;
1555         break;
1556     case CK_APB1:
1557         ck_freq = apb1_freq;
1558         break;
1559     case CK_APB2:
1560         ck_freq = apb2_freq;
1561         break;
1562     case CK_USART:
1563         /* calculate USART5 clock frequency */
1564         if(RCU_USART5SRC_CKAPB2 == (RCU_CFG2 & RCU_CFG2_USART5SEL)){
1565             usart_freq = apb2_freq;
1566         }else if(RCU_USART5SRC_CKSYS == (RCU_CFG2 & RCU_CFG2_USART5SEL)){
1567             usart_freq = cksys_freq;
1568         }else if(RCU_USART5SRC_LXTAL == (RCU_CFG2 & RCU_CFG2_USART5SEL)){
1569             usart_freq = LXTAL_VALUE;
1570         }else if(RCU_USART5SRC_IRC8M == (RCU_CFG2 & RCU_CFG2_USART5SEL)){
1571             usart_freq = IRC8M_VALUE;
1572         }else{
1573         }
1574         ck_freq = usart_freq;
1575         break;
1576     default:
1577         break;
1578     }
1579     return ck_freq;
1580 }
1581