1 /*!
2     \file  system_gd32a50x.c
3     \brief CMSIS Cortex-M33 Device Peripheral Access Layer Source File for
4            GD32A50X Device Series
5 */
6 
7 /* Copyright (c) 2012 ARM LIMITED
8 
9    All rights reserved.
10    Redistribution and use in source and binary forms, with or without
11    modification, are permitted provided that the following conditions are met:
12    - Redistributions of source code must retain the above copyright
13      notice, this list of conditions and the following disclaimer.
14    - Redistributions in binary form must reproduce the above copyright
15      notice, this list of conditions and the following disclaimer in the
16      documentation and/or other materials provided with the distribution.
17    - Neither the name of ARM nor the names of its contributors may be used
18      to endorse or promote products derived from this software without
19      specific prior written permission.
20    *
21    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24    ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
25    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31    POSSIBILITY OF SUCH DAMAGE.
32    ---------------------------------------------------------------------------*/
33 
34 /* This file refers the CMSIS standard, some adjustments are made according to GigaDevice chips */
35 
36 #include "gd32a50x.h"
37 
38 #define __IRC8M           (IRC8M_VALUE)            /* internal 8 MHz RC oscillator frequency */
39 #define __HXTAL           (HXTAL_VALUE)            /* high speed crystal oscillator frequency */
40 
41 #define VECT_TAB_OFFSET  (uint32_t)0x00            /* vector table base offset */
42 
43 /* select a system clock by uncommenting the following line */
44 /* use IRC8M */
45 //#define __SYSTEM_CLOCK_IRC8M                            (uint32_t)(__IRC8M)
46 //#define __SYSTEM_CLOCK_24M_PLL_IRC8M                    (uint32_t)(24000000)
47 //#define __SYSTEM_CLOCK_48M_PLL_IRC8M                    (uint32_t)(48000000)
48 //#define __SYSTEM_CLOCK_72M_PLL_IRC8M                    (uint32_t)(72000000)
49 //#define __SYSTEM_CLOCK_100M_PLL_IRC8M                   (uint32_t)(100000000)
50 
51 /* use HXTAL(CK_HXTAL = 8M)*/
52 //#define __SYSTEM_CLOCK_HXTAL                            (uint32_t)(__HXTAL)
53 //#define __SYSTEM_CLOCK_24M_PLL_HXTAL                    (uint32_t)(24000000)
54 //#define __SYSTEM_CLOCK_48M_PLL_HXTAL                    (uint32_t)(48000000)
55 //#define __SYSTEM_CLOCK_72M_PLL_HXTAL                    (uint32_t)(72000000)
56 #define __SYSTEM_CLOCK_100M_PLL_HXTAL                   (uint32_t)(100000000)
57 
58 
59 /* set the system clock frequency and declare the system clock configuration function */
60 #ifdef __SYSTEM_CLOCK_IRC8M
61 uint32_t SystemCoreClock = __SYSTEM_CLOCK_IRC8M;
62 static void system_clock_8m_irc8m(void);
63 #elif defined (__SYSTEM_CLOCK_24M_PLL_IRC8M)
64 uint32_t SystemCoreClock = __SYSTEM_CLOCK_24M_PLL_IRC8M;
65 static void system_clock_24m_pll_irc8m(void);
66 #elif defined (__SYSTEM_CLOCK_48M_PLL_IRC8M)
67 uint32_t SystemCoreClock = __SYSTEM_CLOCK_48M_PLL_IRC8M;
68 static void system_clock_48m_pll_irc8m(void);
69 #elif defined (__SYSTEM_CLOCK_72M_PLL_IRC8M)
70 uint32_t SystemCoreClock = __SYSTEM_CLOCK_72M_PLL_IRC8M;
71 static void system_clock_72m_pll_irc8m(void);
72 #elif defined (__SYSTEM_CLOCK_100M_PLL_IRC8M)
73 uint32_t SystemCoreClock = __SYSTEM_CLOCK_100M_PLL_IRC8M;
74 static void system_clock_100m_pll_irc8m(void);
75 
76 #elif defined (__SYSTEM_CLOCK_HXTAL)
77 uint32_t SystemCoreClock = __SYSTEM_CLOCK_HXTAL;
78 static void system_clock_hxtal(void);
79 #elif defined (__SYSTEM_CLOCK_24M_PLL_HXTAL)
80 uint32_t SystemCoreClock = __SYSTEM_CLOCK_24M_PLL_HXTAL;
81 static void system_clock_24m_pll_hxtal(void);
82 #elif defined (__SYSTEM_CLOCK_48M_PLL_HXTAL)
83 uint32_t SystemCoreClock = __SYSTEM_CLOCK_48M_PLL_HXTAL;
84 static void system_clock_48m_pll_hxtal(void);
85 #elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)
86 uint32_t SystemCoreClock = __SYSTEM_CLOCK_72M_PLL_HXTAL;
87 static void system_clock_72m_pll_hxtal(void);
88 #elif defined (__SYSTEM_CLOCK_100M_PLL_HXTAL)
89 uint32_t SystemCoreClock = __SYSTEM_CLOCK_100M_PLL_HXTAL;
90 static void system_clock_100m_pll_hxtal(void);
91 #endif /* __SYSTEM_CLOCK_IRC8M */
92 
93 /* configure the system clock */
94 static void system_clock_config(void);
95 
96 /*!
97     \brief      setup the micro-controller system, initialize the system
98     \param[in]  none
99     \param[out] none
100     \retval     none
101 */
SystemInit(void)102 void SystemInit(void)
103 {
104     /* FPU settings */
105 #if (__FPU_PRESENT == 1U) && (__FPU_USED == 1U)
106     SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); /* set CP10 and CP11 Full Access */
107 #endif
108     /* reset the RCU clock configuration to the default reset state */
109     /* set IRC8MEN bit */
110     RCU_CTL |= RCU_CTL_IRC8MEN;
111 
112     RCU_CFG0 &= ~RCU_CFG0_SCS;
113     /* reset HXTALSCAL, LCKMEN, PLLMEN, PLLEN, CKMEN and HXTALEN bits */
114     RCU_CTL &= ~(RCU_CTL_PLLEN | RCU_CTL_CKMEN | RCU_CTL_HXTALEN | RCU_CTL_HXTALSCAL | RCU_CTL_LCKMEN | RCU_CTL_PLLMEN);
115     /* disable all interrupts */
116     RCU_INT = 0x00FF0000U;
117 
118     /* Reset CFG0 and CFG1 registers */
119     RCU_CFG0 = 0x00020000U;
120     RCU_CFG1 = 0x00000000U;
121 
122     /* reset HXTALBPS bit */
123     RCU_CTL &= ~(RCU_CTL_HXTALBPS);
124 
125     /* configure the system clock source, PLL Multiplier, AHB/APBx prescalers and Flash settings */
126     system_clock_config();
127 
128     /* LXTALBPS configuration */
129     if(0U == (RCU_APB1EN & RCU_APB1EN_PMUEN)) {
130         /* check whether PMU clock is enabled */
131         RCU_APB1EN |= RCU_APB1EN_PMUEN;
132         if(0U == (PMU_CTL & PMU_CTL_BKPWEN)) {
133             /* BKPWEN bit is not been set */
134             PMU_CTL |= PMU_CTL_BKPWEN;
135             /* LXTALBPS bit must be configured to 1 */
136             RCU_BDCTL |= RCU_BDCTL_LXTALBPS;
137             /* clear the BKPWEN bit */
138             PMU_CTL &= ~PMU_CTL_BKPWEN;
139         } else {
140             /* LXTALBPS bit must be configured to 1 */
141             RCU_BDCTL |= RCU_BDCTL_LXTALBPS;
142         }
143 
144         /* disable the PMU clock */
145         RCU_APB1EN &= ~RCU_APB1EN_PMUEN;
146     } else {
147         /* the PMU clock is already enabled */
148         if(0U == (PMU_CTL & PMU_CTL_BKPWEN)) {
149             /* BKPWEN bit is not been set */
150             PMU_CTL |= PMU_CTL_BKPWEN;
151             /* LXTALBPS bit must be configured to 1 */
152             RCU_BDCTL |= RCU_BDCTL_LXTALBPS;
153             /* clear the BKPWEN bit */
154             PMU_CTL &= ~PMU_CTL_BKPWEN;
155         } else {
156             /* LXTALBPS bit must be configured to 1 */
157             RCU_BDCTL |= RCU_BDCTL_LXTALBPS;
158         }
159     }
160 }
161 
162 /*!
163     \brief      configure the system clock
164     \param[in]  none
165     \param[out] none
166     \retval     none
167 */
system_clock_config(void)168 static void system_clock_config(void)
169 {
170 #ifdef __SYSTEM_CLOCK_IRC8M
171     system_clock_8m_irc8m();
172 #elif defined (__SYSTEM_CLOCK_24M_PLL_IRC8M)
173     system_clock_24m_pll_irc8m();
174 #elif defined (__SYSTEM_CLOCK_48M_PLL_IRC8M)
175     system_clock_48m_pll_irc8m();
176 #elif defined (__SYSTEM_CLOCK_72M_PLL_IRC8M)
177     system_clock_72m_pll_irc8m();
178 #elif defined (__SYSTEM_CLOCK_100M_PLL_IRC8M)
179     system_clock_100m_pll_irc8m();
180 
181 #elif defined (__SYSTEM_CLOCK_HXTAL)
182     system_clock_hxtal();
183 #elif defined (__SYSTEM_CLOCK_24M_PLL_HXTAL)
184     system_clock_24m_pll_hxtal();
185 #elif defined (__SYSTEM_CLOCK_48M_PLL_HXTAL)
186     system_clock_48m_pll_hxtal();
187 #elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)
188     system_clock_72m_pll_hxtal();
189 #elif defined (__SYSTEM_CLOCK_100M_PLL_HXTAL)
190     system_clock_100m_pll_hxtal();
191 #endif /* __SYSTEM_CLOCK_IRC8M */
192 }
193 
194 #ifdef __SYSTEM_CLOCK_IRC8M
195 /*!
196     \brief      configure the system clock to 8M by IRC8M
197     \param[in]  none
198     \param[out] none
199     \retval     none
200 */
system_clock_8m_irc8m(void)201 static void system_clock_8m_irc8m(void)
202 {
203     uint32_t timeout = 0U;
204     uint32_t stab_flag = 0U;
205 
206     /* enable IRC8M */
207     RCU_CTL |= RCU_CTL_IRC8MEN;
208 
209     /* wait until IRC8M is stable or the startup time is longer than IRC8M_STARTUP_TIMEOUT */
210     do {
211         timeout++;
212         stab_flag = (RCU_CTL & RCU_CTL_IRC8MSTB);
213     } while((0U == stab_flag) && (IRC8M_STARTUP_TIMEOUT != timeout));
214 
215     /* if fail */
216     if(0U == (RCU_CTL & RCU_CTL_IRC8MSTB)) {
217         while(1) {
218         }
219     }
220 
221     FMC_WS = (FMC_WS & (~FMC_WS_WSCNT)) | WS_WSCNT(0);
222 
223     RCU_APB1EN |= RCU_APB1EN_PMUEN;
224 
225     /* AHB = SYSCLK */
226     RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
227     /* APB2 = AHB/1 */
228     RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
229     /* APB1 = AHB/1 */
230     RCU_CFG0 |= RCU_APB1_CKAHB_DIV1;
231 
232     /* select IRC8M as system clock */
233     RCU_CFG0 &= ~RCU_CFG0_SCS;
234     RCU_CFG0 |= RCU_CKSYSSRC_IRC8M;
235 
236     /* wait until IRC8M is selected as system clock */
237     while((RCU_CFG0 & RCU_CFG0_SCSS) != RCU_SCSS_IRC8M) {
238     }
239 }
240 /*!
241     \brief      configure the system clock to 24M by PLL which selects IRC8M as its clock source
242     \param[in]  none
243     \param[out] none
244     \retval     none
245 */
246 #elif defined (__SYSTEM_CLOCK_24M_PLL_IRC8M)
system_clock_24m_pll_irc8m(void)247 static void system_clock_24m_pll_irc8m(void)
248 {
249     uint32_t timeout = 0U;
250     uint32_t stab_flag = 0U;
251 
252     /* enable IRC8M */
253     RCU_CTL |= RCU_CTL_IRC8MEN;
254 
255     /* wait until IRC8M is stable or the startup time is longer than IRC8M_STARTUP_TIMEOUT */
256     do {
257         timeout++;
258         stab_flag = (RCU_CTL & RCU_CTL_IRC8MSTB);
259     } while((0U == stab_flag) && (IRC8M_STARTUP_TIMEOUT != timeout));
260 
261     /* if fail */
262     if(0U == (RCU_CTL & RCU_CTL_IRC8MSTB)) {
263         while(1) {
264         }
265     }
266 
267     FMC_WS = (FMC_WS & (~FMC_WS_WSCNT)) | WS_WSCNT(0);
268 
269     /* LDO output voltage high mode */
270     RCU_APB1EN |= RCU_APB1EN_PMUEN;
271 
272     /* IRC8M is stable */
273     /* AHB = SYSCLK */
274     RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
275     /* APB2 = AHB/1 */
276     RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
277     /* APB1 = AHB/2 */
278     RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
279 
280     /* CK_PLL = (CK_IRC8M/2) * 6 = 24 MHz */
281     RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
282     RCU_CFG0 |= RCU_PLL_MUL6;
283 
284     /* enable PLL */
285     RCU_CTL |= RCU_CTL_PLLEN;
286 
287     /* wait until PLL is stable */
288     while(0U == (RCU_CTL & RCU_CTL_PLLSTB)) {
289     }
290 
291     /* select PLL as system clock */
292     RCU_CFG0 &= ~RCU_CFG0_SCS;
293     RCU_CFG0 |= RCU_CKSYSSRC_PLL;
294 
295     /* wait until PLL is selected as system clock */
296     while((RCU_CFG0 & RCU_CFG0_SCSS) != RCU_SCSS_PLL) {
297     }
298 }
299 
300 
301 #elif defined (__SYSTEM_CLOCK_48M_PLL_IRC8M)
302 /*!
303     \brief      configure the system clock to 48M by PLL which selects IRC8M as its clock source
304     \param[in]  none
305     \param[out] none
306     \retval     none
307 */
system_clock_48m_pll_irc8m(void)308 static void system_clock_48m_pll_irc8m(void)
309 {
310     uint32_t timeout = 0U;
311     uint32_t stab_flag = 0U;
312 
313     /* enable IRC8M */
314     RCU_CTL |= RCU_CTL_IRC8MEN;
315 
316     /* wait until IRC8M is stable or the startup time is longer than IRC8M_STARTUP_TIMEOUT */
317     do {
318         timeout++;
319         stab_flag = (RCU_CTL & RCU_CTL_IRC8MSTB);
320     } while((0U == stab_flag) && (IRC8M_STARTUP_TIMEOUT != timeout));
321 
322     /* if fail */
323     if(0U == (RCU_CTL & RCU_CTL_IRC8MSTB)) {
324         while(1) {
325         }
326     }
327 
328     FMC_WS = (FMC_WS & (~FMC_WS_WSCNT)) | WS_WSCNT(1);
329 
330     /* LDO output voltage high mode */
331     RCU_APB1EN |= RCU_APB1EN_PMUEN;
332 
333     /* IRC8M is stable */
334     /* AHB = SYSCLK */
335     RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
336     /* APB2 = AHB/1 */
337     RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
338     /* APB1 = AHB/2 */
339     RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
340 
341     /* CK_PLL = (CK_IRC8M/2) * 12 = 48 MHz */
342     RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
343     RCU_CFG0 |= RCU_PLL_MUL12;
344 
345     /* enable PLL */
346     RCU_CTL |= RCU_CTL_PLLEN;
347 
348     /* wait until PLL is stable */
349     while(0U == (RCU_CTL & RCU_CTL_PLLSTB)) {
350     }
351 
352     /* select PLL as system clock */
353     RCU_CFG0 &= ~RCU_CFG0_SCS;
354     RCU_CFG0 |= RCU_CKSYSSRC_PLL;
355 
356     /* wait until PLL is selected as system clock */
357     while((RCU_CFG0 & RCU_CFG0_SCSS) != RCU_SCSS_PLL) {
358     }
359 }
360 
361 #elif defined (__SYSTEM_CLOCK_72M_PLL_IRC8M)
362 /*!
363     \brief      configure the system clock to 72M by PLL which selects IRC8M as its clock source
364     \param[in]  none
365     \param[out] none
366     \retval     none
367 */
system_clock_72m_pll_irc8m(void)368 static void system_clock_72m_pll_irc8m(void)
369 {
370     uint32_t timeout = 0U;
371     uint32_t stab_flag = 0U;
372 
373     /* enable IRC8M */
374     RCU_CTL |= RCU_CTL_IRC8MEN;
375 
376     /* wait until IRC8M is stable or the startup time is longer than IRC8M_STARTUP_TIMEOUT */
377     do {
378         timeout++;
379         stab_flag = (RCU_CTL & RCU_CTL_IRC8MSTB);
380     } while((0U == stab_flag) && (IRC8M_STARTUP_TIMEOUT != timeout));
381 
382     /* if fail */
383     if(0U == (RCU_CTL & RCU_CTL_IRC8MSTB)) {
384         while(1) {
385         }
386     }
387 
388     FMC_WS = (FMC_WS & (~FMC_WS_WSCNT)) | WS_WSCNT(2);
389 
390     /* LDO output voltage high mode */
391     RCU_APB1EN |= RCU_APB1EN_PMUEN;
392 
393     /* IRC8M is stable */
394     /* AHB = SYSCLK */
395     RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
396     /* APB2 = AHB/1 */
397     RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
398     /* APB1 = AHB/2 */
399     RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
400 
401     /* CK_PLL = (CK_IRC8M/2) * 18 = 72 MHz */
402     RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
403     RCU_CFG0 |= RCU_PLL_MUL18;
404 
405     /* enable PLL */
406     RCU_CTL |= RCU_CTL_PLLEN;
407 
408     /* wait until PLL is stable */
409     while(0U == (RCU_CTL & RCU_CTL_PLLSTB)) {
410     }
411 
412     /* select PLL as system clock */
413     RCU_CFG0 &= ~RCU_CFG0_SCS;
414     RCU_CFG0 |= RCU_CKSYSSRC_PLL;
415 
416     /* wait until PLL is selected as system clock */
417     while((RCU_CFG0 & RCU_CFG0_SCSS) != RCU_SCSS_PLL) {
418     }
419 }
420 
421 #elif defined (__SYSTEM_CLOCK_100M_PLL_IRC8M)
422 /*!
423     \brief      configure the system clock to 100M by PLL which selects IRC8M as its clock source
424     \param[in]  none
425     \param[out] none
426     \retval     none
427 */
system_clock_100m_pll_irc8m(void)428 static void system_clock_100m_pll_irc8m(void)
429 {
430     uint32_t timeout = 0U;
431     uint32_t stab_flag = 0U;
432 
433     /* enable IRC8M */
434     RCU_CTL |= RCU_CTL_IRC8MEN;
435 
436     /* wait until IRC8M is stable or the startup time is longer than IRC8M_STARTUP_TIMEOUT */
437     do {
438         timeout++;
439         stab_flag = (RCU_CTL & RCU_CTL_IRC8MSTB);
440     } while((0U == stab_flag) && (IRC8M_STARTUP_TIMEOUT != timeout));
441 
442     /* if fail */
443     if(0U == (RCU_CTL & RCU_CTL_IRC8MSTB)) {
444         while(1) {
445         }
446     }
447 
448     FMC_WS = (FMC_WS & (~FMC_WS_WSCNT)) | WS_WSCNT(3);
449 
450     /* LDO output voltage high mode */
451     RCU_APB1EN |= RCU_APB1EN_PMUEN;
452 
453     /* IRC8M is stable */
454     /* AHB = SYSCLK */
455     RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
456     /* APB2 = AHB/1 */
457     RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
458     /* APB1 = AHB/2 */
459     RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
460 
461     /* CK_PLL = (CK_IRC8M/2) * 25 = 100 MHz */
462     RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
463     RCU_CFG0 |= RCU_PLL_MUL25;
464 
465     /* enable PLL */
466     RCU_CTL |= RCU_CTL_PLLEN;
467 
468     /* wait until PLL is stable */
469     while(0U == (RCU_CTL & RCU_CTL_PLLSTB)) {
470     }
471 
472     /* select PLL as system clock */
473     RCU_CFG0 &= ~RCU_CFG0_SCS;
474     RCU_CFG0 |= RCU_CKSYSSRC_PLL;
475 
476     /* wait until PLL is selected as system clock */
477     while((RCU_CFG0 & RCU_CFG0_SCSS) != RCU_SCSS_PLL) {
478     }
479 }
480 
481 #elif defined (__SYSTEM_CLOCK_HXTAL)
482 /*!
483     \brief      configure the system clock to HXTAL
484     \param[in]  none
485     \param[out] none
486     \retval     none
487 */
system_clock_hxtal(void)488 static void system_clock_hxtal(void)
489 {
490     uint32_t timeout = 0U;
491     uint32_t stab_flag = 0U;
492 
493     /* enable HXTAL */
494     RCU_CTL |= RCU_CTL_HXTALEN;
495 
496     /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
497     do {
498         timeout++;
499         stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB);
500     } while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
501 
502     /* if fail */
503     if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)) {
504         while(1) {
505         }
506     }
507 
508     FMC_WS = (FMC_WS & (~FMC_WS_WSCNT)) | WS_WSCNT(0);
509 
510     RCU_APB1EN |= RCU_APB1EN_PMUEN;
511 
512     /* AHB = SYSCLK */
513     RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
514     /* APB2 = AHB/1 */
515     RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
516     /* APB1 = AHB/1 */
517     RCU_CFG0 |= RCU_APB1_CKAHB_DIV1;
518 
519     /* select HXTAL as system clock */
520     RCU_CFG0 &= ~RCU_CFG0_SCS;
521     RCU_CFG0 |= RCU_CKSYSSRC_HXTAL;
522 
523     /* wait until HXTAL is selected as system clock */
524     while((RCU_CFG0 & RCU_CFG0_SCSS) != RCU_SCSS_HXTAL) {
525     }
526 }
527 
528 #elif defined (__SYSTEM_CLOCK_24M_PLL_HXTAL)
529 /*!
530     \brief      configure the system clock to 24M by PLL which selects HXTAL as its clock source
531     \param[in]  none
532     \param[out] none
533     \retval     none
534 */
system_clock_24m_pll_hxtal(void)535 static void system_clock_24m_pll_hxtal(void)
536 {
537     uint32_t timeout = 0U;
538     uint32_t stab_flag = 0U;
539 
540     /* enable HXTAL */
541     RCU_CTL |= RCU_CTL_HXTALEN;
542 
543     /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
544     do {
545         timeout++;
546         stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB);
547     } while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
548 
549     /* if fail */
550     if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)) {
551         while(1) {
552         }
553     }
554 
555     FMC_WS = (FMC_WS & (~FMC_WS_WSCNT)) | WS_WSCNT(0);
556 
557     RCU_APB1EN |= RCU_APB1EN_PMUEN;
558 
559     /* HXTAL is stable */
560     /* AHB = SYSCLK */
561     RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
562     /* APB2 = AHB/1 */
563     RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
564     /* APB1 = AHB/2 */
565     RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
566 
567     /* CK_PLL = (HXTAL / 2) * 6 = 24 MHz */
568     RCU_CFG1 |=  RCU_PREDV_DIV2;
569     RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
570     RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL6);
571 
572     /* enable PLL */
573     RCU_CTL |= RCU_CTL_PLLEN;
574 
575     /* wait until PLL is stable */
576     while(0U == (RCU_CTL & RCU_CTL_PLLSTB)) {
577     }
578 
579     /* select PLL as system clock */
580     RCU_CFG0 &= ~RCU_CFG0_SCS;
581     RCU_CFG0 |= RCU_CKSYSSRC_PLL;
582 
583     /* wait until PLL is selected as system clock */
584     while((RCU_CFG0 & RCU_CFG0_SCSS) != RCU_SCSS_PLL) {
585     }
586 }
587 
588 #elif defined (__SYSTEM_CLOCK_48M_PLL_HXTAL)
589 /*!
590     \brief      configure the system clock to 48M by PLL which selects HXTAL as its clock source
591     \param[in]  none
592     \param[out] none
593     \retval     none
594 */
system_clock_48m_pll_hxtal(void)595 static void system_clock_48m_pll_hxtal(void)
596 {
597     uint32_t timeout = 0U;
598     uint32_t stab_flag = 0U;
599 
600     /* enable HXTAL */
601     RCU_CTL |= RCU_CTL_HXTALEN;
602 
603     /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
604     do {
605         timeout++;
606         stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB);
607     } while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
608 
609     /* if fail */
610     if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)) {
611         while(1) {
612         }
613     }
614 
615     FMC_WS = (FMC_WS & (~FMC_WS_WSCNT)) | WS_WSCNT(1);
616 
617     RCU_APB1EN |= RCU_APB1EN_PMUEN;
618 
619     /* HXTAL is stable */
620     /* AHB = SYSCLK */
621     RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
622     /* APB2 = AHB/1 */
623     RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
624     /* APB1 = AHB/2 */
625     RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
626 
627     /* CK_PLL = (HXTAL / 2) * 12 = 48 MHz */
628     RCU_CFG1 |=  RCU_PREDV_DIV2;
629     RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
630     RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL12);
631 
632     /* enable PLL */
633     RCU_CTL |= RCU_CTL_PLLEN;
634 
635     /* wait until PLL is stable */
636     while(0U == (RCU_CTL & RCU_CTL_PLLSTB)) {
637     }
638 
639     /* select PLL as system clock */
640     RCU_CFG0 &= ~RCU_CFG0_SCS;
641     RCU_CFG0 |= RCU_CKSYSSRC_PLL;
642 
643     /* wait until PLL is selected as system clock */
644     while((RCU_CFG0 & RCU_CFG0_SCSS) != RCU_SCSS_PLL) {
645     }
646 }
647 
648 #elif defined (__SYSTEM_CLOCK_72M_PLL_HXTAL)
649 /*!
650     \brief      configure the system clock to 72M by PLL which selects HXTAL as its clock source
651     \param[in]  none
652     \param[out] none
653     \retval     none
654 */
system_clock_72m_pll_hxtal(void)655 static void system_clock_72m_pll_hxtal(void)
656 {
657     uint32_t timeout = 0U;
658     uint32_t stab_flag = 0U;
659 
660     /* enable HXTAL */
661     RCU_CTL |= RCU_CTL_HXTALEN;
662 
663     /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
664     do {
665         timeout++;
666         stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB);
667     } while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
668 
669     /* if fail */
670     if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)) {
671         while(1) {
672         }
673     }
674 
675     FMC_WS = (FMC_WS & (~FMC_WS_WSCNT)) | WS_WSCNT(2);
676 
677     RCU_APB1EN |= RCU_APB1EN_PMUEN;
678 
679     /* HXTAL is stable */
680     /* AHB = SYSCLK */
681     RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
682     /* APB2 = AHB/1 */
683     RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
684     /* APB1 = AHB/2 */
685     RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
686 
687     /* CK_PLL = (HXTAL / 2) * 18 = 72 MHz */
688     RCU_CFG1 |=  RCU_PREDV_DIV2;
689     RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
690     RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL18);
691 
692     /* enable PLL */
693     RCU_CTL |= RCU_CTL_PLLEN;
694 
695     /* wait until PLL is stable */
696     while(0U == (RCU_CTL & RCU_CTL_PLLSTB)) {
697     }
698 
699     /* select PLL as system clock */
700     RCU_CFG0 &= ~RCU_CFG0_SCS;
701     RCU_CFG0 |= RCU_CKSYSSRC_PLL;
702 
703     /* wait until PLL is selected as system clock */
704     while((RCU_CFG0 & RCU_CFG0_SCSS) != RCU_SCSS_PLL) {
705     }
706 }
707 
708 #elif defined (__SYSTEM_CLOCK_100M_PLL_HXTAL)
709 /*!
710     \brief      configure the system clock to 100M by PLL which selects HXTAL as its clock source
711     \param[in]  none
712     \param[out] none
713     \retval     none
714 */
system_clock_100m_pll_hxtal(void)715 static void system_clock_100m_pll_hxtal(void)
716 {
717     uint32_t timeout = 0U;
718     uint32_t stab_flag = 0U;
719 
720     /* enable HXTAL */
721     RCU_CTL |= RCU_CTL_HXTALEN;
722 
723     /* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */
724     do {
725         timeout++;
726         stab_flag = (RCU_CTL & RCU_CTL_HXTALSTB);
727     } while((0U == stab_flag) && (HXTAL_STARTUP_TIMEOUT != timeout));
728 
729     /* if fail */
730     if(0U == (RCU_CTL & RCU_CTL_HXTALSTB)) {
731         while(1) {
732         }
733     }
734 
735     FMC_WS = (FMC_WS & (~FMC_WS_WSCNT)) | WS_WSCNT(3);
736 
737     RCU_APB1EN |= RCU_APB1EN_PMUEN;
738 
739     /* HXTAL is stable */
740     /* AHB = SYSCLK */
741     RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
742     /* APB2 = AHB/1 */
743     RCU_CFG0 |= RCU_APB2_CKAHB_DIV1;
744     /* APB1 = AHB/2 */
745     RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;
746 
747     /* CK_PLL = (HXTAL / 2) * 25 = 100 MHz */
748     RCU_CFG1 |=  RCU_PREDV_DIV2;
749     RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
750     RCU_CFG0 |= (RCU_PLLSRC_HXTAL | RCU_PLL_MUL25);
751 
752     /* enable PLL */
753     RCU_CTL |= RCU_CTL_PLLEN;
754 
755     /* wait until PLL is stable */
756     while(0U == (RCU_CTL & RCU_CTL_PLLSTB)) {
757     }
758 
759     /* select PLL as system clock */
760     RCU_CFG0 &= ~RCU_CFG0_SCS;
761     RCU_CFG0 |= RCU_CKSYSSRC_PLL;
762 
763     /* wait until PLL is selected as system clock */
764     while((RCU_CFG0 & RCU_CFG0_SCSS) != RCU_SCSS_PLL) {
765     }
766 }
767 #endif /* __SYSTEM_CLOCK_IRC8M */
768 
769 /*!
770     \brief      update the SystemCoreClock with current core clock retrieved from CPU registers
771     \param[in]  none
772     \param[out] none
773     \retval     none
774 */
SystemCoreClockUpdate(void)775 void SystemCoreClockUpdate(void)
776 {
777     uint32_t sws;
778     uint32_t pllsel, pllmf, ck_src, idx, clk_exp;
779     uint32_t predv0;
780 
781     /* exponent of AHB, APB1 and APB2 clock divider */
782     uint8_t ahb_exp[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
783 
784     sws = RCU_CFG0 & RCU_CFG0_SCSS;
785     switch(sws) {
786     /* IRC8M is selected as CK_SYS */
787     case RCU_SCSS_IRC8M:
788         SystemCoreClock = IRC8M_VALUE;
789         break;
790     /* HXTAL is selected as CK_SYS */
791     case RCU_SCSS_HXTAL:
792         SystemCoreClock = HXTAL_VALUE;
793         break;
794     /* PLL is selected as CK_SYS */
795     case RCU_SCSS_PLL:
796         /* PLL clock source selection, HXTAL or IRC8M/2 */
797         pllsel = (RCU_CFG0 & RCU_CFG0_PLLSEL);
798 
799         if(RCU_PLLSRC_HXTAL == pllsel) {
800             /* PLL clock source is HXTAL */
801             ck_src = HXTAL_VALUE;
802             predv0 = (RCU_CFG1 & RCU_CFG1_PREDV) + 1U;
803             ck_src /= predv0;
804         } else {
805             /* PLL clock source is IRC8M/2 */
806             ck_src = IRC8M_VALUE / 2U;
807         }
808 
809         /* PLL multiplication factor */
810         pllmf = GET_BITS(RCU_CFG0, 18, 21);
811         pllmf += ((RCU_CFG0 & RCU_CFG0_PLLMF_4) ? 15U : 0U);
812         pllmf += ((RCU_CFG0_PLLMF == (RCU_CFG0 & RCU_CFG0_PLLMF)) ? 1U : 2U);
813 
814         SystemCoreClock = ck_src * pllmf;
815 
816         break;
817     /* IRC8M is selected as CK_SYS */
818     default:
819         SystemCoreClock = IRC8M_VALUE;
820         break;
821     }
822 
823     /* calculate AHB clock frequency */
824     idx = GET_BITS(RCU_CFG0, 4, 7);
825     clk_exp = ahb_exp[idx];
826     SystemCoreClock >>= clk_exp;
827 }
828