LPCOpen Platform  v1.03
LPCOpen Platform for NXP LPC Microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
clock_17xx_40xx.c
Go to the documentation of this file.
1 /*
2  * @brief LPC17xx/40xx System and Control driver
3  *
4  * @note
5  * Copyright(C) NXP Semiconductors, 2012
6  * All rights reserved.
7  *
8  * @par
9  * Software that is described herein is for illustrative purposes only
10  * which provides customers with programming information regarding the
11  * LPC products. This software is supplied "AS IS" without any warranties of
12  * any kind, and NXP Semiconductors and its licensor disclaim any and
13  * all warranties, express or implied, including all implied warranties of
14  * merchantability, fitness for a particular purpose and non-infringement of
15  * intellectual property rights. NXP Semiconductors assumes no responsibility
16  * or liability for the use of the software, conveys no license or rights under any
17  * patent, copyright, mask work right, or any other intellectual property rights in
18  * or to any products. NXP Semiconductors reserves the right to make changes
19  * in the software without notification. NXP Semiconductors also makes no
20  * representation or warranty that such application will be suitable for the
21  * specified use without further testing or modification.
22  *
23  * @par
24  * Permission to use, copy, modify, and distribute this software and its
25  * documentation is hereby granted, under NXP Semiconductors' and its
26  * licensor's relevant copyrights in the software, without fee, provided that it
27  * is used in conjunction with NXP Semiconductors microcontrollers. This
28  * copyright, permission, and disclaimer notice must appear in all copies of
29  * this code.
30  */
31 
32 #include "chip.h"
33 
34 /*****************************************************************************
35  * Private types/enumerations/variables
36  ****************************************************************************/
37 
38 /*****************************************************************************
39  * Public types/enumerations/variables
40  ****************************************************************************/
41 
42 /*****************************************************************************
43  * Private functions
44  ****************************************************************************/
45 
46 /*****************************************************************************
47  * Public functions
48  ****************************************************************************/
49 
50 /* Enables or connects a PLL */
52  uint32_t temp;
53 
54  temp = LPC_SYSCTL->PLL[pllNum].PLLCON;
55  temp |= flags;
56  LPC_SYSCTL->PLL[pllNum].PLLCON = temp;
57  Chip_Clock_FeedPLL(pllNum);
58 }
59 
60 /* Disables or disconnects a PLL */
62  uint32_t temp;
63 
64  temp = LPC_SYSCTL->PLL[pllNum].PLLCON;
65  temp &= ~flags;
66  LPC_SYSCTL->PLL[pllNum].PLLCON = temp;
67  Chip_Clock_FeedPLL(pllNum);
68 }
69 
70 /* Sets up a PLL */
72  uint32_t pllcfg;
73 
74 #if defined(CHIP_LPC175X_6X)
75  /* PLL0 and PLL1 are slightly different */
76  if (pllNum == SYSCTL_MAIN_PLL) {
77  pllcfg = (msel) | (psel << 16);
78  }
79  else {
80  pllcfg = (msel) | (psel << 5);
81  }
82 
83 #else
84  pllcfg = (msel) | (psel << 5);
85 #endif
86 
87  LPC_SYSCTL->PLL[pllNum].PLLCFG = pllcfg;
88  Chip_Clock_FeedPLL(pllNum);
89 }
90 
91 /* Enables power and clocking for a peripheral */
93  uint32_t bs = (uint32_t) clk;
94 
95 #if defined(CHIP_LPC407X_8X)
96  if (bs >= 32) {
97  LPC_SYSCTL->PCONP1 |= (1 << (bs - 32));
98  }
99  else {
100  LPC_SYSCTL->PCONP |= (1 << bs);
101  }
102 #else
103  LPC_SYSCTL->PCONP |= (1 << bs);
104 #endif
105 }
106 
107 /* Disables power and clocking for a peripheral */
109  uint32_t bs = (uint32_t) clk;
110 
111 #if defined(CHIP_LPC407X_8X)
112  if (bs >= 32) {
113  LPC_SYSCTL->PCONP1 &= ~(1 << (bs - 32));
114  }
115  else {
116  LPC_SYSCTL->PCONP |= ~(1 << bs);
117  }
118 #else
119  LPC_SYSCTL->PCONP |= ~(1 << bs);
120 #endif
121 }
122 
123 /* Returns power enables state for a peripheral */
125 {
126  uint32_t bs = (uint32_t) clk;
127 
128 #if defined(CHIP_LPC407X_8X)
129  if (bs >= 32) {
130  bs = LPC_SYSCTL->PCONP1 & (1 << (bs - 32));
131  }
132  else {
133  bs = LPC_SYSCTL->PCONP & (1 << bs);
134  }
135 #else
136  bs = LPC_SYSCTL->PCONP & (1 << bs);
137 #endif
138 
139  return (bool) (bs != 0);
140 }
141 
142 /* Sets the current CPU clock source */
144 {
145 #if defined(CHIP_LPC175X_6X)
146  /* LPC175x/6x CPU clock source is based on PLL connect status */
147  if (src == SYSCTL_CCLKSRC_MAINPLL) {
148  /* Connect PLL0 */
149  Chip_Clock_EnablePLL(SYSCTL_MAIN_PLL, SYSCTL_PLL_CONNECT);
150  }
151  else {
152  Chip_Clock_DisablePLL(SYSCTL_MAIN_PLL, SYSCTL_PLL_CONNECT);
153  }
154 #else
155  /* LPC177x/8x and 407x/8x CPU clock source is based on CCLKSEL */
156  if (src == SYSCTL_CCLKSRC_MAINPLL) {
157  /* Connect PLL0 */
158  LPC_SYSCTL->CCLKSEL |= (1 << 8);
159  }
160  else {
161  LPC_SYSCTL->CCLKSEL &= ~(1 << 8);
162  }
163 #endif
164 }
165 
166 /* Returns the current CPU clock source */
168 {
170 #if defined(CHIP_LPC175X_6X)
171  /* LPC175x/6x CPU clock source is based on PLL connect status */
172  if (Chip_Clock_IsMainPLLConnected()) {
174  }
175  else {
176  src = SYSCTL_CCLKSRC_SYSCLK;
177  }
178 #else
179  /* LPC177x/8x and 407x/8x CPU clock source is based on CCLKSEL */
180  if (LPC_SYSCTL->CCLKSEL & (1 << 8)) {
182  }
183  else {
184  src = SYSCTL_CCLKSRC_SYSCLK;
185  }
186 #endif
187 
188  return src;
189 }
190 
191 /* Selects the CPU clock divider */
193 {
194 #if defined(CHIP_LPC175X_6X)
195  LPC_SYSCTL->CCLKSEL = div;
196 #else
197  uint32_t temp;
198 
199  /* Save state of CPU clock source bit */
200  temp = LPC_SYSCTL->CCLKSEL & (1 << 8);
201  LPC_SYSCTL->CCLKSEL = temp | div;
202 #endif
203 }
204 
205 /* Gets the CPU clock divider */
207 {
208 #if defined(CHIP_LPC175X_6X)
209  return (LPC_SYSCTL->CCLKSEL & 0xFF) + 1;
210 #else
211  return LPC_SYSCTL->CCLKSEL & 0x1F;
212 #endif
213 }
214 
215 #if !defined(CHIP_LPC175X_6X)
216 /* Selects the USB clock divider source */
218 {
219  uint32_t temp;
220 
221  /* Mask out current source, but keep divider */
222  temp = LPC_SYSCTL->USBCLKSEL & ~(0x3 << 8);
223  LPC_SYSCTL->USBCLKSEL = temp | (((uint32_t) src) << 8);
224 }
225 
226 #endif
227 
228 /* Sets the USB clock divider */
230 {
231  uint32_t temp;
232 
233  /* Mask out current divider */
234 #if defined(CHIP_LPC175X_6X)
235  temp = LPC_SYSCTL->USBCLKSEL & ~(0xF);
236 #else
237  temp = LPC_SYSCTL->USBCLKSEL & ~(0x1F);
238 #endif
239  LPC_SYSCTL->USBCLKSEL = temp | div;
240 }
241 
242 /* Gets the USB clock divider */
244 {
245 #if defined(CHIP_LPC175X_6X)
246  return (LPC_SYSCTL->USBCLKSEL & 0xF) + 1;
247 #else
248  return (LPC_SYSCTL->USBCLKSEL & 0x1F) + 1;
249 #endif
250 }
251 
252 #if defined(CHIP_LPC175X_6X)
253 /* Selects a clock divider for a peripheral */
254 void Chip_Clock_SetPCLKDiv(CHIP_SYSCTL_PCLK_T clk, CHIP_SYSCTL_CLKDIV_T div)
255 {
256  uint32_t temp, bitIndex, regIndex = (uint32_t) clk;
257 
258  /* Get register array index and clock index into the register */
259  bitIndex = ((regIndex % 16) * 2);
260  regIndex = regIndex / 16;
261 
262  /* Mask and update register */
263  temp = LPC_SYSCTL->PCLKSEL[regIndex] & ~(0x3 << bitIndex);
264  temp |= (((uint32_t) div) << bitIndex);
265  LPC_SYSCTL->PCLKSEL[regIndex] = temp;
266 }
267 
268 /* Gets a clock divider for a peripheral */
269 uint32_t Chip_Clock_GetPLCKDiv(CHIP_SYSCTL_PCLK_T clk)
270 {
271  uint32_t div = 1, bitIndex, regIndex = ((uint32_t) clk) * 2;
272 
273  /* Get register array index and clock index into the register */
274  bitIndex = regIndex % 32;
275  regIndex = regIndex / 32;
276 
277  /* Mask and update register */
278  div = LPC_SYSCTL->PCLKSEL[regIndex];
279  div = (div >> bitIndex) & 0x3;
280  if (div == SYSCTL_CLKDIV_4) {
281  div = 4;
282  }
283  else if (div == SYSCTL_CLKDIV_1) {
284  div = 1;
285  }
286  else if (div == SYSCTL_CLKDIV_2) {
287  div = 2;
288  }
289  else {
290  /* Special case for CAN clock divider */
291  if ((clk == SYSCTL_PCLK_CAN1) || (clk == SYSCTL_PCLK_CAN2) || (clk == SYSCTL_PCLK_ACF)) {
292  div = 6;
293  }
294  else {
295  div = 8;
296  }
297  }
298 
299  return div;
300 }
301 
302 #endif
303 
304 /* Selects a source clock and divider rate for the CLKOUT pin */
306  uint32_t div)
307 {
308  uint32_t temp;
309 
310  temp = LPC_SYSCTL->CLKOUTCFG & ~0x1FF;
311  temp |= ((uint32_t) src) | (div - 1);
312  LPC_SYSCTL->CLKOUTCFG = temp;
313 }
314 
315 /* Returns the current SYSCLK clock rate */
317 {
318  /* Determine clock input rate to SYSCLK based on input selection */
319  switch (Chip_Clock_GetMainPllSource()) {
321  return Chip_Clock_GetIntOscRate();
322 
324  return Chip_Clock_GetMainOscRate();
325 
326 #if defined(CHIP_LPC175X_6X)
327  case (uint32_t) SYSCTL_PLLCLKSRC_RTC:
328  return Chip_Clock_GetRTCOscRate();
329 #endif
330  }
331  return 0;
332 }
333 
334 /* Returns the main pll output clock rate */
336 {
337  uint32_t clkhr = 0;
338 
339 #if defined(CHIP_LPC175X_6X)
340  /* Only valid if enabled */
342  uint32_t msel, nsel;
343 
344  /* PLL0 rate is (FIN * 2 * MSEL) / NSEL, get MSEL and NSEL */
345  msel = 1 + (LPC_SYSCTL->PLL[SYSCTL_MAIN_PLL].PLLCFG & 0x7FFF);
346  nsel = 1 + ((LPC_SYSCTL->PLL[SYSCTL_MAIN_PLL].PLLCFG >> 16) & 0xFF);
347  clkhr = (Chip_Clock_GetMainPllInClockRate() * 2 * msel) / nsel;
348  }
349 #else
351  uint32_t msel;
352 
353  /* PLL0 rate is (FIN * MSEL) */
354  msel = 1 + (LPC_SYSCTL->PLL[SYSCTL_MAIN_PLL].PLLCFG & 0x1F);
355  clkhr = (Chip_Clock_GetMainPllInClockRate() * msel);
356  }
357 #endif
358 
359  return (uint32_t) clkhr;
360 
361 }
362 
363 /* Get USB output clock rate */
365 {
366  uint32_t clkhr = 0;
367 
368  /* Only valid if enabled */
370  uint32_t msel;
371 
372  /* PLL1 input clock (FIN) is always main oscillator */
373  /* PLL1 rate is (FIN * MSEL) */
374  msel = 1 + (LPC_SYSCTL->PLL[SYSCTL_USB_PLL].PLLCFG & 0x1F);
375  clkhr = (Chip_Clock_GetUSBPllInClockRate() * msel);
376  }
377 
378  return (uint32_t) clkhr;
379 
380 }
381 
382 /* Get the main clock rate */
383 /* On 175x/6x devices, this is the input clock to the CPU divider.
384  Additionally, on 177x/8x and 407x/8x devices, this is also the
385  input clock to the peripheral divider. */
387 {
388  switch (Chip_Clock_GetCPUClockSource()) {
391 
393  return Chip_Clock_GetSYSCLKRate();
394 
395  default:
396  return 0;
397  }
398 }
399 
400 /* Get CCLK rate */
402 {
404 }
405 
406 /* Returns the USB clock (USB_CLK) rate */
408 {
409  uint32_t div, clkrate;
410 #if defined(CHIP_LPC175X_6X)
411  /* The USB clock rate is derived from PLL1 or PLL0 */
412  if (Chip_Clock_IsUSBPLLConnected()) {
413  /* Use PLL1 clock for USB source with divider of 1 */
415  div = 1;
416  }
417  else {
418  clkrate = Chip_Clock_GetMainClockRate();
420  }
421 
422 #else
423  /* Get clock from source drving USB */
424  switch (Chip_Clock_GetUSBClockSource()) {
426  default:
427  clkrate = Chip_Clock_GetSYSCLKRate();
428  break;
429 
432  break;
433 
436  break;
437  }
438 
440 #endif
441 
442  return clkrate / div;
443 }
444 
445 #if !defined(CHIP_LPC175X_6X)
446 /* Selects the SPIFI clock divider source */
448 {
449  uint32_t temp;
450 
451  /* Mask out current source, but keep divider */
452  temp = LPC_SYSCTL->SPIFICLKSEL & ~(0x3 << 8);
453  LPC_SYSCTL->SPIFICLKSEL = temp | (((uint32_t) src) << 8);
454 }
455 
456 /* Sets the SPIFI clock divider */
458 {
459  uint32_t temp;
460 
461  /* Mask out current divider */
462  temp = LPC_SYSCTL->SPIFICLKSEL & ~(0x1F);
463  LPC_SYSCTL->SPIFICLKSEL = temp | div;
464 }
465 
466 /* Returns the SPIFI clock rate */
468 {
469  uint32_t div, clkrate;
470 
471  /* Get clock from source drving USB */
472  switch (Chip_Clock_GetSPIFIClockSource()) {
474  default:
475  clkrate = Chip_Clock_GetSYSCLKRate();
476  break;
477 
480  break;
481 
484  break;
485  }
486 
488 
489  return clkrate / div;
490 }
491 
492 #endif
493 
494 #if defined(CHIP_LPC175X_6X)
495 /* Returns the clock rate for a peripheral */
496 uint32_t Chip_Clock_GetPeripheralClockRate(CHIP_SYSCTL_PCLK_T clk) {
497  /* 175x/6x clock is derived from CPU clock with CPU divider */
498  return Chip_Clock_GetSystemClockRate() / Chip_Clock_GetPLCKDiv(clk);
499 }
500 
501 #else
502 /* Returns the clock rate for all peripherals */
504 {
505  uint32_t clkrate = 0, div;
506 
507  /* Get divider, a divider of 0 means the clock is disabled */
508  div = Chip_Clock_GetPCLKDiv();
509  if(div != 0) {
510  /* Derived from periperhal clock input and peripheral clock divider */
511  clkrate = Chip_Clock_GetMainClockRate() / div;
512  }
513 
514  return clkrate;
515 }
516 
517 #endif