system_LPC54608.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /*
  2. ** ###################################################################
  3. ** Processors: LPC54608J512BD208
  4. ** LPC54608J512ET180
  5. **
  6. ** Compilers: Keil ARM C/C++ Compiler
  7. ** GNU C Compiler
  8. ** IAR ANSI C/C++ Compiler for ARM
  9. ** MCUXpresso Compiler
  10. **
  11. ** Reference manual: LPC54S60x/LPC5460x User manual Rev.0.9 7 Nov 2016
  12. ** Version: rev. 1.1, 2016-11-25
  13. ** Build: b170214
  14. **
  15. ** Abstract:
  16. ** Provides a system configuration function and a global variable that
  17. ** contains the system frequency. It configures the device and initializes
  18. ** the oscillator (PLL) that is part of the microcontroller device.
  19. **
  20. ** Copyright 2016 Freescale Semiconductor, Inc.
  21. ** Copyright 2016-2017 NXP
  22. ** Redistribution and use in source and binary forms, with or without modification,
  23. ** are permitted provided that the following conditions are met:
  24. **
  25. ** o Redistributions of source code must retain the above copyright notice, this list
  26. ** of conditions and the following disclaimer.
  27. **
  28. ** o Redistributions in binary form must reproduce the above copyright notice, this
  29. ** list of conditions and the following disclaimer in the documentation and/or
  30. ** other materials provided with the distribution.
  31. **
  32. ** o Neither the name of the copyright holder nor the names of its
  33. ** contributors may be used to endorse or promote products derived from this
  34. ** software without specific prior written permission.
  35. **
  36. ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  37. ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  38. ** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. ** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  40. ** ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  41. ** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  42. ** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  43. ** ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  44. ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  45. ** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  46. **
  47. ** http: www.nxp.com
  48. ** mail: support@nxp.com
  49. **
  50. ** Revisions:
  51. ** - rev. 1.0 (2016-08-12)
  52. ** Initial version.
  53. ** - rev. 1.1 (2016-11-25)
  54. ** Update CANFD and Classic CAN register.
  55. ** Add MAC TIMERSTAMP registers.
  56. **
  57. ** ###################################################################
  58. */
  59. /*!
  60. * @file LPC54608
  61. * @version 1.1
  62. * @date 2016-11-25
  63. * @brief Device specific configuration file for LPC54608 (implementation file)
  64. *
  65. * Provides a system configuration function and a global variable that contains
  66. * the system frequency. It configures the device and initializes the oscillator
  67. * (PLL) that is part of the microcontroller device.
  68. */
  69. #include <stdint.h>
  70. #include "fsl_device_registers.h"
  71. #define NVALMAX (0x100)
  72. #define PVALMAX (0x20)
  73. #define MVALMAX (0x8000)
  74. #define PLL_MDEC_VAL_P (0) /* MDEC is in bits 16:0 */
  75. #define PLL_MDEC_VAL_M (0x1FFFFUL << PLL_MDEC_VAL_P)
  76. #define PLL_NDEC_VAL_P (0) /* NDEC is in bits 9:0 */
  77. #define PLL_NDEC_VAL_M (0x3FFUL << PLL_NDEC_VAL_P)
  78. #define PLL_PDEC_VAL_P (0) /* PDEC is in bits 6:0 */
  79. #define PLL_PDEC_VAL_M (0x7FUL << PLL_PDEC_VAL_P)
  80. extern void *__Vectors;
  81. 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,
  82. 48, 49, 50, 52, 53, 54, 56, 57, 58, 59, 60, 61};
  83. /* Get WATCH DOG Clk */
  84. static uint32_t getWdtOscFreq(void)
  85. {
  86. uint8_t freq_sel, div_sel;
  87. if (SYSCON->PDRUNCFG[0] & SYSCON_PDRUNCFG_PDEN_WDT_OSC_MASK)
  88. {
  89. return 0U;
  90. }
  91. else
  92. {
  93. div_sel = ((SYSCON->WDTOSCCTRL & 0x1f) + 1) << 1;
  94. freq_sel = wdtFreqLookup[((SYSCON->WDTOSCCTRL & SYSCON_WDTOSCCTRL_FREQSEL_MASK) >> SYSCON_WDTOSCCTRL_FREQSEL_SHIFT)];
  95. return ((uint32_t) freq_sel * 50000U)/((uint32_t)div_sel);
  96. }
  97. }
  98. /* Find decoded N value for raw NDEC value */
  99. static uint32_t pllDecodeN(uint32_t NDEC)
  100. {
  101. uint32_t n, x, i;
  102. /* Find NDec */
  103. switch (NDEC)
  104. {
  105. case 0x3FF:
  106. n = 0;
  107. break;
  108. case 0x302:
  109. n = 1;
  110. break;
  111. case 0x202:
  112. n = 2;
  113. break;
  114. default:
  115. x = 0x080;
  116. n = 0xFFFFFFFFU;
  117. for (i = NVALMAX; ((i >= 3) && (n == 0xFFFFFFFFU)); i--)
  118. {
  119. x = (((x ^ (x >> 2) ^ (x >> 3) ^ (x >> 4)) & 1) << 7) | ((x >> 1) & 0x7F);
  120. if ((x & (PLL_NDEC_VAL_M >> PLL_NDEC_VAL_P)) == NDEC)
  121. {
  122. /* Decoded value of NDEC */
  123. n = i;
  124. }
  125. }
  126. break;
  127. }
  128. return n;
  129. }
  130. /* Find decoded P value for raw PDEC value */
  131. static uint32_t pllDecodeP(uint32_t PDEC)
  132. {
  133. uint32_t p, x, i;
  134. /* Find PDec */
  135. switch (PDEC)
  136. {
  137. case 0x7F:
  138. p = 0;
  139. break;
  140. case 0x62:
  141. p = 1;
  142. break;
  143. case 0x42:
  144. p = 2;
  145. break;
  146. default:
  147. x = 0x10;
  148. p = 0xFFFFFFFFU;
  149. for (i = PVALMAX; ((i >= 3) && (p == 0xFFFFFFFFU)); i--)
  150. {
  151. x = (((x ^ (x >> 2)) & 1) << 4) | ((x >> 1) & 0xFU);
  152. if ((x & (PLL_PDEC_VAL_M >> PLL_PDEC_VAL_P)) == PDEC)
  153. {
  154. /* Decoded value of PDEC */
  155. p = i;
  156. }
  157. }
  158. break;
  159. }
  160. return p;
  161. }
  162. /* Find decoded M value for raw MDEC value */
  163. static uint32_t pllDecodeM(uint32_t MDEC)
  164. {
  165. uint32_t m, i, x;
  166. /* Find MDec */
  167. switch (MDEC)
  168. {
  169. case 0x1FFFF:
  170. m = 0;
  171. break;
  172. case 0x18003:
  173. m = 1;
  174. break;
  175. case 0x10003:
  176. m = 2;
  177. break;
  178. default:
  179. x = 0x04000;
  180. m = 0xFFFFFFFFU;
  181. for (i = MVALMAX; ((i >= 3) && (m == 0xFFFFFFFFU)); i--)
  182. {
  183. x = (((x ^ (x >> 1)) & 1) << 14) | ((x >> 1) & 0x3FFFU);
  184. if ((x & (PLL_MDEC_VAL_M >> PLL_MDEC_VAL_P)) == MDEC)
  185. {
  186. /* Decoded value of MDEC */
  187. m = i;
  188. }
  189. }
  190. break;
  191. }
  192. return m;
  193. }
  194. /* Get predivider (N) from PLL NDEC setting */
  195. static uint32_t findPllPreDiv(uint32_t ctrlReg, uint32_t nDecReg)
  196. {
  197. uint32_t preDiv = 1;
  198. /* Direct input is not used? */
  199. if ((ctrlReg & SYSCON_SYSPLLCTRL_DIRECTI_MASK) == 0)
  200. {
  201. /* Decode NDEC value to get (N) pre divider */
  202. preDiv = pllDecodeN(nDecReg & 0x3FF);
  203. if (preDiv == 0)
  204. {
  205. preDiv = 1;
  206. }
  207. }
  208. /* Adjusted by 1, directi is used to bypass */
  209. return preDiv;
  210. }
  211. /* Get postdivider (P) from PLL PDEC setting */
  212. static uint32_t findPllPostDiv(uint32_t ctrlReg, uint32_t pDecReg)
  213. {
  214. uint32_t postDiv = 1;
  215. /* Direct input is not used? */
  216. if ((ctrlReg & SYSCON_SYSPLLCTRL_DIRECTO_MASK) == 0)
  217. {
  218. /* Decode PDEC value to get (P) post divider */
  219. postDiv = 2 * pllDecodeP(pDecReg & 0x7F);
  220. if (postDiv == 0)
  221. {
  222. postDiv = 2;
  223. }
  224. }
  225. /* Adjusted by 1, directo is used to bypass */
  226. return postDiv;
  227. }
  228. /* Get multiplier (M) from PLL MDEC and BYPASS_FBDIV2 settings */
  229. static uint32_t findPllMMult(uint32_t ctrlReg, uint32_t mDecReg)
  230. {
  231. uint32_t mMult = 1;
  232. /* Decode MDEC value to get (M) multiplier */
  233. mMult = pllDecodeM(mDecReg & 0x1FFFF);
  234. if (mMult == 0)
  235. {
  236. mMult = 1;
  237. }
  238. return mMult;
  239. }
  240. /* ----------------------------------------------------------------------------
  241. -- Core clock
  242. ---------------------------------------------------------------------------- */
  243. uint32_t SystemCoreClock = DEFAULT_SYSTEM_CLOCK;
  244. /* ----------------------------------------------------------------------------
  245. -- SystemInit()
  246. ---------------------------------------------------------------------------- */
  247. void SystemInit (void) {
  248. #if ((__FPU_PRESENT == 1) && (__FPU_USED == 1))
  249. SCB->CPACR |= ((3UL << 10*2) | (3UL << 11*2)); /* set CP10, CP11 Full Access */
  250. #endif /* ((__FPU_PRESENT == 1) && (__FPU_USED == 1)) */
  251. #if defined(__MCUXPRESSO)
  252. extern void(*const g_pfnVectors[]) (void);
  253. SCB->VTOR = (uint32_t) &g_pfnVectors;
  254. #else
  255. extern void *__Vectors;
  256. SCB->VTOR = (uint32_t) &__Vectors;
  257. #endif
  258. SYSCON->ARMTRACECLKDIV = 0;
  259. /* Optionally enable RAM banks that may be off by default at reset */
  260. #if !defined(DONT_ENABLE_DISABLED_RAMBANKS)
  261. SYSCON->AHBCLKCTRLSET[0] = SYSCON_AHBCLKCTRL_SRAM1_MASK | SYSCON_AHBCLKCTRL_SRAM2_MASK | SYSCON_AHBCLKCTRL_SRAM3_MASK;
  262. #endif
  263. }
  264. /* ----------------------------------------------------------------------------
  265. -- SystemCoreClockUpdate()
  266. ---------------------------------------------------------------------------- */
  267. void SystemCoreClockUpdate (void) {
  268. uint32_t clkRate = 0;
  269. uint32_t prediv, postdiv;
  270. uint64_t workRate;
  271. switch (SYSCON->MAINCLKSELB & SYSCON_MAINCLKSELB_SEL_MASK)
  272. {
  273. case 0x00: /* MAINCLKSELA clock (main_clk_a)*/
  274. switch (SYSCON->MAINCLKSELA & SYSCON_MAINCLKSELA_SEL_MASK)
  275. {
  276. case 0x00: /* FRO 12 MHz (fro_12m) */
  277. clkRate = CLK_FRO_12MHZ;
  278. break;
  279. case 0x01: /* CLKIN (clk_in) */
  280. clkRate = CLK_CLK_IN;
  281. break;
  282. case 0x02: /* Watchdog oscillator (wdt_clk) */
  283. clkRate = getWdtOscFreq();
  284. break;
  285. default: /* = 0x03 = FRO 96 or 48 MHz (fro_hf) */
  286. if (SYSCON->FROCTRL & SYSCON_FROCTRL_SEL_MASK)
  287. {
  288. clkRate = CLK_FRO_96MHZ;
  289. }
  290. else
  291. {
  292. clkRate = CLK_FRO_48MHZ;
  293. }
  294. break;
  295. }
  296. break;
  297. case 0x02: /* System PLL clock (pll_clk)*/
  298. switch (SYSCON->SYSPLLCLKSEL & SYSCON_SYSPLLCLKSEL_SEL_MASK)
  299. {
  300. case 0x00: /* FRO 12 MHz (fro_12m) */
  301. clkRate = CLK_FRO_12MHZ;
  302. break;
  303. case 0x01: /* CLKIN (clk_in) */
  304. clkRate = CLK_CLK_IN;
  305. break;
  306. case 0x02: /* Watchdog oscillator (wdt_clk) */
  307. clkRate = getWdtOscFreq();
  308. break;
  309. case 0x03: /* RTC oscillator 32 kHz output (32k_clk) */
  310. clkRate = CLK_RTC_32K_CLK;
  311. break;
  312. default:
  313. break;
  314. }
  315. if ((SYSCON->SYSPLLCTRL & SYSCON_SYSPLLCTRL_BYPASS_MASK) == 0)
  316. {
  317. /* PLL is not in bypass mode, get pre-divider, post-divider, and M divider */
  318. prediv = findPllPreDiv(SYSCON->SYSPLLCTRL, SYSCON->SYSPLLNDEC);
  319. postdiv = findPllPostDiv(SYSCON->SYSPLLCTRL, SYSCON->SYSPLLPDEC);
  320. /* Adjust input clock */
  321. clkRate = clkRate / prediv;
  322. /* MDEC used for rate */
  323. workRate = (uint64_t)clkRate * (uint64_t)findPllMMult(SYSCON->SYSPLLCTRL, SYSCON->SYSPLLMDEC);
  324. clkRate = workRate / ((uint64_t)postdiv);
  325. clkRate = workRate * 2; /* PLL CCO output is divided by 2 before to M-Divider */
  326. }
  327. break;
  328. case 0x03: /* RTC oscillator 32 kHz output (32k_clk) */
  329. clkRate = CLK_RTC_32K_CLK;
  330. break;
  331. default:
  332. break;
  333. }
  334. SystemCoreClock = clkRate / ((SYSCON->AHBCLKDIV & 0xFF) + 1);
  335. }