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