]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M0+_LPC51U68_LPCXpresso/device/system_LPC51U68.c
ce025663657a872bf89c0720110e79edfdd9a578
[freertos] / FreeRTOS / Demo / CORTEX_M0+_LPC51U68_LPCXpresso / device / system_LPC51U68.c
1 /*\r
2 ** ###################################################################\r
3 **     Processors:          LPC51U68JBD48\r
4 **                          LPC51U68JBD64\r
5 **\r
6 **     Compilers:           Keil ARM C/C++ Compiler\r
7 **                          GNU C Compiler\r
8 **                          IAR ANSI C/C++ Compiler for ARM\r
9 **                          MCUXpresso Compiler\r
10 **\r
11 **     Reference manual:    LPC51U68 User manual User manual Rev. 1.0 13 Dec 2017\r
12 **     Version:             rev. 1.0, 2017-12-15\r
13 **     Build:               b180802\r
14 **\r
15 **     Abstract:\r
16 **         Provides a system configuration function and a global variable that\r
17 **         contains the system frequency. It configures the device and initializes\r
18 **         the oscillator (PLL) that is part of the microcontroller device.\r
19 **\r
20 **     Copyright 2016 Freescale Semiconductor, Inc.\r
21 **     Copyright 2016-2018 NXP\r
22 **\r
23 **     SPDX-License-Identifier: BSD-3-Clause\r
24 **\r
25 **     http:                 www.nxp.com\r
26 **     mail:                 support@nxp.com\r
27 **\r
28 **     Revisions:\r
29 **     - rev. 1.0 (2017-12-15)\r
30 **         Initial version.\r
31 **\r
32 ** ###################################################################\r
33 */\r
34 \r
35 /*!\r
36  * @file LPC51U68\r
37  * @version 1.0\r
38  * @date 2017-12-15\r
39  * @brief Device specific configuration file for LPC51U68 (implementation file)\r
40  *\r
41  * Provides a system configuration function and a global variable that contains\r
42  * the system frequency. It configures the device and initializes the oscillator\r
43  * (PLL) that is part of the microcontroller device.\r
44  */\r
45 \r
46 #include <stdint.h>\r
47 #include "fsl_device_registers.h"\r
48 \r
49 #define NVALMAX (0x100)\r
50 #define PVALMAX (0x20)\r
51 #define MVALMAX (0x8000)\r
52 #define PLL_SSCG0_MDEC_VAL_P (0)                                 /* MDEC is in bits  16 downto 0 */\r
53 #define PLL_SSCG0_MDEC_VAL_M (0x1FFFFUL << PLL_SSCG0_MDEC_VAL_P) /* NDEC is in bits  9 downto 0 */\r
54 #define PLL_NDEC_VAL_P (0)                                       /* NDEC is in bits  9:0 */\r
55 #define PLL_NDEC_VAL_M (0x3FFUL << PLL_NDEC_VAL_P)\r
56 #define PLL_PDEC_VAL_P (0) /* PDEC is in bits 6:0 */\r
57 #define PLL_PDEC_VAL_M (0x3FFUL << PLL_PDEC_VAL_P)\r
58 \r
59 extern void *__Vectors;\r
60 \r
61 /* ----------------------------------------------------------------------------\r
62    -- Core clock\r
63    ---------------------------------------------------------------------------- */\r
64 \r
65 \r
66 static const uint8_t wdtFreqLookup[32] = {0, 8, 12, 15, 18, 20, 24, 26, 28, 30, 32, 34, 36, 38, 40, 41, 42, 44, 45, 46,\r
67                                             48, 49, 50, 52, 53, 54, 56, 57, 58, 59, 60, 61};\r
68 \r
69 static uint32_t GetWdtOscFreq(void)\r
70 {\r
71     uint8_t freq_sel, div_sel;\r
72     div_sel = ((SYSCON->WDTOSCCTRL & SYSCON_WDTOSCCTRL_DIVSEL_MASK) + 1) << 1;\r
73     freq_sel = wdtFreqLookup[((SYSCON->WDTOSCCTRL & SYSCON_WDTOSCCTRL_FREQSEL_MASK) >> SYSCON_WDTOSCCTRL_FREQSEL_SHIFT)];\r
74     return ((uint32_t) freq_sel * 50000U)/((uint32_t)div_sel);\r
75 }\r
76 \r
77 /* Find decoded N value for raw NDEC value */\r
78 static uint32_t pllDecodeN(uint32_t NDEC)\r
79 {\r
80     uint32_t n, x, i;\r
81 \r
82     /* Find NDec */\r
83     switch (NDEC)\r
84     {\r
85         case 0xFFF:\r
86             n = 0;\r
87             break;\r
88         case 0x302:\r
89             n = 1;\r
90             break;\r
91         case 0x202:\r
92             n = 2;\r
93             break;\r
94         default:\r
95             x = 0x080;\r
96             n = 0xFFFFFFFF;\r
97             for (i = NVALMAX; ((i >= 3) && (n == 0xFFFFFFFF)); i--)\r
98             {\r
99                 x = (((x ^ (x >> 2) ^ (x >> 3) ^ (x >> 4)) & 1) << 7) | ((x >> 1) & 0x7F);\r
100                 if ((x & (PLL_NDEC_VAL_M >> PLL_NDEC_VAL_P)) == NDEC)\r
101                 {\r
102                     /* Decoded value of NDEC */\r
103                     n = i;\r
104                 }\r
105             }\r
106             break;\r
107     }\r
108     return n;\r
109 }\r
110 \r
111 /* Find decoded P value for raw PDEC value */\r
112 static uint32_t pllDecodeP(uint32_t PDEC)\r
113 {\r
114     uint32_t p, x, i;\r
115     /* Find PDec */\r
116     switch (PDEC)\r
117     {\r
118         case 0xFF:\r
119             p = 0;\r
120             break;\r
121         case 0x62:\r
122             p = 1;\r
123             break;\r
124         case 0x42:\r
125             p = 2;\r
126             break;\r
127         default:\r
128             x = 0x10;\r
129             p = 0xFFFFFFFF;\r
130             for (i = PVALMAX; ((i >= 3) && (p == 0xFFFFFFFF)); i--)\r
131             {\r
132                 x = (((x ^ (x >> 2)) & 1) << 4) | ((x >> 1) & 0xF);\r
133                 if ((x & (PLL_PDEC_VAL_M >> PLL_PDEC_VAL_P)) == PDEC)\r
134                 {\r
135                     /* Decoded value of PDEC */\r
136                     p = i;\r
137                 }\r
138             }\r
139             break;\r
140     }\r
141     return p;\r
142 }\r
143 \r
144 /* Find decoded M value for raw MDEC value */\r
145 static uint32_t pllDecodeM(uint32_t MDEC)\r
146 {\r
147     uint32_t m, i, x;\r
148 \r
149     /* Find MDec */\r
150     switch (MDEC)\r
151     {\r
152         case 0xFFFFF:\r
153             m = 0;\r
154             break;\r
155         case 0x18003:\r
156             m = 1;\r
157             break;\r
158         case 0x10003:\r
159             m = 2;\r
160             break;\r
161         default:\r
162             x = 0x04000;\r
163             m = 0xFFFFFFFF;\r
164             for (i = MVALMAX; ((i >= 3) && (m == 0xFFFFFFFF)); i--)\r
165             {\r
166                 x = (((x ^ (x >> 1)) & 1) << 14) | ((x >> 1) & 0x3FFF);\r
167                 if ((x & (PLL_SSCG0_MDEC_VAL_M >> PLL_SSCG0_MDEC_VAL_P)) == MDEC)\r
168                 {\r
169                     /* Decoded value of MDEC */\r
170                     m = i;\r
171                 }\r
172             }\r
173             break;\r
174     }\r
175     return m;\r
176 }\r
177 \r
178 /* Get predivider (N) from PLL NDEC setting */\r
179 static uint32_t findPllPreDiv(uint32_t ctrlReg, uint32_t nDecReg)\r
180 {\r
181     uint32_t preDiv = 1;\r
182 \r
183     /* Direct input is not used? */\r
184     if ((ctrlReg & SYSCON_SYSPLLCTRL_DIRECTI_MASK) == 0)\r
185     {\r
186         /* Decode NDEC value to get (N) pre divider */\r
187         preDiv = pllDecodeN(nDecReg & 0x3FF);\r
188         if (preDiv == 0)\r
189         {\r
190             preDiv = 1;\r
191         }\r
192     }\r
193     /* Adjusted by 1, directi is used to bypass */\r
194     return preDiv;\r
195 }\r
196 \r
197 /* Get postdivider (P) from PLL PDEC setting */\r
198 static uint32_t findPllPostDiv(uint32_t ctrlReg, uint32_t pDecReg)\r
199 {\r
200     uint32_t postDiv = 1;\r
201 \r
202     /* Direct input is not used? */\r
203     if ((ctrlReg & SYSCON_SYSPLLCTRL_DIRECTO_MASK) == 0)\r
204     {\r
205         /* Decode PDEC value to get (P) post divider */\r
206         postDiv = 2 * pllDecodeP(pDecReg & 0x7F);\r
207         if (postDiv == 0)\r
208         {\r
209             postDiv = 2;\r
210         }\r
211     }\r
212     /* Adjusted by 1, directo is used to bypass */\r
213     return postDiv;\r
214 }\r
215 \r
216 /* Get multiplier (M) from PLL MDEC and BYPASS_FBDIV2 settings */\r
217 static uint32_t findPllMMult(uint32_t ctrlReg, uint32_t mDecReg)\r
218 {\r
219     uint32_t mMult = 1;\r
220 \r
221     /* Decode MDEC value to get (M) multiplier */\r
222     mMult = pllDecodeM(mDecReg & 0x1FFFF);\r
223     /* Extra multiply by 2 needed? */\r
224     if ((ctrlReg & SYSCON_SYSPLLCTRL_BYPASSCCODIV2_MASK) == 0)\r
225     {\r
226         mMult = mMult << 1;\r
227     }\r
228     if (mMult == 0)\r
229     {\r
230         mMult = 1;\r
231     }\r
232     return mMult;\r
233 }\r
234 \r
235 \r
236 \r
237 /* ----------------------------------------------------------------------------\r
238    -- Core clock\r
239    ---------------------------------------------------------------------------- */\r
240 \r
241 uint32_t SystemCoreClock = DEFAULT_SYSTEM_CLOCK;\r
242 \r
243 /* ----------------------------------------------------------------------------\r
244    -- SystemInit()\r
245    ---------------------------------------------------------------------------- */\r
246 \r
247 void SystemInit (void) {\r
248 \r
249 #if defined(__CODE_RED)\r
250     extern void(*const g_pfnVectors[]) (void);\r
251     SCB->VTOR = (uint32_t) &g_pfnVectors;\r
252 #else\r
253     extern void *__Vectors;\r
254     SCB->VTOR = (uint32_t) &__Vectors;\r
255 #endif\r
256 \r
257 }\r
258 \r
259 /* ----------------------------------------------------------------------------\r
260    -- SystemCoreClockUpdate()\r
261    ---------------------------------------------------------------------------- */\r
262 \r
263 void SystemCoreClockUpdate (void) {\r
264     uint32_t clkRate = 0;\r
265     uint32_t prediv, postdiv;\r
266     uint64_t workRate;\r
267 \r
268     switch (SYSCON->MAINCLKSELB & SYSCON_MAINCLKSELB_SEL_MASK)\r
269     {\r
270         case 0x00: /* MAINCLKSELA clock (main_clk_a)*/\r
271             switch (SYSCON->MAINCLKSELA & SYSCON_MAINCLKSELA_SEL_MASK)\r
272             {\r
273                 case 0x00: /* FRO 12 MHz (fro_12m) */\r
274                     clkRate = CLK_FRO_12MHZ;\r
275                     break;\r
276                 case 0x01: /* CLKIN (clk_in) */\r
277                     clkRate = CLK_CLK_IN;\r
278                     break;\r
279                 case 0x02: /* Watchdog oscillator (wdt_clk) */\r
280                     clkRate = GetWdtOscFreq();\r
281                     break;\r
282                 default: /* = 0x03 = FRO 96 or 48 MHz (fro_hf) */\r
283                     if (SYSCON->FROCTRL & SYSCON_FROCTRL_SEL_MASK)\r
284                     {\r
285                         clkRate = CLK_FRO_96MHZ;\r
286                     }\r
287                     else\r
288                     {\r
289                         clkRate = CLK_FRO_48MHZ;\r
290                     }\r
291                     break;\r
292             }\r
293             break;\r
294         case 0x02: /* System PLL clock (pll_clk)*/\r
295             switch (SYSCON->SYSPLLCLKSEL & SYSCON_SYSPLLCLKSEL_SEL_MASK)\r
296             {\r
297                 case 0x00: /* FRO 12 MHz (fro_12m) */\r
298                     clkRate = CLK_FRO_12MHZ;\r
299                     break;\r
300                 case 0x01: /* CLKIN (clk_in) */\r
301                     clkRate = CLK_CLK_IN;\r
302                     break;\r
303                 case 0x02: /* Watchdog oscillator (wdt_clk) */\r
304                     clkRate = GetWdtOscFreq();\r
305                     break;\r
306                 case 0x03: /* RTC oscillator 32 kHz output (32k_clk) */\r
307                     clkRate = CLK_RTC_32K_CLK;\r
308                     break;\r
309                 default:\r
310                     break;\r
311             }\r
312             if ((SYSCON->SYSPLLCTRL & SYSCON_SYSPLLCTRL_BYPASS_MASK) == 0)\r
313             {\r
314                 /* PLL is not in bypass mode, get pre-divider, post-divider, and M divider */\r
315                 prediv = findPllPreDiv(SYSCON->SYSPLLCTRL, SYSCON->SYSPLLNDEC);\r
316                 postdiv = findPllPostDiv(SYSCON->SYSPLLCTRL, SYSCON->SYSPLLPDEC);\r
317                 /* Adjust input clock */\r
318                 clkRate = clkRate / prediv;\r
319                 /* If using the SS, use the multiplier */\r
320                 if (SYSCON->SYSPLLSSCTRL1 & SYSCON_SYSPLLSSCTRL1_PD_MASK)\r
321                 {\r
322                     /* MDEC used for rate */\r
323                     workRate = (uint64_t)clkRate * (uint64_t)findPllMMult(SYSCON->SYSPLLCTRL, SYSCON->SYSPLLSSCTRL0);\r
324                 }\r
325                 else\r
326                 {\r
327                     /* SS multipler used for rate */\r
328                     workRate = 0;\r
329                     /* Adjust by fractional */\r
330                     workRate = workRate + ((clkRate * (uint64_t)((SYSCON->SYSPLLSSCTRL1 & 0x7FF) >> 0)) / 0x800);\r
331                 }\r
332                 clkRate = workRate / ((uint64_t)postdiv);\r
333             }\r
334             break;\r
335         case 0x03: /* RTC oscillator 32 kHz output (32k_clk) */\r
336             clkRate = CLK_RTC_32K_CLK;\r
337             break;\r
338         default:\r
339             break;\r
340     }\r
341     SystemCoreClock = clkRate / ((SYSCON->AHBCLKDIV & 0xFF) + 1);\r
342 \r
343 }\r