1 /********************************** (C) COPYRIGHT *******************************
2  * File Name          : system_ch32v10x.c
3  * Author             : WCH
4  * Version            : V1.0.0
5  * Date               : 2020/04/30
6  * Description        : CH32V10x Device Peripheral Access Layer System Source File.
7  * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
8  * SPDX-License-Identifier: Apache-2.0
9  *********************************************************************************/
10 #include "ch32v10x.h"
11 
12 /*
13  * Uncomment the line corresponding to the desired System clock (SYSCLK) frequency (after
14  * reset the HSI is used as SYSCLK source).
15  * If none of the define below is enabled, the HSI is used as System clock source.
16  */
17 /* #define SYSCLK_FREQ_HSE    HSE_VALUE */
18 /* #define SYSCLK_FREQ_24MHz  24000000  */
19 /* #define SYSCLK_FREQ_48MHz  48000000  */
20 /* #define SYSCLK_FREQ_56MHz  56000000  */
21 #define SYSCLK_FREQ_72MHz    72000000
22 
23 /* Clock Definitions */
24 #ifdef SYSCLK_FREQ_HSE
25 uint32_t      SystemCoreClock = SYSCLK_FREQ_HSE; /* System Clock Frequency (Core Clock) */
26 #elif defined SYSCLK_FREQ_24MHz
27 uint32_t    SystemCoreClock = SYSCLK_FREQ_24MHz; /* System Clock Frequency (Core Clock) */
28 #elif defined SYSCLK_FREQ_48MHz
29 uint32_t    SystemCoreClock = SYSCLK_FREQ_48MHz; /* System Clock Frequency (Core Clock) */
30 #elif defined SYSCLK_FREQ_56MHz
31 uint32_t    SystemCoreClock = SYSCLK_FREQ_56MHz; /* System Clock Frequency (Core Clock) */
32 #elif defined SYSCLK_FREQ_72MHz
33 uint32_t    SystemCoreClock = SYSCLK_FREQ_72MHz; /* System Clock Frequency (Core Clock) */
34 #else /* HSI Selected as System Clock source */
35 uint32_t SystemCoreClock = HSI_VALUE; /* System Clock Frequency (Core Clock) */
36 #endif
37 
38 __I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
39 
40 /* ch32v10x_system_private_function_proto_types */
41 static void SetSysClock(void);
42 
43 #ifdef SYSCLK_FREQ_HSE
44 static void   SetSysClockToHSE(void);
45 #elif defined SYSCLK_FREQ_24MHz
46 static void SetSysClockTo24(void);
47 #elif defined SYSCLK_FREQ_48MHz
48 static void SetSysClockTo48(void);
49 #elif defined SYSCLK_FREQ_56MHz
50 static void SetSysClockTo56(void);
51 #elif defined SYSCLK_FREQ_72MHz
52 static void SetSysClockTo72(void);
53 #endif
54 
55 /*********************************************************************
56  * @fn      SystemInit
57  *
58  * @brief   Setup the microcontroller system Initialize the Embedded Flash Interface,
59  *        the PLL and update the SystemCoreClock variable.
60  *
61  * @return  none
62  */
SystemInit(void)63 void SystemInit(void)
64 {
65     RCC->CTLR |= (uint32_t)0x00000001;
66     RCC->CFGR0 &= (uint32_t)0xF8FF0000;
67     RCC->CTLR &= (uint32_t)0xFEF6FFFF;
68     RCC->CTLR &= (uint32_t)0xFFFBFFFF;
69     RCC->CFGR0 &= (uint32_t)0xFF80FFFF;
70     RCC->INTR = 0x009F0000;
71     SetSysClock();
72 }
73 
74 /*********************************************************************
75  * @fn      SystemCoreClockUpdate
76  *
77  * @brief   Update SystemCoreClock variable according to Clock Register Values.
78  *
79  * @return  none
80  */
SystemCoreClockUpdate(void)81 void SystemCoreClockUpdate(void)
82 {
83     uint32_t tmp = 0, pllmull = 0, pllsource = 0;
84 
85     tmp = RCC->CFGR0 & RCC_SWS;
86 
87     switch(tmp)
88     {
89         case 0x00:
90             SystemCoreClock = HSI_VALUE;
91             break;
92         case 0x04:
93             SystemCoreClock = HSE_VALUE;
94             break;
95         case 0x08:
96             pllmull = RCC->CFGR0 & RCC_PLLMULL;
97             pllsource = RCC->CFGR0 & RCC_PLLSRC;
98             pllmull = (pllmull >> 18) + 2;
99             if(pllsource == 0x00)
100             {
101                 SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
102             }
103             else
104             {
105                 if((RCC->CFGR0 & RCC_PLLXTPRE) != (uint32_t)RESET)
106                 {
107                     SystemCoreClock = (HSE_VALUE >> 1) * pllmull;
108                 }
109                 else
110                 {
111                     SystemCoreClock = HSE_VALUE * pllmull;
112                 }
113             }
114             break;
115         default:
116             SystemCoreClock = HSI_VALUE;
117             break;
118     }
119 
120     tmp = AHBPrescTable[((RCC->CFGR0 & RCC_HPRE) >> 4)];
121     SystemCoreClock >>= tmp;
122 }
123 
124 /*********************************************************************
125  * @fn      SetSysClock
126  *
127  * @brief   Configures the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers.
128  *
129  * @return  none
130  */
SetSysClock(void)131 static void SetSysClock(void)
132 {
133 #ifdef SYSCLK_FREQ_HSE
134     SetSysClockToHSE();
135 #elif defined SYSCLK_FREQ_24MHz
136     SetSysClockTo24();
137 #elif defined SYSCLK_FREQ_48MHz
138     SetSysClockTo48();
139 #elif defined SYSCLK_FREQ_56MHz
140     SetSysClockTo56();
141 #elif defined SYSCLK_FREQ_72MHz
142     SetSysClockTo72();
143 #endif
144 
145     /* If none of the define above is enabled, the HSI is used as System clock
146      * source (default after reset)
147      */
148 }
149 
150 #ifdef SYSCLK_FREQ_HSE
151 
152 /*********************************************************************
153  * @fn      SetSysClockToHSE
154  *
155  * @brief   Sets HSE as System clock source and configure HCLK, PCLK2 and PCLK1 prescalers.
156  *
157  * @return  none
158  */
SetSysClockToHSE(void)159 static void SetSysClockToHSE(void)
160 {
161     __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
162 
163     RCC->CTLR |= ((uint32_t)RCC_HSEON);
164 
165     /* Wait till HSE is ready and if Time out is reached exit */
166     do
167     {
168         HSEStatus = RCC->CTLR & RCC_HSERDY;
169         StartUpCounter++;
170     } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
171 
172     if((RCC->CTLR & RCC_HSERDY) != RESET)
173     {
174         HSEStatus = (uint32_t)0x01;
175     }
176     else
177     {
178         HSEStatus = (uint32_t)0x00;
179     }
180 
181     if(HSEStatus == (uint32_t)0x01)
182     {
183         FLASH->ACTLR |= FLASH_ACTLR_PRFTBE;
184         /* Flash 0 wait state */
185         FLASH->ACTLR &= (uint32_t)((uint32_t)~FLASH_ACTLR_LATENCY);
186         FLASH->ACTLR |= (uint32_t)FLASH_ACTLR_LATENCY_0;
187 
188         /* HCLK = SYSCLK */
189         RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
190         /* PCLK2 = HCLK */
191         RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
192         /* PCLK1 = HCLK */
193         RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV1;
194 
195         /* Select HSE as system clock source */
196         RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_SW));
197         RCC->CFGR0 |= (uint32_t)RCC_SW_HSE;
198 
199         /* Wait till HSE is used as system clock source */
200         while((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x04)
201         {
202         }
203     }
204     else
205     {
206         /* If HSE fails to start-up, the application will have wrong clock
207          * configuration. User can add here some code to deal with this error
208          */
209     }
210 }
211 
212 #elif defined SYSCLK_FREQ_24MHz
213 
214 /*********************************************************************
215  * @fn      SetSysClockTo24
216  *
217  * @brief   Sets System clock frequency to 24MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
218  *
219  * @return  none
220  */
SetSysClockTo24(void)221 static void SetSysClockTo24(void)
222 {
223     __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
224 
225     RCC->CTLR |= ((uint32_t)RCC_HSEON);
226 
227     /* Wait till HSE is ready and if Time out is reached exit */
228     do
229     {
230         HSEStatus = RCC->CTLR & RCC_HSERDY;
231         StartUpCounter++;
232     } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
233 
234     if((RCC->CTLR & RCC_HSERDY) != RESET)
235     {
236         HSEStatus = (uint32_t)0x01;
237     }
238     else
239     {
240         HSEStatus = (uint32_t)0x00;
241     }
242     if(HSEStatus == (uint32_t)0x01)
243     {
244         /* Enable Prefetch Buffer */
245         FLASH->ACTLR |= FLASH_ACTLR_PRFTBE;
246 
247         /* Flash 0 wait state */
248         FLASH->ACTLR &= (uint32_t)((uint32_t)~FLASH_ACTLR_LATENCY);
249         FLASH->ACTLR |= (uint32_t)FLASH_ACTLR_LATENCY_0;
250 
251         /* HCLK = SYSCLK */
252         RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
253         /* PCLK2 = HCLK */
254         RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
255         /* PCLK1 = HCLK */
256         RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV1;
257 
258         RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
259         RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL3);
260         /* Enable PLL */
261         RCC->CTLR |= RCC_PLLON;
262 
263         /* Wait till PLL is ready */
264         while((RCC->CTLR & RCC_PLLRDY) == 0)
265         {
266         }
267         /* Select PLL as system clock source */
268         RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_SW));
269         RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
270         /* Wait till PLL is used as system clock source */
271         while((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
272         {
273         }
274     }
275     else
276     {
277         /* If HSE fails to start-up, the application will have wrong clock
278          * configuration. User can add here some code to deal with this error
279          */
280     }
281 }
282 
283 #elif defined SYSCLK_FREQ_48MHz
284 
285 /*********************************************************************
286  * @fn      SetSysClockTo48
287  *
288  * @brief   Sets System clock frequency to 48MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
289  *
290  * @return  none
291  */
SetSysClockTo48(void)292 static void SetSysClockTo48(void)
293 {
294     __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
295 
296     RCC->CTLR |= ((uint32_t)RCC_HSEON);
297     /* Wait till HSE is ready and if Time out is reached exit */
298     do
299     {
300         HSEStatus = RCC->CTLR & RCC_HSERDY;
301         StartUpCounter++;
302     } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
303 
304     if((RCC->CTLR & RCC_HSERDY) != RESET)
305     {
306         HSEStatus = (uint32_t)0x01;
307     }
308     else
309     {
310         HSEStatus = (uint32_t)0x00;
311     }
312 
313     if(HSEStatus == (uint32_t)0x01)
314     {
315         /* Enable Prefetch Buffer */
316         FLASH->ACTLR |= FLASH_ACTLR_PRFTBE;
317 
318         /* Flash 1 wait state */
319         FLASH->ACTLR &= (uint32_t)((uint32_t)~FLASH_ACTLR_LATENCY);
320         FLASH->ACTLR |= (uint32_t)FLASH_ACTLR_LATENCY_1;
321 
322         /* HCLK = SYSCLK */
323         RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
324         /* PCLK2 = HCLK */
325         RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
326         /* PCLK1 = HCLK */
327         RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
328 
329         /*  PLL configuration: PLLCLK = HSE * 6 = 48 MHz */
330         RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
331         RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLMULL6);
332 
333         /* Enable PLL */
334         RCC->CTLR |= RCC_PLLON;
335         /* Wait till PLL is ready */
336         while((RCC->CTLR & RCC_PLLRDY) == 0)
337         {
338         }
339         /* Select PLL as system clock source */
340         RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_SW));
341         RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
342         /* Wait till PLL is used as system clock source */
343         while((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
344         {
345         }
346     }
347     else
348     {
349         /*
350          * If HSE fails to start-up, the application will have wrong clock
351          * configuration. User can add here some code to deal with this error
352          */
353     }
354 }
355 
356 #elif defined SYSCLK_FREQ_56MHz
357 
358 /*********************************************************************
359  * @fn      SetSysClockTo56
360  *
361  * @brief   Sets System clock frequency to 56MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
362  *
363  * @return  none
364  */
SetSysClockTo56(void)365 static void SetSysClockTo56(void)
366 {
367     __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
368 
369     RCC->CTLR |= ((uint32_t)RCC_HSEON);
370 
371     /* Wait till HSE is ready and if Time out is reached exit */
372     do
373     {
374         HSEStatus = RCC->CTLR & RCC_HSERDY;
375         StartUpCounter++;
376     } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
377 
378     if((RCC->CTLR & RCC_HSERDY) != RESET)
379     {
380         HSEStatus = (uint32_t)0x01;
381     }
382     else
383     {
384         HSEStatus = (uint32_t)0x00;
385     }
386 
387     if(HSEStatus == (uint32_t)0x01)
388     {
389         /* Enable Prefetch Buffer */
390         FLASH->ACTLR |= FLASH_ACTLR_PRFTBE;
391 
392         /* Flash 2 wait state */
393         FLASH->ACTLR &= (uint32_t)((uint32_t)~FLASH_ACTLR_LATENCY);
394         FLASH->ACTLR |= (uint32_t)FLASH_ACTLR_LATENCY_2;
395 
396         /* HCLK = SYSCLK */
397         RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
398         /* PCLK2 = HCLK */
399         RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
400         /* PCLK1 = HCLK */
401         RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
402 
403         /* PLL configuration: PLLCLK = HSE * 7 = 56 MHz */
404         RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
405         RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLMULL7);
406         /* Enable PLL */
407         RCC->CTLR |= RCC_PLLON;
408         /* Wait till PLL is ready */
409         while((RCC->CTLR & RCC_PLLRDY) == 0)
410         {
411         }
412 
413         /* Select PLL as system clock source */
414         RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_SW));
415         RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
416         /* Wait till PLL is used as system clock source */
417         while((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
418         {
419         }
420     }
421     else
422     {
423         /*
424          * If HSE fails to start-up, the application will have wrong clock
425          * configuration. User can add here some code to deal with this error
426          */
427     }
428 }
429 
430 #elif defined SYSCLK_FREQ_72MHz
431 
432 /*********************************************************************
433  * @fn      SetSysClockTo72
434  *
435  * @brief   Sets System clock frequency to 72MHz and configure HCLK, PCLK2 and PCLK1 prescalers.
436  *
437  * @return  none
438  */
SetSysClockTo72(void)439 static void SetSysClockTo72(void)
440 {
441     __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
442 
443     RCC->CTLR |= ((uint32_t)RCC_HSEON);
444 
445     /* Wait till HSE is ready and if Time out is reached exit */
446     do
447     {
448         HSEStatus = RCC->CTLR & RCC_HSERDY;
449         StartUpCounter++;
450     } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
451 
452     if((RCC->CTLR & RCC_HSERDY) != RESET)
453     {
454         HSEStatus = (uint32_t)0x01;
455     }
456     else
457     {
458         HSEStatus = (uint32_t)0x00;
459     }
460 
461     if(HSEStatus == (uint32_t)0x01)
462     {
463         /* Enable Prefetch Buffer */
464         FLASH->ACTLR |= FLASH_ACTLR_PRFTBE;
465 
466         /* Flash 2 wait state */
467         FLASH->ACTLR &= (uint32_t)((uint32_t)~FLASH_ACTLR_LATENCY);
468         FLASH->ACTLR |= (uint32_t)FLASH_ACTLR_LATENCY_2;
469 
470         /* HCLK = SYSCLK */
471         RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
472         /* PCLK2 = HCLK */
473         RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
474         /* PCLK1 = HCLK */
475         RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
476 
477         /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
478         RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_PLLSRC | RCC_PLLXTPRE |
479                                               RCC_PLLMULL));
480         RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLMULL9);
481         /* Enable PLL */
482         RCC->CTLR |= RCC_PLLON;
483         /* Wait till PLL is ready */
484         while((RCC->CTLR & RCC_PLLRDY) == 0)
485         {
486         }
487         /* Select PLL as system clock source */
488         RCC->CFGR0 &= (uint32_t)((uint32_t) ~(RCC_SW));
489         RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
490         /* Wait till PLL is used as system clock source */
491         while((RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08)
492         {
493         }
494     }
495     else
496     {
497         /*
498          * If HSE fails to start-up, the application will have wrong clock
499          * configuration. User can add here some code to deal with this error
500          */
501     }
502 }
503 #endif
504