1 /*!
2     \file    gd32f4xx_rcu.c
3     \brief   RCU driver
4 
5     \version 2016-08-15, V1.0.0, firmware for GD32F4xx
6     \version 2018-12-12, V2.0.0, firmware for GD32F4xx
7     \version 2020-09-30, V2.1.0, firmware for GD32F4xx
8     \version 2022-03-09, V3.0.0, firmware for GD32F4xx
9 */
10 
11 /*
12     Copyright (c) 2022, GigaDevice Semiconductor Inc.
13 
14     Redistribution and use in source and binary forms, with or without modification,
15 are permitted provided that the following conditions are met:
16 
17     1. Redistributions of source code must retain the above copyright notice, this
18        list of conditions and the following disclaimer.
19     2. Redistributions in binary form must reproduce the above copyright notice,
20        this list of conditions and the following disclaimer in the documentation
21        and/or other materials provided with the distribution.
22     3. Neither the name of the copyright holder nor the names of its contributors
23        may be used to endorse or promote products derived from this software without
24        specific prior written permission.
25 
26     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
30 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
33 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
35 OF SUCH DAMAGE.
36 */
37 
38 #include "gd32f4xx_rcu.h"
39 
40 /* define clock source */
41 #define SEL_IRC16M                  ((uint16_t)0U)                            /* IRC16M is selected as CK_SYS */
42 #define SEL_HXTAL                   ((uint16_t)1U)                            /* HXTAL is selected as CK_SYS */
43 #define SEL_PLLP                    ((uint16_t)2U)                            /* PLLP is selected as CK_SYS */
44 /* define startup timeout count */
45 #define OSC_STARTUP_TIMEOUT         ((uint32_t)0x000fffffU)
46 #define LXTAL_STARTUP_TIMEOUT       ((uint32_t)0x0fffffffU)
47 
48 /* RCU IRC16M adjust value mask and offset*/
49 #define RCU_IRC16M_ADJUST_MASK      ((uint8_t)0x1FU)
50 #define RCU_IRC16M_ADJUST_OFFSET    ((uint32_t)3U)
51 
52 /*!
53     \brief    deinitialize the RCU
54     \param[in]  none
55     \param[out] none
56     \retval     none
57 */
rcu_deinit(void)58 void rcu_deinit(void)
59 {
60     /* enable IRC16M */
61     RCU_CTL |= RCU_CTL_IRC16MEN;
62     rcu_osci_stab_wait(RCU_IRC16M);
63     RCU_CFG0 &= ~RCU_CFG0_SCS;
64 
65     /* reset CTL register */
66     RCU_CTL &= ~(RCU_CTL_HXTALEN | RCU_CTL_CKMEN | RCU_CTL_PLLEN | RCU_CTL_PLLI2SEN
67                  | RCU_CTL_PLLSAIEN);
68     RCU_CTL &= ~(RCU_CTL_HXTALBPS);
69     /* reset CFG0 register */
70     RCU_CFG0 &= ~(RCU_CFG0_SCS | RCU_CFG0_AHBPSC | RCU_CFG0_APB1PSC | RCU_CFG0_APB2PSC |
71                   RCU_CFG0_RTCDIV | RCU_CFG0_CKOUT0SEL | RCU_CFG0_I2SSEL | RCU_CFG0_CKOUT0DIV |
72                   RCU_CFG0_CKOUT1DIV | RCU_CFG0_CKOUT1SEL);
73     /* reset PLL register */
74     RCU_PLL = 0x24003010U;
75     /* reset PLLI2S register */
76     RCU_PLLI2S = 0x24003000U;
77     /* reset PLLSAI register */
78     RCU_PLLSAI = 0x24003010U;
79     /* reset INT register */
80     RCU_INT = 0x00000000U;
81     /* reset CFG1 register */
82     RCU_CFG1 &= ~(RCU_CFG1_PLLSAIRDIV | RCU_CFG1_TIMERSEL);
83 }
84 
85 /*!
86     \brief    enable the peripherals clock
87     \param[in]  periph: RCU peripherals, refer to rcu_periph_enum
88                 only one parameter can be selected which is shown as below:
89       \arg        RCU_GPIOx (x=A,B,C,D,E,F,G,H,I): GPIO ports clock
90       \arg        RCU_CRC: CRC clock
91       \arg        RCU_BKPSRAM: BKPSRAM clock
92       \arg        RCU_TCMSRAM: TCMSRAM clock
93       \arg        RCU_DMAx (x=0,1): DMA clock
94       \arg        RCU_IPA: IPA clock
95       \arg        RCU_ENET: ENET clock
96       \arg        RCU_ENETTX: ENETTX clock
97       \arg        RCU_ENETRX: ENETRX clock
98       \arg        RCU_ENETPTP: ENETPTP clock
99       \arg        RCU_USBHS: USBHS clock
100       \arg        RCU_USBHSULPI: USBHSULPI clock
101       \arg        RCU_DCI: DCI clock
102       \arg        RCU_TRNG: TRNG clock
103       \arg        RCU_USBFS: USBFS clock
104       \arg        RCU_EXMC: EXMC clock
105       \arg        RCU_TIMERx (x=0,1,2,3,4,5,6,7,8,9,10,11,12,13): TIMER clock
106       \arg        RCU_WWDGT: WWDGT clock
107       \arg        RCU_SPIx (x=0,1,2,3,4,5): SPI clock
108       \arg        RCU_USARTx (x=0,1,2,5): USART clock
109       \arg        RCU_UARTx (x=3,4,6,7): UART clock
110       \arg        RCU_I2Cx (x=0,1,2): I2C clock
111       \arg        RCU_CANx (x=0,1): CAN clock
112       \arg        RCU_PMU: PMU clock
113       \arg        RCU_DAC: DAC clock
114       \arg        RCU_RTC: RTC clock
115       \arg        RCU_ADCx (x=0,1,2): ADC clock
116       \arg        RCU_SDIO: SDIO clock
117       \arg        RCU_SYSCFG: SYSCFG clock
118       \arg        RCU_TLI: TLI clock
119       \arg        RCU_CTC: CTC clock
120       \arg        RCU_IREF: IREF clock
121     \param[out] none
122     \retval     none
123 */
rcu_periph_clock_enable(rcu_periph_enum periph)124 void rcu_periph_clock_enable(rcu_periph_enum periph)
125 {
126     RCU_REG_VAL(periph) |= BIT(RCU_BIT_POS(periph));
127 }
128 
129 /*!
130     \brief    disable the peripherals clock
131     \param[in]  periph: RCU peripherals, refer to rcu_periph_enum
132                 only one parameter can be selected which is shown as below:
133       \arg        RCU_GPIOx (x=A,B,C,D,E,F,G,H,I): GPIO ports clock
134       \arg        RCU_CRC: CRC clock
135       \arg        RCU_BKPSRAM: BKPSRAM clock
136       \arg        RCU_TCMSRAM: TCMSRAM clock
137       \arg        RCU_DMAx (x=0,1): DMA clock
138       \arg        RCU_IPA: IPA clock
139       \arg        RCU_ENET: ENET clock
140       \arg        RCU_ENETTX: ENETTX clock
141       \arg        RCU_ENETRX: ENETRX clock
142       \arg        RCU_ENETPTP: ENETPTP clock
143       \arg        RCU_USBHS: USBHS clock
144       \arg        RCU_USBHSULPI: USBHSULPI clock
145       \arg        RCU_DCI: DCI clock
146       \arg        RCU_TRNG: TRNG clock
147       \arg        RCU_USBFS: USBFS clock
148       \arg        RCU_EXMC: EXMC clock
149       \arg        RCU_TIMERx (x=0,1,2,3,4,5,6,7,8,9,10,11,12,13): TIMER clock
150       \arg        RCU_WWDGT: WWDGT clock
151       \arg        RCU_SPIx (x=0,1,2,3,4,5): SPI clock
152       \arg        RCU_USARTx (x=0,1,2,5): USART clock
153       \arg        RCU_UARTx (x=3,4,6,7): UART clock
154       \arg        RCU_I2Cx (x=0,1,2): I2C clock
155       \arg        RCU_CANx (x=0,1): CAN clock
156       \arg        RCU_PMU: PMU clock
157       \arg        RCU_DAC: DAC clock
158       \arg        RCU_RTC: RTC clock
159       \arg        RCU_ADCx (x=0,1,2): ADC clock
160       \arg        RCU_SDIO: SDIO clock
161       \arg        RCU_SYSCFG: SYSCFG clock
162       \arg        RCU_TLI: TLI clock
163       \arg        RCU_CTC: CTC clock
164       \arg        RCU_IREF: IREF clock
165     \param[out] none
166     \retval     none
167 */
rcu_periph_clock_disable(rcu_periph_enum periph)168 void rcu_periph_clock_disable(rcu_periph_enum periph)
169 {
170     RCU_REG_VAL(periph) &= ~BIT(RCU_BIT_POS(periph));
171 }
172 
173 /*!
174     \brief    enable the peripherals clock when sleep mode
175     \param[in]  periph: RCU peripherals, refer to rcu_periph_sleep_enum
176                 only one parameter can be selected which is shown as below:
177       \arg        RCU_GPIOx_SLP (x=A,B,C,D,E,F,G,H,I): GPIO ports clock
178       \arg        RCU_CRC_SLP: CRC clock
179       \arg        RCU_FMC_SLP: FMC clock
180       \arg        RCU_SRAM0_SLP: SRAM0 clock
181       \arg        RCU_SRAM1_SLP: SRAM1 clock
182       \arg        RCU_BKPSRAM: BKPSRAM clock
183       \arg        RCU_SRAM2_SLP: SRAM2 clock
184       \arg        RCU_DMAx_SLP (x=0,1): DMA clock
185       \arg        RCU_IPA_SLP: IPA clock
186       \arg        RCU_ENET_SLP: ENET clock
187       \arg        RCU_ENETTX_SLP: ENETTX clock
188       \arg        RCU_ENETRX_SLP: ENETRX clock
189       \arg        RCU_ENETPTP_SLP: ENETPTP clock
190       \arg        RCU_USBHS_SLP: USBHS clock
191       \arg        RCU_USBHSULPI_SLP: USBHSULPI clock
192       \arg        RCU_DCI_SLP: DCI clock
193       \arg        RCU_TRNG_SLP: TRNG clock
194       \arg        RCU_USBFS_SLP: USBFS clock
195       \arg        RCU_EXMC_SLP: EXMC clock
196       \arg        RCU_TIMERx_SLP (x=0,1,2,3,4,5,6,7,8,9,10,11,12,13): TIMER clock
197       \arg        RCU_WWDGT_SLP: WWDGT clock
198       \arg        RCU_SPIx_SLP (x=0,1,2,3,4,5): SPI clock
199       \arg        RCU_USARTx_SLP (x=0,1,2,5): USART clock
200       \arg        RCU_UARTx_SLP (x=3,4,6,7): UART clock
201       \arg        RCU_I2Cx_SLP (x=0,1,2): I2C clock
202       \arg        RCU_CANx_SLP (x=0,1): CAN clock
203       \arg        RCU_PMU_SLP: PMU clock
204       \arg        RCU_DAC_SLP: DAC clock
205       \arg        RCU_RTC_SLP: RTC clock
206       \arg        RCU_ADCx_SLP (x=0,1,2): ADC clock
207       \arg        RCU_SDIO_SLP: SDIO clock
208       \arg        RCU_SYSCFG_SLP: SYSCFG clock
209       \arg        RCU_TLI_SLP: TLI clock
210       \arg        RCU_CTC_SLP: CTC clock
211       \arg        RCU_IREF_SLP: IREF clock
212     \param[out] none
213     \retval     none
214 */
rcu_periph_clock_sleep_enable(rcu_periph_sleep_enum periph)215 void rcu_periph_clock_sleep_enable(rcu_periph_sleep_enum periph)
216 {
217     RCU_REG_VAL(periph) |= BIT(RCU_BIT_POS(periph));
218 }
219 
220 /*!
221     \brief    disable the peripherals clock when sleep mode
222     \param[in]  periph: RCU peripherals, refer to rcu_periph_sleep_enum
223                 only one parameter can be selected which is shown as below:
224       \arg        RCU_GPIOx_SLP (x=A,B,C,D,E,F,G,H,I): GPIO ports clock
225       \arg        RCU_CRC_SLP: CRC clock
226       \arg        RCU_FMC_SLP: FMC clock
227       \arg        RCU_SRAM0_SLP: SRAM0 clock
228       \arg        RCU_SRAM1_SLP: SRAM1 clock
229       \arg        RCU_BKPSRAM: BKPSRAM clock
230       \arg        RCU_SRAM2_SLP: SRAM2 clock
231       \arg        RCU_DMAx_SLP (x=0,1): DMA clock
232       \arg        RCU_IPA_SLP: IPA clock
233       \arg        RCU_ENET_SLP: ENET clock
234       \arg        RCU_ENETTX_SLP: ENETTX clock
235       \arg        RCU_ENETRX_SLP: ENETRX clock
236       \arg        RCU_ENETPTP_SLP: ENETPTP clock
237       \arg        RCU_USBHS_SLP: USBHS clock
238       \arg        RCU_USBHSULPI_SLP: USBHSULPI clock
239       \arg        RCU_DCI_SLP: DCI clock
240       \arg        RCU_TRNG_SLP: TRNG clock
241       \arg        RCU_USBFS_SLP: USBFS clock
242       \arg        RCU_EXMC_SLP: EXMC clock
243       \arg        RCU_TIMERx_SLP (x=0,1,2,3,4,5,6,7,8,9,10,11,12,13): TIMER clock
244       \arg        RCU_WWDGT_SLP: WWDGT clock
245       \arg        RCU_SPIx_SLP (x=0,1,2,3,4,5): SPI clock
246       \arg        RCU_USARTx_SLP (x=0,1,2,5): USART clock
247       \arg        RCU_UARTx_SLP (x=3,4,6,7): UART clock
248       \arg        RCU_I2Cx_SLP (x=0,1,2): I2C clock
249       \arg        RCU_CANx_SLP (x=0,1): CAN clock
250       \arg        RCU_PMU_SLP: PMU clock
251       \arg        RCU_DAC_SLP: DAC clock
252       \arg        RCU_RTC_SLP: RTC clock
253       \arg        RCU_ADCx_SLP (x=0,1,2): ADC clock
254       \arg        RCU_SDIO_SLP: SDIO clock
255       \arg        RCU_SYSCFG_SLP: SYSCFG clock
256       \arg        RCU_TLI_SLP: TLI clock
257       \arg        RCU_CTC_SLP: CTC clock
258       \arg        RCU_IREF_SLP: IREF clock
259     \param[out] none
260     \retval     none
261 */
rcu_periph_clock_sleep_disable(rcu_periph_sleep_enum periph)262 void rcu_periph_clock_sleep_disable(rcu_periph_sleep_enum periph)
263 {
264     RCU_REG_VAL(periph) &= ~BIT(RCU_BIT_POS(periph));
265 }
266 
267 /*!
268     \brief    reset the peripherals
269     \param[in]  periph_reset: RCU peripherals reset, refer to rcu_periph_reset_enum
270                 only one parameter can be selected which is shown as below:
271       \arg        RCU_GPIOxRST (x=A,B,C,D,E,F,G,H,I): reset GPIO ports
272       \arg        RCU_CRCRST: reset CRC
273       \arg        RCU_DMAxRST (x=0,1): reset DMA
274       \arg        RCU_IPARST: reset IPA
275       \arg        RCU_ENETRST: reset ENET
276       \arg        RCU_USBHSRST: reset USBHS
277       \arg        RCU_DCIRST: reset DCI
278       \arg        RCU_TRNGRST: reset TRNG
279       \arg        RCU_USBFSRST: reset USBFS
280       \arg        RCU_EXMCRST: reset EXMC
281       \arg        RCU_TIMERxRST (x=0,1,2,3,4,5,6,7,8,9,10,11,12,13): reset TIMER
282       \arg        RCU_WWDGTRST: reset WWDGT
283       \arg        RCU_SPIxRST (x=0,1,2,3,4,5): reset SPI
284       \arg        RCU_USARTxRST (x=0,1,2,5): reset USART
285       \arg        RCU_UARTxRST (x=3,4,6,7): reset UART
286       \arg        RCU_I2CxRST (x=0,1,2): reset I2C
287       \arg        RCU_CANxRST (x=0,1): reset CAN
288       \arg        RCU_PMURST: reset PMU
289       \arg        RCU_DACRST: reset DAC
290       \arg        RCU_ADCRST (x=0,1,2): reset ADC
291       \arg        RCU_SDIORST: reset SDIO
292       \arg        RCU_SYSCFGRST: reset SYSCFG
293       \arg        RCU_TLIRST: reset TLI
294       \arg        RCU_CTCRST: reset CTC
295       \arg        RCU_IREFRST: reset IREF
296     \param[out] none
297     \retval     none
298 */
rcu_periph_reset_enable(rcu_periph_reset_enum periph_reset)299 void rcu_periph_reset_enable(rcu_periph_reset_enum periph_reset)
300 {
301     RCU_REG_VAL(periph_reset) |= BIT(RCU_BIT_POS(periph_reset));
302 }
303 
304 /*!
305     \brief    disable reset the peripheral
306     \param[in]  periph_reset: RCU peripherals reset, refer to rcu_periph_reset_enum
307                 only one parameter can be selected which is shown as below:
308       \arg        RCU_GPIOxRST (x=A,B,C,D,E,F,G,H,I): reset GPIO ports
309       \arg        RCU_CRCRST: reset CRC
310       \arg        RCU_DMAxRST (x=0,1): reset DMA
311       \arg        RCU_IPARST: reset IPA
312       \arg        RCU_ENETRST: reset ENET
313       \arg        RCU_USBHSRST: reset USBHS
314       \arg        RCU_DCIRST: reset DCI
315       \arg        RCU_TRNGRST: reset TRNG
316       \arg        RCU_USBFSRST: reset USBFS
317       \arg        RCU_EXMCRST: reset EXMC
318       \arg        RCU_TIMERxRST (x=0,1,2,3,4,5,6,7,8,9,10,11,12,13): reset TIMER
319       \arg        RCU_WWDGTRST: reset WWDGT
320       \arg        RCU_SPIxRST (x=0,1,2,3,4,5): reset SPI
321       \arg        RCU_USARTxRST (x=0,1,2,5): reset USART
322       \arg        RCU_UARTxRST (x=3,4,6,7): reset UART
323       \arg        RCU_I2CxRST (x=0,1,2): reset I2C
324       \arg        RCU_CANxRST (x=0,1): reset CAN
325       \arg        RCU_PMURST: reset PMU
326       \arg        RCU_DACRST: reset DAC
327       \arg        RCU_ADCRST (x=0,1,2): reset ADC
328       \arg        RCU_SDIORST: reset SDIO
329       \arg        RCU_SYSCFGRST: reset SYSCFG
330       \arg        RCU_TLIRST: reset TLI
331       \arg        RCU_CTCRST: reset CTC
332       \arg        RCU_IREFRST: reset IREF
333     \param[out] none
334     \retval     none
335 */
rcu_periph_reset_disable(rcu_periph_reset_enum periph_reset)336 void rcu_periph_reset_disable(rcu_periph_reset_enum periph_reset)
337 {
338     RCU_REG_VAL(periph_reset) &= ~BIT(RCU_BIT_POS(periph_reset));
339 }
340 
341 /*!
342     \brief    reset the BKP
343     \param[in]  none
344     \param[out] none
345     \retval     none
346 */
rcu_bkp_reset_enable(void)347 void rcu_bkp_reset_enable(void)
348 {
349     RCU_BDCTL |= RCU_BDCTL_BKPRST;
350 }
351 
352 /*!
353     \brief    disable the BKP reset
354     \param[in]  none
355     \param[out] none
356     \retval     none
357 */
rcu_bkp_reset_disable(void)358 void rcu_bkp_reset_disable(void)
359 {
360     RCU_BDCTL &= ~RCU_BDCTL_BKPRST;
361 }
362 
363 /*!
364     \brief    configure the system clock source
365     \param[in]  ck_sys: system clock source select
366                 only one parameter can be selected which is shown as below:
367       \arg        RCU_CKSYSSRC_IRC16M: select CK_IRC16M as the CK_SYS source
368       \arg        RCU_CKSYSSRC_HXTAL: select CK_HXTAL as the CK_SYS source
369       \arg        RCU_CKSYSSRC_PLLP: select CK_PLLP as the CK_SYS source
370     \param[out] none
371     \retval     none
372 */
rcu_system_clock_source_config(uint32_t ck_sys)373 void rcu_system_clock_source_config(uint32_t ck_sys)
374 {
375     uint32_t reg;
376 
377     reg = RCU_CFG0;
378     /* reset the SCS bits and set according to ck_sys */
379     reg &= ~RCU_CFG0_SCS;
380     RCU_CFG0 = (reg | ck_sys);
381 }
382 
383 /*!
384     \brief    get the system clock source
385     \param[in]  none
386     \param[out] none
387     \retval     which clock is selected as CK_SYS source
388       \arg        RCU_SCSS_IRC16M: CK_IRC16M is selected as the CK_SYS source
389       \arg        RCU_SCSS_HXTAL: CK_HXTAL is selected as the CK_SYS source
390       \arg        RCU_SCSS_PLLP: CK_PLLP is selected as the CK_SYS source
391 */
rcu_system_clock_source_get(void)392 uint32_t rcu_system_clock_source_get(void)
393 {
394     return (RCU_CFG0 & RCU_CFG0_SCSS);
395 }
396 
397 /*!
398     \brief    configure the AHB clock prescaler selection
399     \param[in]  ck_ahb: AHB clock prescaler selection
400                 only one parameter can be selected which is shown as below:
401       \arg        RCU_AHB_CKSYS_DIVx, x=1, 2, 4, 8, 16, 64, 128, 256, 512
402     \param[out] none
403     \retval     none
404 */
rcu_ahb_clock_config(uint32_t ck_ahb)405 void rcu_ahb_clock_config(uint32_t ck_ahb)
406 {
407     uint32_t reg;
408 
409     reg = RCU_CFG0;
410     /* reset the AHBPSC bits and set according to ck_ahb */
411     reg &= ~RCU_CFG0_AHBPSC;
412     RCU_CFG0 = (reg | ck_ahb);
413 }
414 
415 /*!
416     \brief    configure the APB1 clock prescaler selection
417     \param[in]  ck_apb1: APB1 clock prescaler selection
418                 only one parameter can be selected which is shown as below:
419       \arg        RCU_APB1_CKAHB_DIV1: select CK_AHB as CK_APB1
420       \arg        RCU_APB1_CKAHB_DIV2: select CK_AHB/2 as CK_APB1
421       \arg        RCU_APB1_CKAHB_DIV4: select CK_AHB/4 as CK_APB1
422       \arg        RCU_APB1_CKAHB_DIV8: select CK_AHB/8 as CK_APB1
423       \arg        RCU_APB1_CKAHB_DIV16: select CK_AHB/16 as CK_APB1
424     \param[out] none
425     \retval     none
426 */
rcu_apb1_clock_config(uint32_t ck_apb1)427 void rcu_apb1_clock_config(uint32_t ck_apb1)
428 {
429     uint32_t reg;
430 
431     reg = RCU_CFG0;
432     /* reset the APB1PSC and set according to ck_apb1 */
433     reg &= ~RCU_CFG0_APB1PSC;
434     RCU_CFG0 = (reg | ck_apb1);
435 }
436 
437 /*!
438     \brief    configure the APB2 clock prescaler selection
439     \param[in]  ck_apb2: APB2 clock prescaler selection
440                 only one parameter can be selected which is shown as below:
441       \arg        RCU_APB2_CKAHB_DIV1: select CK_AHB as CK_APB2
442       \arg        RCU_APB2_CKAHB_DIV2: select CK_AHB/2 as CK_APB2
443       \arg        RCU_APB2_CKAHB_DIV4: select CK_AHB/4 as CK_APB2
444       \arg        RCU_APB2_CKAHB_DIV8: select CK_AHB/8 as CK_APB2
445       \arg        RCU_APB2_CKAHB_DIV16: select CK_AHB/16 as CK_APB2
446     \param[out] none
447     \retval     none
448 */
rcu_apb2_clock_config(uint32_t ck_apb2)449 void rcu_apb2_clock_config(uint32_t ck_apb2)
450 {
451     uint32_t reg;
452 
453     reg = RCU_CFG0;
454     /* reset the APB2PSC and set according to ck_apb2 */
455     reg &= ~RCU_CFG0_APB2PSC;
456     RCU_CFG0 = (reg | ck_apb2);
457 }
458 
459 /*!
460     \brief    configure the CK_OUT0 clock source and divider
461     \param[in]  ckout0_src: CK_OUT0 clock source selection
462                 only one parameter can be selected which is shown as below:
463       \arg        RCU_CKOUT0SRC_IRC16M: IRC16M selected
464       \arg        RCU_CKOUT0SRC_LXTAL: LXTAL selected
465       \arg        RCU_CKOUT0SRC_HXTAL: HXTAL selected
466       \arg        RCU_CKOUT0SRC_PLLP: PLLP selected
467     \param[in]  ckout0_div: CK_OUT0 divider
468       \arg        RCU_CKOUT0_DIVx(x=1,2,3,4,5): CK_OUT0 is divided by x
469     \param[out] none
470     \retval     none
471 */
rcu_ckout0_config(uint32_t ckout0_src,uint32_t ckout0_div)472 void rcu_ckout0_config(uint32_t ckout0_src, uint32_t ckout0_div)
473 {
474     uint32_t reg;
475 
476     reg = RCU_CFG0;
477     /* reset the CKOUT0SRC, CKOUT0DIV and set according to ckout0_src and ckout0_div */
478     reg &= ~(RCU_CFG0_CKOUT0SEL | RCU_CFG0_CKOUT0DIV);
479     RCU_CFG0 = (reg | ckout0_src | ckout0_div);
480 }
481 
482 /*!
483     \brief    configure the CK_OUT1 clock source and divider
484     \param[in]  ckout1_src: CK_OUT1 clock source selection
485                 only one parameter can be selected which is shown as below:
486       \arg        RCU_CKOUT1SRC_SYSTEMCLOCK: system clock selected
487       \arg        RCU_CKOUT1SRC_PLLI2SR: PLLI2SR selected
488       \arg        RCU_CKOUT1SRC_HXTAL: HXTAL selected
489       \arg        RCU_CKOUT1SRC_PLLP: PLLP selected
490     \param[in]  ckout1_div: CK_OUT1 divider
491       \arg        RCU_CKOUT1_DIVx(x=1,2,3,4,5): CK_OUT1 is divided by x
492     \param[out] none
493     \retval     none
494 */
rcu_ckout1_config(uint32_t ckout1_src,uint32_t ckout1_div)495 void rcu_ckout1_config(uint32_t ckout1_src, uint32_t ckout1_div)
496 {
497     uint32_t reg;
498 
499     reg = RCU_CFG0;
500     /* reset the CKOUT1SRC, CKOUT1DIV and set according to ckout1_src and ckout1_div */
501     reg &= ~(RCU_CFG0_CKOUT1SEL | RCU_CFG0_CKOUT1DIV);
502     RCU_CFG0 = (reg | ckout1_src | ckout1_div);
503 }
504 
505 /*!
506     \brief    configure the main PLL clock
507     \param[in]  pll_src: PLL clock source selection
508       \arg        RCU_PLLSRC_IRC16M: select IRC16M as PLL source clock
509       \arg        RCU_PLLSRC_HXTAL: select HXTAL as PLL source clock
510     \param[in]  pll_psc: the PLL VCO source clock prescaler
511       \arg         this parameter should be selected between 2 and 63
512     \param[in]  pll_n: the PLL VCO clock multi factor
513       \arg        this parameter should be selected between 64 and 500
514     \param[in]  pll_p: the PLLP output frequency division factor from PLL VCO clock
515       \arg        this parameter should be selected 2,4,6,8
516     \param[in]  pll_q: the PLL Q output frequency division factor from PLL VCO clock
517       \arg        this parameter should be selected between 2 and 15
518     \param[out] none
519     \retval     ErrStatus: SUCCESS or ERROR
520 */
rcu_pll_config(uint32_t pll_src,uint32_t pll_psc,uint32_t pll_n,uint32_t pll_p,uint32_t pll_q)521 ErrStatus rcu_pll_config(uint32_t pll_src, uint32_t pll_psc, uint32_t pll_n, uint32_t pll_p, uint32_t pll_q)
522 {
523     uint32_t ss_modulation_inc;
524     uint32_t ss_modulation_reg;
525 
526     ss_modulation_inc = 0U;
527     ss_modulation_reg = RCU_PLLSSCTL;
528 
529     /* calculate the minimum factor of PLLN */
530     if((ss_modulation_reg & RCU_PLLSSCTL_SSCGON) == RCU_PLLSSCTL_SSCGON) {
531         if((ss_modulation_reg & RCU_SS_TYPE_DOWN) == RCU_SS_TYPE_DOWN) {
532             ss_modulation_inc += RCU_SS_MODULATION_DOWN_INC;
533         } else {
534             ss_modulation_inc += RCU_SS_MODULATION_CENTER_INC;
535         }
536     }
537 
538     /* check the function parameter */
539     if(CHECK_PLL_PSC_VALID(pll_psc) && CHECK_PLL_N_VALID(pll_n, ss_modulation_inc) &&
540             CHECK_PLL_P_VALID(pll_p) && CHECK_PLL_Q_VALID(pll_q)) {
541         RCU_PLL = pll_psc | (pll_n << 6) | (((pll_p >> 1) - 1U) << 16) |
542                   (pll_src) | (pll_q << 24);
543     } else {
544         /* return status */
545         return ERROR;
546     }
547 
548     /* return status */
549     return SUCCESS;
550 }
551 
552 /*!
553     \brief    configure the PLLI2S clock
554     \param[in]  plli2s_n: the PLLI2S VCO clock multi factor
555       \arg        this parameter should be selected between 50 and 500
556     \param[in]  plli2s_r: the PLLI2S R output frequency division factor from PLLI2S VCO clock
557       \arg        this parameter should be selected between 2 and 7
558     \param[out] none
559     \retval     ErrStatus: SUCCESS or ERROR
560 */
rcu_plli2s_config(uint32_t plli2s_n,uint32_t plli2s_r)561 ErrStatus rcu_plli2s_config(uint32_t plli2s_n, uint32_t plli2s_r)
562 {
563     /* check the function parameter */
564     if(CHECK_PLLI2S_N_VALID(plli2s_n) && CHECK_PLLI2S_R_VALID(plli2s_r)) {
565         RCU_PLLI2S = (plli2s_n << 6) | (plli2s_r << 28);
566     } else {
567         /* return status */
568         return ERROR;
569     }
570 
571     /* return status */
572     return SUCCESS;
573 }
574 
575 /*!
576     \brief    configure the PLLSAI clock
577     \param[in]  pllsai_n: the PLLSAI VCO clock multi factor
578       \arg        this parameter should be selected between 50 and 500
579     \param[in]  pllsai_p: the PLLSAI P output frequency division factor from PLL VCO clock
580       \arg        this parameter should be selected 2,4,6,8
581     \param[in]  pllsai_r: the PLLSAI R output frequency division factor from PLL VCO clock
582       \arg        this parameter should be selected between 2 and 7
583     \param[out] none
584     \retval     ErrStatus: SUCCESS or ERROR
585 */
rcu_pllsai_config(uint32_t pllsai_n,uint32_t pllsai_p,uint32_t pllsai_r)586 ErrStatus rcu_pllsai_config(uint32_t pllsai_n, uint32_t pllsai_p, uint32_t pllsai_r)
587 {
588     /* check the function parameter */
589     if(CHECK_PLLSAI_N_VALID(pllsai_n) && CHECK_PLLSAI_P_VALID(pllsai_p) && CHECK_PLLSAI_R_VALID(pllsai_r)) {
590         RCU_PLLSAI = (pllsai_n << 6U) | (((pllsai_p >> 1U) - 1U) << 16U) | (pllsai_r << 28U);
591     } else {
592         /* return status */
593         return ERROR;
594     }
595 
596     /* return status */
597     return SUCCESS;
598 }
599 
600 /*!
601     \brief    configure the RTC clock source selection
602     \param[in]  rtc_clock_source: RTC clock source selection
603                 only one parameter can be selected which is shown as below:
604       \arg        RCU_RTCSRC_NONE: no clock selected
605       \arg        RCU_RTCSRC_LXTAL: CK_LXTAL selected as RTC source clock
606       \arg        RCU_RTCSRC_IRC32K: CK_IRC32K selected as RTC source clock
607       \arg        RCU_RTCSRC_HXTAL_DIV_RTCDIV: CK_HXTAL/RTCDIV selected as RTC source clock
608     \param[out] none
609     \retval     none
610 */
rcu_rtc_clock_config(uint32_t rtc_clock_source)611 void rcu_rtc_clock_config(uint32_t rtc_clock_source)
612 {
613     uint32_t reg;
614 
615     reg = RCU_BDCTL;
616     /* reset the RTCSRC bits and set according to rtc_clock_source */
617     reg &= ~RCU_BDCTL_RTCSRC;
618     RCU_BDCTL = (reg | rtc_clock_source);
619 }
620 
621 /*!
622     \brief    configure the frequency division of RTC clock when HXTAL was selected as its clock source
623     \param[in]  rtc_div: RTC clock frequency division
624                 only one parameter can be selected which is shown as below:
625       \arg        RCU_RTC_HXTAL_NONE: no clock for RTC
626       \arg        RCU_RTC_HXTAL_DIVx: RTCDIV clock select CK_HXTAL/x, x = 2....31
627     \param[out] none
628     \retval     none
629 */
rcu_rtc_div_config(uint32_t rtc_div)630 void rcu_rtc_div_config(uint32_t rtc_div)
631 {
632     uint32_t reg;
633 
634     reg = RCU_CFG0;
635     /* reset the RTCDIV bits and set according to rtc_div value */
636     reg &= ~RCU_CFG0_RTCDIV;
637     RCU_CFG0 = (reg | rtc_div);
638 }
639 
640 
641 /*!
642     \brief    configure the I2S clock source selection
643     \param[in]  i2s_clock_source: I2S clock source selection
644                 only one parameter can be selected which is shown as below:
645       \arg        RCU_I2SSRC_PLLI2S: CK_PLLI2S selected as I2S source clock
646       \arg        RCU_I2SSRC_I2S_CKIN: external i2s_ckin pin selected as I2S source clock
647     \param[out] none
648     \retval     none
649 */
rcu_i2s_clock_config(uint32_t i2s_clock_source)650 void rcu_i2s_clock_config(uint32_t i2s_clock_source)
651 {
652     uint32_t reg;
653 
654     reg = RCU_CFG0;
655     /* reset the I2SSEL bit and set according to i2s_clock_source */
656     reg &= ~RCU_CFG0_I2SSEL;
657     RCU_CFG0 = (reg | i2s_clock_source);
658 }
659 
660 /*!
661     \brief    configure the CK48M clock source selection
662     \param[in]  ck48m_clock_source: CK48M clock source selection
663                 only one parameter can be selected which is shown as below:
664       \arg        RCU_CK48MSRC_PLL48M: CK_PLL48M selected as CK48M source clock
665       \arg        RCU_CK48MSRC_IRC48M: CK_IRC48M selected as CK48M source clock
666     \param[out] none
667     \retval     none
668 */
rcu_ck48m_clock_config(uint32_t ck48m_clock_source)669 void rcu_ck48m_clock_config(uint32_t ck48m_clock_source)
670 {
671     uint32_t reg;
672 
673     reg = RCU_ADDCTL;
674     /* reset the CK48MSEL bit and set according to i2s_clock_source */
675     reg &= ~RCU_ADDCTL_CK48MSEL;
676     RCU_ADDCTL = (reg | ck48m_clock_source);
677 }
678 
679 /*!
680     \brief    configure the PLL48M clock source selection
681     \param[in]  pll48m_clock_source: PLL48M clock source selection
682                 only one parameter can be selected which is shown as below:
683       \arg        RCU_PLL48MSRC_PLLQ: CK_PLLQ selected as PLL48M source clock
684       \arg        RCU_PLL48MSRC_PLLSAIP: CK_PLLSAIP selected as PLL48M source clock
685     \param[out] none
686     \retval     none
687 */
rcu_pll48m_clock_config(uint32_t pll48m_clock_source)688 void rcu_pll48m_clock_config(uint32_t pll48m_clock_source)
689 {
690     uint32_t reg;
691 
692     reg = RCU_ADDCTL;
693     /* reset the PLL48MSEL bit and set according to pll48m_clock_source */
694     reg &= ~RCU_ADDCTL_PLL48MSEL;
695     RCU_ADDCTL = (reg | pll48m_clock_source);
696 }
697 
698 /*!
699     \brief    configure the TIMER clock prescaler selection
700     \param[in]  timer_clock_prescaler: TIMER clock selection
701                 only one parameter can be selected which is shown as below:
702       \arg        RCU_TIMER_PSC_MUL2: if APB1PSC/APB2PSC in RCU_CFG0 register is 0b0xx(CK_APBx = CK_AHB)
703                                       or 0b100(CK_APBx = CK_AHB/2), the TIMER clock is equal to CK_AHB(CK_TIMERx = CK_AHB).
704                                       or else, the TIMER clock is twice the corresponding APB clock (TIMER in APB1 domain: CK_TIMERx = 2 x CK_APB1;
705                                       TIMER in APB2 domain: CK_TIMERx = 2 x CK_APB2)
706       \arg        RCU_TIMER_PSC_MUL4: if APB1PSC/APB2PSC in RCU_CFG0 register is 0b0xx(CK_APBx = CK_AHB),
707                                       0b100(CK_APBx = CK_AHB/2), or 0b101(CK_APBx = CK_AHB/4), the TIMER clock is equal to CK_AHB(CK_TIMERx = CK_AHB).
708                                       or else, the TIMER clock is four timers the corresponding APB clock (TIMER in APB1 domain: CK_TIMERx = 4 x CK_APB1;
709                                       TIMER in APB2 domain: CK_TIMERx = 4 x CK_APB2)
710     \param[out] none
711     \retval     none
712 */
rcu_timer_clock_prescaler_config(uint32_t timer_clock_prescaler)713 void rcu_timer_clock_prescaler_config(uint32_t timer_clock_prescaler)
714 {
715     /* configure the TIMERSEL bit and select the TIMER clock prescaler */
716     if(timer_clock_prescaler == RCU_TIMER_PSC_MUL2) {
717         RCU_CFG1 &= timer_clock_prescaler;
718     } else {
719         RCU_CFG1 |= timer_clock_prescaler;
720     }
721 }
722 
723 /*!
724     \brief    configure the PLLSAIR divider used as input of TLI
725     \param[in]  pllsai_r_div: PLLSAIR divider used as input of TLI
726                 only one parameter can be selected which is shown as below:
727       \arg        RCU_PLLSAIR_DIVx(x=2,4,8,16): PLLSAIR divided x used as input of TLI
728     \param[out] none
729     \retval     none
730 */
rcu_tli_clock_div_config(uint32_t pllsai_r_div)731 void rcu_tli_clock_div_config(uint32_t pllsai_r_div)
732 {
733     uint32_t reg;
734 
735     reg = RCU_CFG1;
736     /* reset the PLLSAIRDIV bit and set according to pllsai_r_div */
737     reg &= ~RCU_CFG1_PLLSAIRDIV;
738     RCU_CFG1 = (reg | pllsai_r_div);
739 }
740 
741 /*!
742     \brief    get the clock stabilization and periphral reset flags
743     \param[in]  flag: the clock stabilization and periphral reset flags, refer to rcu_flag_enum
744                 only one parameter can be selected which is shown as below:
745       \arg        RCU_FLAG_IRC16MSTB: IRC16M stabilization flag
746       \arg        RCU_FLAG_HXTALSTB: HXTAL stabilization flag
747       \arg        RCU_FLAG_PLLSTB: PLL stabilization flag
748       \arg        RCU_FLAG_PLLI2SSTB: PLLI2S stabilization flag
749       \arg        RCU_FLAG_PLLSAISTB: PLLSAI stabilization flag
750       \arg        RCU_FLAG_LXTALSTB: LXTAL stabilization flag
751       \arg        RCU_FLAG_IRC32KSTB: IRC32K stabilization flag
752       \arg        RCU_FLAG_IRC48MSTB: IRC48M stabilization flag
753       \arg        RCU_FLAG_BORRST: BOR reset flags
754       \arg        RCU_FLAG_EPRST: external PIN reset flag
755       \arg        RCU_FLAG_PORRST: Power reset flag
756       \arg        RCU_FLAG_SWRST: software reset flag
757       \arg        RCU_FLAG_FWDGTRST: free watchdog timer reset flag
758       \arg        RCU_FLAG_WWDGTRST: window watchdog timer reset flag
759       \arg        RCU_FLAG_LPRST: low-power reset flag
760     \param[out] none
761     \retval     none
762 */
rcu_flag_get(rcu_flag_enum flag)763 FlagStatus rcu_flag_get(rcu_flag_enum flag)
764 {
765     /* get the rcu flag */
766     if(RESET != (RCU_REG_VAL(flag) & BIT(RCU_BIT_POS(flag)))) {
767         return SET;
768     } else {
769         return RESET;
770     }
771 }
772 
773 /*!
774     \brief    clear all the reset flag
775     \param[in]  none
776     \param[out] none
777     \retval     none
778 */
rcu_all_reset_flag_clear(void)779 void rcu_all_reset_flag_clear(void)
780 {
781     RCU_RSTSCK |= RCU_RSTSCK_RSTFC;
782 }
783 
784 /*!
785     \brief    get the clock stabilization interrupt and ckm flags
786     \param[in]  int_flag: interrupt and ckm flags, refer to rcu_int_flag_enum
787                 only one parameter can be selected which is shown as below:
788       \arg        RCU_INT_FLAG_IRC32KSTB: IRC32K stabilization interrupt flag
789       \arg        RCU_INT_FLAG_LXTALSTB: LXTAL stabilization interrupt flag
790       \arg        RCU_INT_FLAG_IRC16MSTB: IRC16M stabilization interrupt flag
791       \arg        RCU_INT_FLAG_HXTALSTB: HXTAL stabilization interrupt flag
792       \arg        RCU_INT_FLAG_PLLSTB: PLL stabilization interrupt flag
793       \arg        RCU_INT_FLAG_PLLI2SSTB: PLLI2S stabilization interrupt flag
794       \arg        RCU_INT_FLAG_PLLSAISTB: PLLSAI stabilization interrupt flag
795       \arg        RCU_INT_FLAG_CKM: HXTAL clock stuck interrupt flag
796       \arg        RCU_INT_FLAG_IRC48MSTB: IRC48M stabilization interrupt flag
797     \param[out] none
798     \retval     FlagStatus: SET or RESET
799 */
rcu_interrupt_flag_get(rcu_int_flag_enum int_flag)800 FlagStatus rcu_interrupt_flag_get(rcu_int_flag_enum int_flag)
801 {
802     /* get the rcu interrupt flag */
803     if(RESET != (RCU_REG_VAL(int_flag) & BIT(RCU_BIT_POS(int_flag)))) {
804         return SET;
805     } else {
806         return RESET;
807     }
808 }
809 
810 /*!
811     \brief    clear the interrupt flags
812     \param[in]  int_flag: clock stabilization and stuck interrupt flags clear, refer to rcu_int_flag_clear_enum
813                 only one parameter can be selected which is shown as below:
814       \arg        RCU_INT_FLAG_IRC32KSTB_CLR: IRC32K stabilization interrupt flag clear
815       \arg        RCU_INT_FLAG_LXTALSTB_CLR: LXTAL stabilization interrupt flag clear
816       \arg        RCU_INT_FLAG_IRC16MSTB_CLR: IRC16M stabilization interrupt flag clear
817       \arg        RCU_INT_FLAG_HXTALSTB_CLR: HXTAL stabilization interrupt flag clear
818       \arg        RCU_INT_FLAG_PLLSTB_CLR: PLL stabilization interrupt flag clear
819       \arg        RCU_INT_FLAG_PLLI2SSTB_CLR: PLLI2S stabilization interrupt flag clear
820       \arg        RCU_INT_FLAG_PLLSAISTB_CLR: PLLSAI stabilization interrupt flag clear
821       \arg        RCU_INT_FLAG_CKM_CLR: clock stuck interrupt flag clear
822       \arg        RCU_INT_FLAG_IRC48MSTB_CLR: IRC48M stabilization interrupt flag clear
823     \param[out] none
824     \retval     none
825 */
rcu_interrupt_flag_clear(rcu_int_flag_clear_enum int_flag)826 void rcu_interrupt_flag_clear(rcu_int_flag_clear_enum int_flag)
827 {
828     RCU_REG_VAL(int_flag) |= BIT(RCU_BIT_POS(int_flag));
829 }
830 
831 /*!
832     \brief    enable the stabilization interrupt
833     \param[in]  interrupt: clock stabilization interrupt, refer to rcu_int_enum
834                 Only one parameter can be selected which is shown as below:
835       \arg        RCU_INT_IRC32KSTB: IRC32K stabilization interrupt enable
836       \arg        RCU_INT_LXTALSTB: LXTAL stabilization interrupt enable
837       \arg        RCU_INT_IRC16MSTB: IRC16M stabilization interrupt enable
838       \arg        RCU_INT_HXTALSTB: HXTAL stabilization interrupt enable
839       \arg        RCU_INT_PLLSTB: PLL stabilization interrupt enable
840       \arg        RCU_INT_PLLI2SSTB: PLLI2S stabilization interrupt enable
841       \arg        RCU_INT_PLLSAISTB: PLLSAI stabilization interrupt enable
842       \arg        RCU_INT_IRC48MSTB: IRC48M stabilization interrupt enable
843     \param[out] none
844     \retval     none
845 */
rcu_interrupt_enable(rcu_int_enum interrupt)846 void rcu_interrupt_enable(rcu_int_enum interrupt)
847 {
848     RCU_REG_VAL(interrupt) |= BIT(RCU_BIT_POS(interrupt));
849 }
850 
851 
852 /*!
853     \brief    disable the stabilization interrupt
854     \param[in]  interrupt: clock stabilization interrupt, refer to rcu_int_enum
855                 only one parameter can be selected which is shown as below:
856       \arg        RCU_INT_IRC32KSTB: IRC32K stabilization interrupt disable
857       \arg        RCU_INT_LXTALSTB: LXTAL stabilization interrupt disable
858       \arg        RCU_INT_IRC16MSTB: IRC16M stabilization interrupt disable
859       \arg        RCU_INT_HXTALSTB: HXTAL stabilization interrupt disable
860       \arg        RCU_INT_PLLSTB: PLL stabilization interrupt disable
861       \arg        RCU_INT_PLLI2SSTB: PLLI2S stabilization interrupt disable
862       \arg        RCU_INT_PLLSAISTB: PLLSAI stabilization interrupt disable
863       \arg        RCU_INT_IRC48MSTB: IRC48M stabilization interrupt disable
864     \param[out] none
865     \retval     none
866 */
rcu_interrupt_disable(rcu_int_enum interrupt)867 void rcu_interrupt_disable(rcu_int_enum interrupt)
868 {
869     RCU_REG_VAL(interrupt) &= ~BIT(RCU_BIT_POS(interrupt));
870 }
871 
872 /*!
873     \brief    configure the LXTAL drive capability
874     \param[in]  lxtal_dricap: drive capability of LXTAL
875                 only one parameter can be selected which is shown as below:
876       \arg        RCU_LXTALDRI_LOWER_DRIVE: lower driving capability
877       \arg        RCU_LXTALDRI_HIGHER_DRIVE: higher driving capability
878     \param[out] none
879     \retval     none
880 */
rcu_lxtal_drive_capability_config(uint32_t lxtal_dricap)881 void rcu_lxtal_drive_capability_config(uint32_t lxtal_dricap)
882 {
883     uint32_t reg;
884 
885     reg = RCU_BDCTL;
886 
887     /* reset the LXTALDRI bits and set according to lxtal_dricap */
888     reg &= ~RCU_BDCTL_LXTALDRI;
889     RCU_BDCTL = (reg | lxtal_dricap);
890 }
891 
892 /*!
893     \brief    wait for oscillator stabilization flags is SET or oscillator startup is timeout
894     \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
895                 only one parameter can be selected which is shown as below:
896       \arg        RCU_HXTAL: HXTAL
897       \arg        RCU_LXTAL: LXTAL
898       \arg        RCU_IRC16M: IRC16M
899       \arg        RCU_IRC48M: IRC48M
900       \arg        RCU_IRC32K: IRC32K
901       \arg        RCU_PLL_CK: PLL
902       \arg        RCU_PLLI2S_CK: PLLI2S
903       \arg        RCU_PLLSAI_CK: PLLSAI
904     \param[out] none
905     \retval     ErrStatus: SUCCESS or ERROR
906 */
rcu_osci_stab_wait(rcu_osci_type_enum osci)907 ErrStatus rcu_osci_stab_wait(rcu_osci_type_enum osci)
908 {
909     uint32_t stb_cnt = 0U;
910     ErrStatus reval = ERROR;
911     FlagStatus osci_stat = RESET;
912 
913     switch(osci) {
914     /* wait HXTAL stable */
915     case RCU_HXTAL:
916         while((RESET == osci_stat) && (HXTAL_STARTUP_TIMEOUT != stb_cnt)) {
917             osci_stat = rcu_flag_get(RCU_FLAG_HXTALSTB);
918             stb_cnt++;
919         }
920 
921         /* check whether flag is set */
922         if(RESET != rcu_flag_get(RCU_FLAG_HXTALSTB)) {
923             reval = SUCCESS;
924         }
925         break;
926     /* wait LXTAL stable */
927     case RCU_LXTAL:
928         while((RESET == osci_stat) && (LXTAL_STARTUP_TIMEOUT != stb_cnt)) {
929             osci_stat = rcu_flag_get(RCU_FLAG_LXTALSTB);
930             stb_cnt++;
931         }
932 
933         /* check whether flag is set */
934         if(RESET != rcu_flag_get(RCU_FLAG_LXTALSTB)) {
935             reval = SUCCESS;
936         }
937         break;
938     /* wait IRC16M stable */
939     case RCU_IRC16M:
940         while((RESET == osci_stat) && (IRC16M_STARTUP_TIMEOUT != stb_cnt)) {
941             osci_stat = rcu_flag_get(RCU_FLAG_IRC16MSTB);
942             stb_cnt++;
943         }
944 
945         /* check whether flag is set */
946         if(RESET != rcu_flag_get(RCU_FLAG_IRC16MSTB)) {
947             reval = SUCCESS;
948         }
949         break;
950     /* wait IRC48M stable */
951     case RCU_IRC48M:
952         while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)) {
953             osci_stat = rcu_flag_get(RCU_FLAG_IRC48MSTB);
954             stb_cnt++;
955         }
956 
957         /* check whether flag is set */
958         if(RESET != rcu_flag_get(RCU_FLAG_IRC48MSTB)) {
959             reval = SUCCESS;
960         }
961         break;
962     /* wait IRC32K stable */
963     case RCU_IRC32K:
964         while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)) {
965             osci_stat = rcu_flag_get(RCU_FLAG_IRC32KSTB);
966             stb_cnt++;
967         }
968 
969         /* check whether flag is set */
970         if(RESET != rcu_flag_get(RCU_FLAG_IRC32KSTB)) {
971             reval = SUCCESS;
972         }
973         break;
974     /* wait PLL stable */
975     case RCU_PLL_CK:
976         while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)) {
977             osci_stat = rcu_flag_get(RCU_FLAG_PLLSTB);
978             stb_cnt++;
979         }
980 
981         /* check whether flag is set */
982         if(RESET != rcu_flag_get(RCU_FLAG_PLLSTB)) {
983             reval = SUCCESS;
984         }
985         break;
986     /* wait PLLI2S stable */
987     case RCU_PLLI2S_CK:
988         while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)) {
989             osci_stat = rcu_flag_get(RCU_FLAG_PLLI2SSTB);
990             stb_cnt++;
991         }
992 
993         /* check whether flag is set */
994         if(RESET != rcu_flag_get(RCU_FLAG_PLLI2SSTB)) {
995             reval = SUCCESS;
996         }
997         break;
998     /* wait PLLSAI stable */
999     case RCU_PLLSAI_CK:
1000         while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)) {
1001             osci_stat = rcu_flag_get(RCU_FLAG_PLLSAISTB);
1002             stb_cnt++;
1003         }
1004 
1005         /* check whether flag is set */
1006         if(RESET != rcu_flag_get(RCU_FLAG_PLLSAISTB)) {
1007             reval = SUCCESS;
1008         }
1009         break;
1010 
1011     default:
1012         break;
1013     }
1014 
1015     /* return value */
1016     return reval;
1017 }
1018 
1019 /*!
1020     \brief    turn on the oscillator
1021     \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
1022                 only one parameter can be selected which is shown as below:
1023       \arg        RCU_HXTAL: HXTAL
1024       \arg        RCU_LXTAL: LXTAL
1025       \arg        RCU_IRC16M: IRC16M
1026       \arg        RCU_IRC48M: IRC48M
1027       \arg        RCU_IRC32K: IRC32K
1028       \arg        RCU_PLL_CK: PLL
1029       \arg        RCU_PLLI2S_CK: PLLI2S
1030       \arg        RCU_PLLSAI_CK: PLLSAI
1031     \param[out] none
1032     \retval     none
1033 */
rcu_osci_on(rcu_osci_type_enum osci)1034 void rcu_osci_on(rcu_osci_type_enum osci)
1035 {
1036     RCU_REG_VAL(osci) |= BIT(RCU_BIT_POS(osci));
1037 }
1038 
1039 /*!
1040     \brief    turn off the oscillator
1041     \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
1042                 only one parameter can be selected which is shown as below:
1043       \arg        RCU_HXTAL: HXTAL
1044       \arg        RCU_LXTAL: LXTAL
1045       \arg        RCU_IRC16M: IRC16M
1046       \arg        RCU_IRC48M: IRC48M
1047       \arg        RCU_IRC32K: IRC32K
1048       \arg        RCU_PLL_CK: PLL
1049       \arg        RCU_PLLI2S_CK: PLLI2S
1050       \arg        RCU_PLLSAI_CK: PLLSAI
1051     \param[out] none
1052     \retval     none
1053 */
rcu_osci_off(rcu_osci_type_enum osci)1054 void rcu_osci_off(rcu_osci_type_enum osci)
1055 {
1056     RCU_REG_VAL(osci) &= ~BIT(RCU_BIT_POS(osci));
1057 }
1058 
1059 /*!
1060     \brief    enable the oscillator bypass mode, HXTALEN or LXTALEN must be reset before it
1061     \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
1062                 only one parameter can be selected which is shown as below:
1063       \arg        RCU_HXTAL: high speed crystal oscillator(HXTAL)
1064       \arg        RCU_LXTAL: low speed crystal oscillator(LXTAL)
1065     \param[out] none
1066     \retval     none
1067 */
rcu_osci_bypass_mode_enable(rcu_osci_type_enum osci)1068 void rcu_osci_bypass_mode_enable(rcu_osci_type_enum osci)
1069 {
1070     uint32_t reg;
1071 
1072     switch(osci) {
1073     /* enable HXTAL to bypass mode */
1074     case RCU_HXTAL:
1075         reg = RCU_CTL;
1076         RCU_CTL &= ~RCU_CTL_HXTALEN;
1077         RCU_CTL = (reg | RCU_CTL_HXTALBPS);
1078         break;
1079     /* enable LXTAL to bypass mode */
1080     case RCU_LXTAL:
1081         reg = RCU_BDCTL;
1082         RCU_BDCTL &= ~RCU_BDCTL_LXTALEN;
1083         RCU_BDCTL = (reg | RCU_BDCTL_LXTALBPS);
1084         break;
1085     case RCU_IRC16M:
1086     case RCU_IRC48M:
1087     case RCU_IRC32K:
1088     case RCU_PLL_CK:
1089     case RCU_PLLI2S_CK:
1090     case RCU_PLLSAI_CK:
1091         break;
1092     default:
1093         break;
1094     }
1095 }
1096 
1097 /*!
1098     \brief    disable the oscillator bypass mode, HXTALEN or LXTALEN must be reset before it
1099     \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
1100                 only one parameter can be selected which is shown as below:
1101       \arg        RCU_HXTAL: high speed crystal oscillator(HXTAL)
1102       \arg        RCU_LXTAL: low speed crystal oscillator(LXTAL)
1103     \param[out] none
1104     \retval     none
1105 */
rcu_osci_bypass_mode_disable(rcu_osci_type_enum osci)1106 void rcu_osci_bypass_mode_disable(rcu_osci_type_enum osci)
1107 {
1108     uint32_t reg;
1109 
1110     switch(osci) {
1111     /* disable HXTAL to bypass mode */
1112     case RCU_HXTAL:
1113         reg = RCU_CTL;
1114         RCU_CTL &= ~RCU_CTL_HXTALEN;
1115         RCU_CTL = (reg & ~RCU_CTL_HXTALBPS);
1116         break;
1117     /* disable LXTAL to bypass mode */
1118     case RCU_LXTAL:
1119         reg = RCU_BDCTL;
1120         RCU_BDCTL &= ~RCU_BDCTL_LXTALEN;
1121         RCU_BDCTL = (reg & ~RCU_BDCTL_LXTALBPS);
1122         break;
1123     case RCU_IRC16M:
1124     case RCU_IRC48M:
1125     case RCU_IRC32K:
1126     case RCU_PLL_CK:
1127     case RCU_PLLI2S_CK:
1128     case RCU_PLLSAI_CK:
1129         break;
1130     default:
1131         break;
1132     }
1133 }
1134 
1135 /*!
1136     \brief    enable the HXTAL clock monitor
1137     \param[in]  none
1138     \param[out] none
1139     \retval     none
1140 */
1141 
rcu_hxtal_clock_monitor_enable(void)1142 void rcu_hxtal_clock_monitor_enable(void)
1143 {
1144     RCU_CTL |= RCU_CTL_CKMEN;
1145 }
1146 
1147 /*!
1148     \brief    disable the HXTAL clock monitor
1149     \param[in]  none
1150     \param[out] none
1151     \retval     none
1152 */
rcu_hxtal_clock_monitor_disable(void)1153 void rcu_hxtal_clock_monitor_disable(void)
1154 {
1155     RCU_CTL &= ~RCU_CTL_CKMEN;
1156 }
1157 
1158 /*!
1159     \brief    set the IRC16M adjust value
1160     \param[in]  irc16m_adjval: IRC16M adjust value, must be between 0 and 0x1F
1161       \arg        0x00 - 0x1F
1162     \param[out] none
1163     \retval     none
1164 */
rcu_irc16m_adjust_value_set(uint32_t irc16m_adjval)1165 void rcu_irc16m_adjust_value_set(uint32_t irc16m_adjval)
1166 {
1167     uint32_t reg;
1168 
1169     reg = RCU_CTL;
1170     /* reset the IRC16MADJ bits and set according to irc16m_adjval */
1171     reg &= ~RCU_CTL_IRC16MADJ;
1172     RCU_CTL = (reg | ((irc16m_adjval & RCU_IRC16M_ADJUST_MASK) << RCU_IRC16M_ADJUST_OFFSET));
1173 }
1174 
1175 /*!
1176     \brief    unlock the voltage key
1177     \param[in]  none
1178     \param[out] none
1179     \retval     none
1180 */
rcu_voltage_key_unlock(void)1181 void rcu_voltage_key_unlock(void)
1182 {
1183     RCU_VKEY = RCU_VKEY_UNLOCK;
1184 }
1185 
1186 /*!
1187     \brief    deep-sleep mode voltage select
1188     \param[in]  dsvol: deep sleep mode voltage
1189                 only one parameter can be selected which is shown as below:
1190       \arg        RCU_DEEPSLEEP_V_0: the core voltage is default value
1191       \arg        RCU_DEEPSLEEP_V_1: the core voltage is (default value-0.1)V(customers are not recommended to use it)
1192       \arg        RCU_DEEPSLEEP_V_2: the core voltage is (default value-0.2)V(customers are not recommended to use it)
1193       \arg        RCU_DEEPSLEEP_V_3: the core voltage is (default value-0.3)V(customers are not recommended to use it)
1194     \param[out] none
1195     \retval     none
1196 */
rcu_deepsleep_voltage_set(uint32_t dsvol)1197 void rcu_deepsleep_voltage_set(uint32_t dsvol)
1198 {
1199     dsvol &= RCU_DSV_DSLPVS;
1200     RCU_DSV = dsvol;
1201 }
1202 
1203 /*!
1204     \brief    configure the spread spectrum modulation for the main PLL clock
1205     \param[in]  spread_spectrum_type: PLL spread spectrum modulation type select
1206       \arg        RCU_SS_TYPE_CENTER: center spread type is selected
1207       \arg        RCU_SS_TYPE_DOWN: down spread type is selected
1208     \param[in]  modstep: configure PLL spread spectrum modulation profile amplitude and frequency
1209       \arg        This parameter should be selected between 0 and 7FFF.The following criteria must be met: MODSTEP*MODCNT <=2^15-1
1210     \param[in]  modcnt: configure PLL spread spectrum modulation profile amplitude and frequency
1211       \arg        This parameter should be selected between 0 and 1FFF.The following criteria must be met: MODSTEP*MODCNT <=2^15-1
1212     \param[out] none
1213     \retval     none
1214 */
rcu_spread_spectrum_config(uint32_t spread_spectrum_type,uint32_t modstep,uint32_t modcnt)1215 void rcu_spread_spectrum_config(uint32_t spread_spectrum_type, uint32_t modstep, uint32_t modcnt)
1216 {
1217     uint32_t reg;
1218 
1219     reg = RCU_PLLSSCTL;
1220     /* reset the RCU_PLLSSCTL register bits */
1221     reg &= ~(RCU_PLLSSCTL_MODCNT | RCU_PLLSSCTL_MODSTEP | RCU_PLLSSCTL_SS_TYPE);
1222     RCU_PLLSSCTL = (reg | spread_spectrum_type | modstep << 13 | modcnt);
1223 }
1224 
1225 /*!
1226     \brief    enable the PLL spread spectrum modulation
1227     \param[in]  none
1228     \param[out] none
1229     \retval     none
1230 */
rcu_spread_spectrum_enable(void)1231 void rcu_spread_spectrum_enable(void)
1232 {
1233     RCU_PLLSSCTL |= RCU_PLLSSCTL_SSCGON;
1234 }
1235 
1236 /*!
1237     \brief    disable the PLL spread spectrum modulation
1238     \param[in]  none
1239     \param[out] none
1240     \retval     none
1241 */
rcu_spread_spectrum_disable(void)1242 void rcu_spread_spectrum_disable(void)
1243 {
1244     RCU_PLLSSCTL &= ~RCU_PLLSSCTL_SSCGON;
1245 }
1246 
1247 /*!
1248     \brief    get the system clock, bus and peripheral clock frequency
1249     \param[in]  clock: the clock frequency which to get
1250                 only one parameter can be selected which is shown as below:
1251       \arg        CK_SYS: system clock frequency
1252       \arg        CK_AHB: AHB clock frequency
1253       \arg        CK_APB1: APB1 clock frequency
1254       \arg        CK_APB2: APB2 clock frequency
1255     \param[out] none
1256     \retval     clock frequency of system, AHB, APB1, APB2
1257 */
rcu_clock_freq_get(rcu_clock_freq_enum clock)1258 uint32_t rcu_clock_freq_get(rcu_clock_freq_enum clock)
1259 {
1260     uint32_t sws, ck_freq = 0U;
1261     uint32_t cksys_freq, ahb_freq, apb1_freq, apb2_freq;
1262     uint32_t pllpsc, plln, pllsel, pllp, ck_src, idx, clk_exp;
1263 
1264     /* exponent of AHB, APB1 and APB2 clock divider */
1265     const uint8_t ahb_exp[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
1266     const uint8_t apb1_exp[8] = {0, 0, 0, 0, 1, 2, 3, 4};
1267     const uint8_t apb2_exp[8] = {0, 0, 0, 0, 1, 2, 3, 4};
1268 
1269     sws = GET_BITS(RCU_CFG0, 2, 3);
1270     switch(sws) {
1271     /* IRC16M is selected as CK_SYS */
1272     case SEL_IRC16M:
1273         cksys_freq = IRC16M_VALUE;
1274         break;
1275     /* HXTAL is selected as CK_SYS */
1276     case SEL_HXTAL:
1277         cksys_freq = HXTAL_VALUE;
1278         break;
1279     /* PLLP is selected as CK_SYS */
1280     case SEL_PLLP:
1281         /* get the value of PLLPSC[5:0] */
1282         pllpsc = GET_BITS(RCU_PLL, 0U, 5U);
1283         plln = GET_BITS(RCU_PLL, 6U, 14U);
1284         pllp = (GET_BITS(RCU_PLL, 16U, 17U) + 1U) * 2U;
1285         /* PLL clock source selection, HXTAL or IRC16M/2 */
1286         pllsel = (RCU_PLL & RCU_PLL_PLLSEL);
1287         if(RCU_PLLSRC_HXTAL == pllsel) {
1288             ck_src = HXTAL_VALUE;
1289         } else {
1290             ck_src = IRC16M_VALUE;
1291         }
1292         cksys_freq = ((ck_src / pllpsc) * plln) / pllp;
1293         break;
1294     /* IRC16M is selected as CK_SYS */
1295     default:
1296         cksys_freq = IRC16M_VALUE;
1297         break;
1298     }
1299     /* calculate AHB clock frequency */
1300     idx = GET_BITS(RCU_CFG0, 4, 7);
1301     clk_exp = ahb_exp[idx];
1302     ahb_freq = cksys_freq >> clk_exp;
1303 
1304     /* calculate APB1 clock frequency */
1305     idx = GET_BITS(RCU_CFG0, 10, 12);
1306     clk_exp = apb1_exp[idx];
1307     apb1_freq = ahb_freq >> clk_exp;
1308 
1309     /* calculate APB2 clock frequency */
1310     idx = GET_BITS(RCU_CFG0, 13, 15);
1311     clk_exp = apb2_exp[idx];
1312     apb2_freq = ahb_freq >> clk_exp;
1313 
1314     /* return the clocks frequency */
1315     switch(clock) {
1316     case CK_SYS:
1317         ck_freq = cksys_freq;
1318         break;
1319     case CK_AHB:
1320         ck_freq = ahb_freq;
1321         break;
1322     case CK_APB1:
1323         ck_freq = apb1_freq;
1324         break;
1325     case CK_APB2:
1326         ck_freq = apb2_freq;
1327         break;
1328     default:
1329         break;
1330     }
1331     return ck_freq;
1332 }
1333