1 /*****************************************************************************
2  * Copyright (c) 2022, Nations Technologies Inc.
3  *
4  * All rights reserved.
5  * ****************************************************************************
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * - Redistributions of source code must retain the above copyright notice,
11  * this list of conditions and the disclaimer below.
12  *
13  * Nations' name may not be used to endorse or promote products derived from
14  * this software without specific prior written permission.
15  *
16  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
19  * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
22  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
25  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  * ****************************************************************************/
27 
28 /**
29  * @file system_n32l40x.c
30  * @author Nations
31  * @version v1.2.0
32  *
33  * @copyright Copyright (c) 2022, Nations Technologies Inc. All rights reserved.
34  */
35 #include "n32l40x.h"
36 
37 /* Uncomment the line corresponding to the desired System clock (SYSCLK)
38    frequency (after reset the HSI is used as SYSCLK source)
39 
40    IMPORTANT NOTE:
41    ==============
42    1. After each device reset the HSI is used as System clock source.
43 
44    2. Please make sure that the selected System clock doesn't exceed your
45    device's maximum frequency.
46 
47    3. If none of the define below is enabled, the HSI is used as System clock
48     source.
49 
50    4. The System clock configuration functions provided within this file assume
51    that:
52         - For Low, Medium and High density Value line devices an external 8MHz
53           crystal is used to drive the System clock.
54         - For Low, Medium and High density devices an external 8MHz crystal is
55           used to drive the System clock.
56         - For Connectivity line devices an external 25MHz crystal is used to
57    drive the System clock. If you are using different crystal you have to adapt
58    those functions accordingly.
59     */
60 
61 #define SYSCLK_USE_MSI     0
62 #define SYSCLK_USE_HSI     1
63 #define SYSCLK_USE_HSE     2
64 #define SYSCLK_USE_HSI_PLL 3
65 #define SYSCLK_USE_HSE_PLL 4
66 
67 #ifndef SYSCLK_FREQ
68 #define SYSCLK_FREQ 64000000
69 #endif
70 
71 /*
72 * SYSCLK_SRC *
73 ** SYSCLK_USE_MSI      **
74 ** SYSCLK_USE_HSI      **
75 ** SYSCLK_USE_HSE      **
76 ** SYSCLK_USE_HSI_PLL  **
77 ** SYSCLK_USE_HSE_PLL  **
78 */
79 #ifndef SYSCLK_SRC
80 #define SYSCLK_SRC SYSCLK_USE_HSE_PLL
81 #endif
82 
83 #define PLL_DIV2_DISABLE 0x00000000
84 #define PLL_DIV2_ENABLE 0x00000002
85 #define SRAM_VOL   (__IO unsigned*)(0x40001800 + 0x20)
86 #define ConfigSRAMVoltage(vale) do{(*SRAM_VOL ) &= (~(uint32_t)(1 <<25));(*SRAM_VOL ) |= (uint32_t)(vale <<25);}while (0) //vale only equal to 0,1
87 #if SYSCLK_SRC == SYSCLK_USE_MSI
88 
89     #if (SYSCLK_FREQ == MSI_VALUE_L0)
90         #define MSI_CLK 0
91     #elif (SYSCLK_FREQ == MSI_VALUE_L1)
92         #define MSI_CLK 1
93     #elif (SYSCLK_FREQ == MSI_VALUE_L2)
94         #define MSI_CLK 2
95     #elif (SYSCLK_FREQ == MSI_VALUE_L3)
96         #define MSI_CLK 3
97     #elif (SYSCLK_FREQ == MSI_VALUE_L4)
98         #define MSI_CLK 4
99     #elif (SYSCLK_FREQ == MSI_VALUE_L5)
100         #define MSI_CLK 5
101     #elif (SYSCLK_FREQ == MSI_VALUE_L6)
102         #define MSI_CLK 6
103     #else
104         #error SYSCL_FREQ must be set to MSI_VALUE_Lx(x=0~6)
105     #endif
106 
107 #elif SYSCLK_SRC == SYSCLK_USE_HSI
108 
109     #if SYSCLK_FREQ != HSI_VALUE
110         #error SYSCL_FREQ must be set to HSI_VALUE
111     #endif
112 
113 #elif SYSCLK_SRC == SYSCLK_USE_HSE
114 
115     #ifndef HSE_VALUE
116         #error HSE_VALUE must be defined!
117     #endif
118 
119     #if SYSCLK_FREQ != HSE_VALUE
120         #error SYSCL_FREQ must be set to HSE_VALUE
121     #endif
122 
123 #elif SYSCLK_SRC == SYSCLK_USE_HSI_PLL
124 
125     #ifndef HSI_VALUE
126         #error HSI_VALUE must be defined!
127     #endif
128 
129     #if ((SYSCLK_FREQ % (HSI_VALUE / 2)) == 0) && (SYSCLK_FREQ / (HSI_VALUE / 2) >= 2)                                     \
130         && (SYSCLK_FREQ / (HSI_VALUE / 2) <= 32)
131 
132         #define PLLSRC_DIV 2
133         #define PLL_DIV    PLL_DIV2_DISABLE
134         #define PLL_MUL    (SYSCLK_FREQ / (HSI_VALUE / 2))
135 
136     #elif (SYSCLK_FREQ % HSI_VALUE == 0) && (SYSCLK_FREQ / HSI_VALUE >= 2) && (SYSCLK_FREQ / HSI_VALUE <= 32)
137 
138         #define PLLSRC_DIV 1
139         #define PLL_DIV    PLL_DIV2_DISABLE
140         #define PLL_MUL    (SYSCLK_FREQ / HSI_VALUE)
141 
142     #elif ((SYSCLK_FREQ % (HSI_VALUE / 4)) == 0) && (SYSCLK_FREQ / (HSI_VALUE / 4) >= 2)                                     \
143           && (SYSCLK_FREQ / (HSI_VALUE / 4) <= 32)
144 
145         #define PLLSRC_DIV 2
146         #define PLL_DIV    PLL_DIV2_ENABLE
147         #define PLL_MUL    (SYSCLK_FREQ / (HSI_VALUE / 4))
148 
149     #else
150         #error Cannot make a PLL multiply factor to SYSCLK_FREQ.
151     #endif
152 
153 #elif SYSCLK_SRC == SYSCLK_USE_HSE_PLL
154 
155     #ifndef HSE_VALUE
156         #error HSE_VALUE must be defined!
157     #endif
158 
159     #if ((SYSCLK_FREQ % (HSE_VALUE / 2)) == 0) && (SYSCLK_FREQ / (HSE_VALUE / 2) >= 2)                                     \
160         && (SYSCLK_FREQ / (HSE_VALUE / 2) <= 32)
161 
162         #define PLLSRC_DIV 2
163         #define PLL_DIV    PLL_DIV2_DISABLE
164         #define PLL_MUL    (SYSCLK_FREQ / (HSE_VALUE / 2))
165 
166     #elif (SYSCLK_FREQ % HSE_VALUE == 0) && (SYSCLK_FREQ / HSE_VALUE >= 2) && (SYSCLK_FREQ / HSE_VALUE <= 32)
167 
168         #define PLLSRC_DIV 1
169         #define PLL_DIV    PLL_DIV2_DISABLE
170         #define PLL_MUL    (SYSCLK_FREQ / HSE_VALUE)
171 
172     #elif ((SYSCLK_FREQ % (HSE_VALUE / 4)) == 0) && (SYSCLK_FREQ / (HSE_VALUE / 4) >= 2)                                     \
173           && (SYSCLK_FREQ / (HSE_VALUE / 4) <= 32)
174 
175         #define PLLSRC_DIV 2
176         #define PLL_DIV    PLL_DIV2_ENABLE
177         #define PLL_MUL    (SYSCLK_FREQ / (HSE_VALUE / 4))
178 
179     #else
180         #error Cannot make a PLL multiply factor to SYSCLK_FREQ.
181     #endif
182 
183 #else
184 #error wrong value for SYSCLK_SRC
185 #endif
186 
187 /* #define VECT_TAB_SRAM */
188 #define VECT_TAB_OFFSET 0x0 /*!< Vector Table base offset field. This value must be a multiple of 0x200. */
189 
190 /*******************************************************************************
191  *  Clock Definitions
192  *******************************************************************************/
193 uint32_t SystemCoreClock = SYSCLK_FREQ; /*!< System Clock Frequency (Core Clock) */
194 
195 const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
196 const uint32_t MSIClockTable[7] = {MSI_VALUE_L0, MSI_VALUE_L1, MSI_VALUE_L2, MSI_VALUE_L3,
197                                    MSI_VALUE_L4, MSI_VALUE_L5, MSI_VALUE_L6};
198 
199 static void SetSysClock(void);
200 
201 #ifdef DATA_IN_ExtSRAM
202 static void SystemInit_ExtMemCtl(void);
203 #endif /* DATA_IN_ExtSRAM */
204 
205 /**
206  * @brief  Setup the microcontroller system
207  *         Initialize the Embedded Flash Interface, the PLL and update the
208  *         SystemCoreClock variable.
209  * @note   This function should be used only after reset.
210  */
SystemInit(void)211 void SystemInit(void)
212 {
213     /* FPU settings
214      * ------------------------------------------------------------*/
215 #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
216     SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); /* set CP10 and CP11 Full Access */
217 #endif
218 
219     /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
220     /* Set MSIEN bit */
221     RCC->CTRLSTS |= (uint32_t)0x00000004;
222 
223     /* Reset SW, HPRE, PPRE1, PPRE2 and MCO bits */
224     RCC->CFG &= (uint32_t)0xF8FFC000;
225 
226     /* Reset HSEON, CLKSSEN and PLLEN bits */
227     RCC->CTRL &= (uint32_t)0xFEF6FFFF;
228 
229     /* Reset HSEBYP bit */
230     RCC->CTRL &= (uint32_t)0xFFFBFFFF;
231 
232     /* Reset PLLSRC, PLLXTPRE, PLLMUL, MCOPRES and USBPRES bits */
233     RCC->CFG &= (uint32_t)0x0700FFFF;
234 
235     /* Reset CFG2 register */
236     RCC->CFG2 = 0x00007000;
237 
238     /* Reset CFG3 register */
239     RCC->CFG3 = 0x00003800;
240 
241     /* Reset RDCTRL register */
242     RCC->RDCTRL = 0x00000000;
243 
244     /* Reset PLLHSIPRE register */
245     RCC->PLLHSIPRE = 0x00000000;
246 
247     /* Disable all interrupts and clear pending bits  */
248     RCC->CLKINT = 0x04BF8000;
249 
250     /* Enable ex mode */
251     RCC->APB1PCLKEN |= RCC_APB1PCLKEN_PWREN;
252 
253     if ((PWR->CTRL1 & PWR_CTRL1_MRSEL2) == PWR_CTRL1_MRSEL2)
254     {
255         ConfigSRAMVoltage(1);
256     }
257     /* Enable ICACHE and Prefetch Buffer */
258     FLASH->AC |= (uint32_t)(FLASH_AC_ICAHEN | FLASH_AC_PRFTBFEN);
259 
260     /* Checks whether the Low Voltage Mode status is SET or RESET */
261     if ((FLASH->AC & FLASH_AC_LVMF) != RESET)
262     {
263         /* FLASH Low Voltage Mode Disable */
264         FLASH->AC &= (uint32_t)(~FLASH_AC_LVMEN);
265     }
266 
267 #ifdef DATA_IN_ExtSRAM
268     SystemInit_ExtMemCtl();
269 #endif /* DATA_IN_ExtSRAM */
270 
271     /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
272     /* Configure the Flash Latency cycles and enable prefetch buffer */
273     SetSysClock();
274 
275 #ifdef VECT_TAB_SRAM
276     SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
277 #else
278     SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
279 #endif
280 }
281 
282 /**
283  * @brief  Update SystemCoreClock variable according to Clock Register Values.
284  *         The SystemCoreClock variable contains the core clock (HCLK), it can
285  *         be used by the user application to setup the SysTick timer or
286  * configure other parameters.
287  *
288  * @note   Each time the core clock (HCLK) changes, this function must be called
289  *         to update SystemCoreClock variable value. Otherwise, any
290  * configuration based on this variable will be incorrect.
291  *
292  * @note   - The system frequency computed by this function is not the real
293  *           frequency in the chip. It is calculated based on the predefined
294  *           constant and the selected clock source:
295  *
296  *           - If SYSCLK source is MSI, SystemCoreClock will contain the
297  * MSI_VALUE(*)
298  *
299  *           - If SYSCLK source is HSI, SystemCoreClock will contain the
300  * HSI_VALUE(**)
301  *
302  *           - If SYSCLK source is HSE, SystemCoreClock will contain the
303  * HSE_VALUE(***)
304  *
305  *           - If SYSCLK source is PLL, SystemCoreClock will contain the
306  * HSE_VALUE(***) or HSI_VALUE(**) multiplied by the PLL factors.
307  *
308  *         (*) MSI_VALUE is a constant defined in n32l40x.h file (default value
309  *             4 MHz, 100KHz/200KHz/400KHz/800KHz/1MHz/2MHz/4MHz ) but the real
310  *             value may vary depending on the variations in voltage and temperature.
311  *
312  *         (**) HSI_VALUE is a constant defined in n32l40x.h file (default value
313  *             8 MHz) but the real value may vary depending on the variations
314  *             in voltage and temperature.
315  *
316  *         (***) HSE_VALUE is a constant defined in n32l40x.h file (default value
317  *              8 MHz or 25 MHz, depedning on the product used), user has to
318  *              ensure that HSE_VALUE is same as the real frequency of the crystal used.
319  *              Otherwise, this function may have wrong result.
320  *
321  *         - The result of this function could be not correct when using
322  * fractional value for HSE crystal.
323  */
SystemCoreClockUpdate(void)324 void SystemCoreClockUpdate(void)
325 {
326     uint32_t tmp = 0, pllmull = 0, pllsource = 0, plldiv2 = 0;
327     uint8_t msi_clk = 0;
328 
329     /* Get SYSCLK source
330      * -------------------------------------------------------*/
331     tmp = RCC->CFG & RCC_CFG_SCLKSTS;
332 
333     /* Get MSI clock
334      * -------------------------------------------------------*/
335     msi_clk = (uint8_t) ((RCC->CTRLSTS & RCC_CTRLSTS_MSIRANGE)>>4);
336 
337     switch (tmp)
338     {
339     case 0x00: /* MSI used as system clock */
340         SystemCoreClock = MSIClockTable[msi_clk];
341         break;
342     case 0x04: /* HSI used as system clock */
343         SystemCoreClock = HSI_VALUE;
344         break;
345     case 0x08: /* HSE used as system clock */
346         SystemCoreClock = HSE_VALUE;
347         break;
348     case 0x0C: /* PLL used as system clock */
349 
350         /* Get PLL clock source and multiplication factor
351          * ----------------------*/
352         pllmull   = RCC->CFG & RCC_CFG_PLLMULFCT;
353         pllsource = RCC->CFG & RCC_CFG_PLLSRC;
354         plldiv2   = RCC->PLLHSIPRE & RCC_PLLHSIPRE_PLLSRCDIV;
355 
356         if ((pllmull & RCC_CFG_PLLMULFCT_4) == 0)
357         {
358             pllmull = (pllmull >> 18) + 2; // PLLMUL[4]=0
359         }
360         else
361         {
362             pllmull = ((pllmull >> 18) - 496) + 1; // PLLMUL[4]=1
363         }
364 
365         if (pllsource == 0x00)
366         {
367             /* HSI selected as PLL clock entry */
368             if ((RCC->PLLHSIPRE & RCC_PLLHSIPRE_PLLSRCDIV) != (uint32_t)RESET)
369             { /* HSI oscillator clock divided by 2 */
370                 SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
371             }
372             else
373             {
374                 SystemCoreClock = HSI_VALUE * pllmull;
375             }
376         }
377         else
378         {
379             /* HSE selected as PLL clock entry */
380             if ((RCC->CFG & RCC_CFG_PLLHSEPRES) != (uint32_t)RESET)
381             { /* HSE oscillator clock divided by 2 */
382                 SystemCoreClock = (HSE_VALUE >> 1) * pllmull;
383             }
384             else
385             {
386                 SystemCoreClock = HSE_VALUE * pllmull;
387             }
388         }
389 
390         if (plldiv2 == 0x02)
391         {
392             /* PLL source clock divided by 2 selected as PLL clock entry */
393             SystemCoreClock >>= 1;
394         }
395 
396         break;
397 
398     default:
399         SystemCoreClock = MSIClockTable[msi_clk];
400         break;
401     }
402 
403     /* Compute HCLK clock frequency ----------------*/
404     /* Get HCLK prescaler */
405     tmp = AHBPrescTable[((RCC->CFG & RCC_CFG_AHBPRES) >> 4)];
406     /* HCLK clock frequency */
407     SystemCoreClock >>= tmp;
408 }
409 
410 /**
411  * @brief  Configures the System PWR level to 1.0V
412  * .
413  */
ConfigMRVoltage1V(void)414 void ConfigMRVoltage1V(void)
415 {
416     uint32_t  i=0;
417     ConfigSRAMVoltage(1);                  //SRAM read margin setting switch in 0.9/lprun mode: use low voltage mode settings and 1.0v use normal mode
418     PWR->CTRL1 &= (uint32_t)(~PWR_CTRL1_MRSEL);
419     PWR->CTRL1 |= PWR_CTRL1_MRSEL2;        //MR=1.0V
420     while ((PWR->STS2 &PWR_STS2_MRF) != 0);               // wait VOSF to be 0 first
421     for(i=0;i<0x2A;i++);
422     while ((PWR->STS2 & PWR_STS2_MRF) != PWR_STS2_MRF);   // wait VOSF to be 1 then
423 }
424 /**
425  * @brief  Configures the System clock frequency, HCLK, PCLK2 and PCLK1
426  * prescalers.
427  */
SetSysClock(void)428 static void SetSysClock(void)
429 {
430     uint32_t rcc_cfg        = 0;
431     uint32_t rcc_pllhsipre  = 0;
432     uint32_t StartUpCounter = 0;
433 
434 #if (SYSCLK_SRC == SYSCLK_USE_MSI)
435     uint8_t i=0;
436     bool MSIStatus = 0;
437     /* Config MSI */
438     RCC->CTRLSTS &= 0xFFFFFF8F;
439     /*Delay for while*/
440     for(i=0;i<0x30;i++);
441     RCC->CTRLSTS |= (((uint32_t)MSI_CLK) << 4);
442     /*Delay for while*/
443     for(i=0;i<0x30;i++);
444     /* Enable MSI */
445     RCC->CTRLSTS |= ((uint32_t)RCC_CTRLSTS_MSIEN);
446 
447     /* Wait till MSI is ready and if Time out is reached exit */
448     do
449     {
450         MSIStatus = RCC->CTRLSTS & RCC_CTRLSTS_MSIRD;
451         StartUpCounter++;
452     } while ((MSIStatus == 0) && (StartUpCounter != MSI_STARTUP_TIMEOUT));
453 
454     MSIStatus = ((RCC->CTRLSTS & RCC_CTRLSTS_MSIRD) != RESET);
455     if (!MSIStatus)
456     {
457         /* If MSI fails to start-up, the application will have wrong clock
458          * configuration. User can add here some code to deal with this error */
459         SystemCoreClock = MSI_VALUE_L6;
460         return;
461     }
462 
463 #elif ((SYSCLK_SRC == SYSCLK_USE_HSI) || (SYSCLK_SRC == SYSCLK_USE_HSI_PLL))
464 
465     bool HSIStatus = 0;
466     /* Enable HSI */
467     RCC->CTRL |= ((uint32_t)RCC_CTRL_HSIEN);
468 
469     /* Wait till HSI is ready and if Time out is reached exit */
470     do
471     {
472         HSIStatus = RCC->CTRL & RCC_CTRL_HSIRDF;
473         StartUpCounter++;
474     } while ((HSIStatus == 0) && (StartUpCounter != HSI_STARTUP_TIMEOUT));
475 
476     HSIStatus = ((RCC->CTRL & RCC_CTRL_HSIRDF) != RESET);
477     if (!HSIStatus)
478     {
479         /* If HSI fails to start-up, the application will have wrong clock
480          * configuration. User can add here some code to deal with this error */
481         SystemCoreClock = MSI_VALUE_L6;
482         return;
483     }
484 
485 #elif ((SYSCLK_SRC == SYSCLK_USE_HSE) || (SYSCLK_SRC == SYSCLK_USE_HSE_PLL))
486 
487     bool HSEStatus = 0;
488     /* Enable HSE */
489     RCC->CTRL |= ((uint32_t)RCC_CTRL_HSEEN);
490 
491     /* Wait till HSE is ready and if Time out is reached exit */
492     do
493     {
494         HSEStatus = RCC->CTRL & RCC_CTRL_HSERDF;
495         StartUpCounter++;
496     } while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
497 
498     HSEStatus = ((RCC->CTRL & RCC_CTRL_HSERDF) != RESET);
499     if (!HSEStatus)
500     {
501         /* If HSE fails to start-up, the application will have wrong clock
502          * configuration. User can add here some code to deal with this error */
503         SystemCoreClock = MSI_VALUE_L6;
504         return;
505     }
506 #endif
507 
508     ConfigMRVoltage1V();
509 
510     /* Flash wait state
511         0: HCLK <= 32M
512         1: HCLK <= 64M
513      */
514     FLASH->AC &= (uint32_t)((uint32_t)~FLASH_AC_LATENCY);
515     FLASH->AC |= (uint32_t)((SYSCLK_FREQ - 1) / 32000000);
516 
517     /* HCLK = SYSCLK */
518     RCC->CFG |= (uint32_t)RCC_CFG_AHBPRES_DIV1;
519 
520     /* PCLK2 max 32M */
521     if (SYSCLK_FREQ > 54000000)
522     {
523         RCC->CFG |= (uint32_t)RCC_CFG_APB2PRES_DIV2;
524     }
525     else
526     {
527         RCC->CFG |= (uint32_t)RCC_CFG_APB2PRES_DIV1;
528     }
529 
530     /* PCLK1 max 16M */
531     if (SYSCLK_FREQ > 54000000)
532     {
533         RCC->CFG |= (uint32_t)RCC_CFG_APB1PRES_DIV4;
534     }
535     else if (SYSCLK_FREQ > 27000000)
536     {
537         RCC->CFG |= (uint32_t)RCC_CFG_APB1PRES_DIV2;
538     }
539     else
540     {
541         RCC->CFG |= (uint32_t)RCC_CFG_APB1PRES_DIV1;
542     }
543 
544 #if SYSCLK_SRC == SYSCLK_USE_MSI
545     /* Select MSI as system clock source */
546     RCC->CFG &= (uint32_t)((uint32_t) ~(RCC_CFG_SCLKSW));
547     RCC->CFG |= (uint32_t)RCC_CFG_SCLKSW_MSI;
548 
549     /* Wait till MSI is used as system clock source */
550     while ((RCC->CFG & (uint32_t)RCC_CFG_SCLKSTS) != (uint32_t)0x00)
551     {
552     }
553 #elif SYSCLK_SRC == SYSCLK_USE_HSI
554     /* Select HSI as system clock source */
555     RCC->CFG &= (uint32_t)((uint32_t) ~(RCC_CFG_SCLKSW));
556     RCC->CFG |= (uint32_t)RCC_CFG_SCLKSW_HSI;
557 
558     /* Wait till HSI is used as system clock source */
559     while ((RCC->CFG & (uint32_t)RCC_CFG_SCLKSTS) != (uint32_t)0x04)
560     {
561     }
562 #elif SYSCLK_SRC == SYSCLK_USE_HSE
563     /* Select HSE as system clock source */
564     RCC->CFG &= (uint32_t)((uint32_t) ~(RCC_CFG_SCLKSW));
565     RCC->CFG |= (uint32_t)RCC_CFG_SCLKSW_HSE;
566 
567     /* Wait till HSE is used as system clock source */
568     while ((RCC->CFG & (uint32_t)RCC_CFG_SCLKSTS) != (uint32_t)0x08)
569     {
570     }
571 #elif SYSCLK_SRC == SYSCLK_USE_HSI_PLL || SYSCLK_SRC == SYSCLK_USE_HSE_PLL
572 
573     /* clear bits */
574     RCC->CFG &= (uint32_t)((uint32_t) ~(RCC_CFG_PLLSRC | RCC_CFG_PLLHSEPRES | RCC_CFG_PLLMULFCT));
575     RCC->PLLHSIPRE &= (uint32_t)((uint32_t) ~(RCC_PLLHSIPRE_PLLHSIPRE | RCC_PLLHSIPRE_PLLSRCDIV));
576 
577     /* set PLL source */
578     rcc_cfg = RCC->CFG;
579     rcc_cfg |= (SYSCLK_SRC == SYSCLK_USE_HSI_PLL ? RCC_CFG_PLLSRC_HSI : RCC_CFG_PLLSRC_HSE);
580     /* PLL DIV */
581     rcc_pllhsipre = RCC->PLLHSIPRE;
582 
583     #if SYSCLK_SRC == SYSCLK_USE_HSI_PLL
584         rcc_pllhsipre |= (PLLSRC_DIV == 1 ? RCC_PLLHSIPRE_PLLHSIPRE_HSI : RCC_PLLHSIPRE_PLLHSIPRE_HSI_DIV2);
585     #elif SYSCLK_SRC == SYSCLK_USE_HSE_PLL
586         rcc_cfg |= (PLLSRC_DIV == 1 ? RCC_CFG_PLLHSEPRES_HSE : RCC_CFG_PLLHSEPRES_HSE_DIV2);
587     #endif
588 
589     /* set PLL DIV */
590     rcc_pllhsipre |= (PLL_DIV == PLL_DIV2_DISABLE ? RCC_PLLHSIPRE_PLLSRCDIV_DISABLE : RCC_PLLHSIPRE_PLLSRCDIV_ENABLE);
591 
592     /* set PLL multiply factor */
593     #if PLL_MUL <= 16
594         rcc_cfg |= (PLL_MUL - 2) << 18;
595     #else
596         rcc_cfg |= ((PLL_MUL - 17) << 18) | (1 << 27);
597     #endif
598 
599     RCC->CFG       = rcc_cfg;
600     RCC->PLLHSIPRE = rcc_pllhsipre;
601 
602     /* Enable PLL */
603     RCC->CTRL |= RCC_CTRL_PLLEN;
604 
605     /* Wait till PLL is ready */
606     while ((RCC->CTRL & RCC_CTRL_PLLRDF) == 0)
607     {
608     }
609 
610     /* Select PLL as system clock source */
611     RCC->CFG &= (uint32_t)((uint32_t) ~(RCC_CFG_SCLKSW));
612     RCC->CFG |= (uint32_t)RCC_CFG_SCLKSW_PLL;
613 
614     /* Wait till PLL is used as system clock source */
615     while ((RCC->CFG & (uint32_t)RCC_CFG_SCLKSTS) != (uint32_t)0x0C)
616     {
617     }
618 #endif
619 }
620