1 /*****************************************************************************
2  * Copyright (c) 2019, 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_n32wb452.c
30  * @author Nations
31  * @version v1.0.2
32  *
33  * @copyright Copyright (c) 2019, Nations Technologies Inc. All rights reserved.
34  */
35 #include "n32wb452.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_HSI     0
62 #define SYSCLK_USE_HSE     1
63 #define SYSCLK_USE_HSI_PLL 2
64 #define SYSCLK_USE_HSE_PLL 3
65 
66 #ifndef SYSCLK_FREQ
67 #define SYSCLK_FREQ 144000000
68 #endif
69 
70 #ifndef SYSCLK_SRC
71 #define SYSCLK_SRC SYSCLK_USE_HSE_PLL
72 #endif
73 
74 #if SYSCLK_SRC == SYSCLK_USE_HSI
75 
76 #if SYSCLK_FREQ != HSI_VALUE
77 #error SYSCL_FREQ must be set to HSI_VALUE
78 #endif
79 
80 #elif SYSCLK_SRC == SYSCLK_USE_HSE
81 
82 #ifndef HSE_VALUE
83 #error HSE_VALUE must be defined!
84 #endif
85 
86 #if SYSCLK_FREQ != HSE_VALUE
87 #error SYSCL_FREQ must be set to HSE_VALUE
88 #endif
89 
90 #elif SYSCLK_SRC == SYSCLK_USE_HSI_PLL
91 
92 #if (SYSCLK_FREQ % (HSI_VALUE / 2) == 0) && (SYSCLK_FREQ / (HSI_VALUE / 2) >= 2)                                       \
93     && (SYSCLK_FREQ / (HSI_VALUE / 2) <= 32)
94 
95 #define PLLSRC_DIV 2
96 #define PLL_MUL    (SYSCLK_FREQ / (HSI_VALUE / 2))
97 
98 #else
99 #error Cannot make a PLL multiply factor to SYSCLK_FREQ.
100 #endif
101 
102 #elif SYSCLK_SRC == SYSCLK_USE_HSE_PLL
103 
104 #ifndef HSE_VALUE
105 #error HSE_VALUE must be defined!
106 #endif
107 
108 #if ((SYSCLK_FREQ % (HSE_VALUE / 2)) == 0) && (SYSCLK_FREQ / (HSE_VALUE / 2) >= 2)                                     \
109     && (SYSCLK_FREQ / (HSE_VALUE / 2) <= 32)
110 
111 #define PLLSRC_DIV 2
112 #define PLL_MUL    (SYSCLK_FREQ / (HSE_VALUE / 2))
113 
114 #elif (SYSCLK_FREQ % HSE_VALUE == 0) && (SYSCLK_FREQ / HSE_VALUE >= 2) && (SYSCLK_FREQ / HSE_VALUE <= 32)
115 
116 #define PLLSRC_DIV 1
117 #define PLL_MUL    (SYSCLK_FREQ / HSE_VALUE)
118 
119 #else
120 #error Cannot make a PLL multiply factor to SYSCLK_FREQ.
121 #endif
122 
123 #else
124 #error wrong value for SYSCLK_SRC
125 #endif
126 
127 /* #define VECT_TAB_SRAM */
128 #define VECT_TAB_OFFSET 0x0 /*!< Vector Table base offset field. This value must be a multiple of 0x200. */
129 
130 /*******************************************************************************
131  *  Clock Definitions
132  *******************************************************************************/
133 uint32_t SystemCoreClock = SYSCLK_FREQ; /*!< System Clock Frequency (Core Clock) */
134 
135 const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
136 
137 static void SetSysClock(void);
138 
139 #ifdef DATA_IN_ExtSRAM
140 static void SystemInit_ExtMemCtl(void);
141 #endif /* DATA_IN_ExtSRAM */
142 
143 /**
144  * @brief  Setup the microcontroller system
145  *         Initialize the Embedded Flash Interface, the PLL and update the
146  *         SystemCoreClock variable.
147  * @note   This function should be used only after reset.
148  */
SystemInit(void)149 void SystemInit(void)
150 {
151     /* FPU settings
152      * ------------------------------------------------------------*/
153 #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
154     SCB->CPACR |= ((3UL << 10 * 2) | (3UL << 11 * 2)); /* set CP10 and CP11 Full Access */
155 #endif
156 
157     /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
158     /* Set HSIEN bit */
159     RCC->CTRL |= (uint32_t)0x00000001;
160 
161     /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
162     RCC->CFG &= (uint32_t)0xF8FFC000;
163 
164     /* Reset HSEON, CLKSSEN and PLLEN bits */
165     RCC->CTRL &= (uint32_t)0xFEF6FFFF;
166 
167     /* Reset HSEBYP bit */
168     RCC->CTRL &= (uint32_t)0xFFFBFFFF;
169 
170     /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRES/OTGFSPRE bits */
171     RCC->CFG &= (uint32_t)0xF700FFFF;
172 
173     /* Reset CFG2 register */
174     RCC->CFG2 = 0x00003800;
175 
176     /* Reset CFG3 register */
177     RCC->CFG3 = 0x00003840;
178 
179     /* Disable all interrupts and clear pending bits  */
180     RCC->CLKINT = 0x009F0000;
181 
182     /* Enable ex mode */
183     RCC->APB1PCLKEN |= RCC_APB1PCLKEN_PWREN;
184     PWR->CTRL3 |= 0x00000001;
185     RCC->APB1PCLKEN &= (uint32_t)(~RCC_APB1PCLKEN_PWREN);
186 
187     /* Enable ICACHE and Prefetch Buffer */
188      FLASH->AC |= (uint32_t)(FLASH_AC_ICAHEN | FLASH_AC_PRFTBFEN);
189 
190 #ifdef DATA_IN_ExtSRAM
191     SystemInit_ExtMemCtl();
192 #endif /* DATA_IN_ExtSRAM */
193 
194     /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
195     /* Configure the Flash Latency cycles and enable prefetch buffer */
196     SetSysClock();
197 
198 #ifdef VECT_TAB_SRAM
199     SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
200 #else
201     SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
202 #endif
203 }
204 
205 /**
206  * @brief  Update SystemCoreClock variable according to Clock Register Values.
207  *         The SystemCoreClock variable contains the core clock (HCLK), it can
208  *         be used by the user application to setup the SysTick timer or
209  * configure other parameters.
210  *
211  * @note   Each time the core clock (HCLK) changes, this function must be called
212  *         to update SystemCoreClock variable value. Otherwise, any
213  * configuration based on this variable will be incorrect.
214  *
215  * @note   - The system frequency computed by this function is not the real
216  *           frequency in the chip. It is calculated based on the predefined
217  *           constant and the selected clock source:
218  *
219  *           - If SYSCLK source is HSI, SystemCoreClock will contain the
220  * HSI_VALUE(*)
221  *
222  *           - If SYSCLK source is HSE, SystemCoreClock will contain the
223  * HSE_VALUE(**)
224  *
225  *           - If SYSCLK source is PLL, SystemCoreClock will contain the
226  * HSE_VALUE(**) or HSI_VALUE(*) multiplied by the PLL factors.
227  *
228  *         (*) HSI_VALUE is a constant defined in n32wb452.h file (default value
229  *             8 MHz) but the real value may vary depending on the variations
230  *             in voltage and temperature.
231  *
232  *         (**) HSE_VALUE is a constant defined in N32WB452.h file (default value
233  *              8 MHz or 25 MHz, depedning on the product used), user has to
234  * ensure that HSE_VALUE is same as the real frequency of the crystal used.
235  *              Otherwise, this function may have wrong result.
236  *
237  *         - The result of this function could be not correct when using
238  * fractional value for HSE crystal.
239  */
SystemCoreClockUpdate(void)240 void SystemCoreClockUpdate(void)
241 {
242     uint32_t tmp = 0, pllmull = 0, pllsource = 0;
243 
244     /* Get SYSCLK source
245      * -------------------------------------------------------*/
246     tmp = RCC->CFG & RCC_CFG_SCLKSTS;
247 
248     switch (tmp)
249     {
250     case 0x00: /* HSI used as system clock */
251         SystemCoreClock = HSI_VALUE;
252         break;
253     case 0x04: /* HSE used as system clock */
254         SystemCoreClock = HSE_VALUE;
255         break;
256     case 0x08: /* PLL used as system clock */
257 
258         /* Get PLL clock source and multiplication factor
259          * ----------------------*/
260         pllmull   = RCC->CFG & RCC_CFG_PLLMULFCT;
261         pllsource = RCC->CFG & RCC_CFG_PLLSRC;
262 
263         if ((pllmull & RCC_CFG_PLLMULFCT_4) == 0)
264         {
265             pllmull = (pllmull >> 18) + 2; // PLLMUL[4]=0
266         }
267         else
268         {
269             pllmull = ((pllmull >> 18) - 496) + 1; // PLLMUL[4]=1
270         }
271 
272         if (pllsource == 0x00)
273         {
274             /* HSI oscillator clock divided by 2 selected as PLL clock entry */
275             SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
276         }
277         else
278         {
279             /* HSE selected as PLL clock entry */
280             if ((RCC->CFG & RCC_CFG_PLLHSEPRES) != (uint32_t)RESET)
281             { /* HSE oscillator clock divided by 2 */
282                 SystemCoreClock = (HSE_VALUE >> 1) * pllmull;
283             }
284             else
285             {
286                 SystemCoreClock = HSE_VALUE * pllmull;
287             }
288         }
289 
290         break;
291 
292     default:
293         SystemCoreClock = HSI_VALUE;
294         break;
295     }
296 
297     /* Compute HCLK clock frequency ----------------*/
298     /* Get HCLK prescaler */
299     tmp = AHBPrescTable[((RCC->CFG & RCC_CFG_AHBPRES) >> 4)];
300     /* HCLK clock frequency */
301     SystemCoreClock >>= tmp;
302 }
303 
304 /**
305  * @brief  Configures the System clock frequency, HCLK, PCLK2 and PCLK1
306  * prescalers.
307  */
SetSysClock(void)308 static void SetSysClock(void)
309 {
310     uint32_t rcc_cfgr       = 0;
311     bool HSEStatus          = 0;
312     uint32_t StartUpCounter = 0;
313 
314 #if SYSCLK_SRC == SYSCLK_USE_HSE || SYSCLK_SRC == SYSCLK_USE_HSE_PLL
315 
316     /* Enable HSE */
317     RCC->CTRL |= ((uint32_t)RCC_CTRL_HSEEN);
318 
319     /* Wait till HSE is ready and if Time out is reached exit */
320     do
321     {
322         HSEStatus = RCC->CTRL & RCC_CTRL_HSERDF;
323         StartUpCounter++;
324     } while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
325 
326     HSEStatus = ((RCC->CTRL & RCC_CTRL_HSERDF) != RESET);
327     if (!HSEStatus)
328     {
329         /* If HSE fails to start-up, the application will have wrong clock
330          * configuration. User can add here some code to deal with this error */
331         SystemCoreClock = HSI_VALUE;
332         return;
333     }
334 #endif
335 
336     /* Flash wait state
337         0: HCLK <= 32M
338         1: HCLK <= 64M
339         2: HCLK <= 96M
340         3: HCLK <= 128M
341         4: HCLK <= 144M
342      */
343     FLASH->AC &= (uint32_t)((uint32_t)~FLASH_AC_LATENCY);
344     FLASH->AC |= (uint32_t)((SYSCLK_FREQ - 1) / 32000000);
345 
346     /* HCLK = SYSCLK */
347     RCC->CFG |= (uint32_t)RCC_CFG_AHBPRES_DIV1;
348 
349     /* PCLK2 max 72M */
350     if (SYSCLK_FREQ > 72000000)
351     {
352         RCC->CFG |= (uint32_t)RCC_CFG_APB2PRES_DIV2;
353     }
354     else
355     {
356         RCC->CFG |= (uint32_t)RCC_CFG_APB2PRES_DIV1;
357     }
358 
359     /* PCLK1 max 36M */
360     if (SYSCLK_FREQ > 72000000)
361     {
362         RCC->CFG |= (uint32_t)RCC_CFG_APB1PRES_DIV4;
363     }
364     else if (SYSCLK_FREQ > 36000000)
365     {
366         RCC->CFG |= (uint32_t)RCC_CFG_APB1PRES_DIV2;
367     }
368     else
369     {
370         RCC->CFG |= (uint32_t)RCC_CFG_APB1PRES_DIV1;
371     }
372 
373 #if SYSCLK_SRC == SYSCLK_USE_HSE
374     /* Select HSE as system clock source */
375     RCC->CFG &= (uint32_t)((uint32_t) ~(RCC_CFG_SCLKSW));
376     RCC->CFG |= (uint32_t)RCC_CFG_SCLKSW_HSE;
377 
378     /* Wait till HSE is used as system clock source */
379     while ((RCC->CFG & (uint32_t)RCC_CFG_SCLKSTS) != (uint32_t)0x04)
380     {
381     }
382 #elif SYSCLK_SRC == SYSCLK_USE_HSI_PLL || SYSCLK_SRC == SYSCLK_USE_HSE_PLL
383 
384     /* clear bits */
385     RCC->CFG &= (uint32_t)((uint32_t) ~(RCC_CFG_PLLSRC | RCC_CFG_PLLHSEPRES | RCC_CFG_PLLMULFCT));
386 
387     /* set PLL source */
388     rcc_cfgr = RCC->CFG;
389     rcc_cfgr |= (SYSCLK_SRC == SYSCLK_USE_HSI_PLL ? RCC_CFG_PLLSRC_HSI_DIV2 : RCC_CFG_PLLSRC_HSE);
390 
391 #if SYSCLK_SRC == SYSCLK_USE_HSE_PLL
392     rcc_cfgr |= (PLLSRC_DIV == 1 ? RCC_CFG_PLLHSEPRES_HSE : RCC_CFG_PLLHSEPRES_HSE_DIV2);
393 #endif
394 
395     /* set PLL multiply factor */
396 #if PLL_MUL <= 16
397     rcc_cfgr |= (PLL_MUL - 2) << 18;
398 #else
399     rcc_cfgr |= ((PLL_MUL - 17) << 18) | (1 << 27);
400 #endif
401 
402     RCC->CFG = rcc_cfgr;
403 
404     /* Enable PLL */
405     RCC->CTRL |= RCC_CTRL_PLLEN;
406 
407     /* Wait till PLL is ready */
408     while ((RCC->CTRL & RCC_CTRL_PLLRDF) == 0)
409     {
410     }
411 
412     /* Select PLL as system clock source */
413     RCC->CFG &= (uint32_t)((uint32_t) ~(RCC_CFG_SCLKSW));
414     RCC->CFG |= (uint32_t)RCC_CFG_SCLKSW_PLL;
415 
416     /* Wait till PLL is used as system clock source */
417     while ((RCC->CFG & (uint32_t)RCC_CFG_SCLKSTS) != (uint32_t)0x08)
418     {
419     }
420 #endif
421 }
422