/** * @file * * @ingroup lpc24xx * * @brief System clocks. */ /* * Copyright (c) 2008 * Embedded Brains GmbH * Obere Lagerstr. 30 * D-82178 Puchheim * Germany * rtems@embedded-brains.de * * The license and distribution terms for this file may be found in the file * LICENSE in this distribution or at http://www.rtems.com/license/LICENSE. */ #include #include #include #include /** * @brief Internal RC oscillator frequency in [Hz]. */ #define LPC24XX_OSCILLATOR_INTERNAL 4000000U #if !defined(LPC24XX_OSCILLATOR_MAIN) #error unknown main oscillator frequency #endif #if !defined(LPC24XX_OSCILLATOR_RTC) #error unknown rtc oscillator frequency #endif /** * @brief Returns the CPU clock frequency in [Hz]. */ unsigned lpc24xx_cclk( void) { unsigned clksrc = GET_CLKSRCSEL_CLKSRC( CLKSRCSEL); unsigned pllinclk = 0; unsigned pllclk = 0; unsigned cclk = 0; /* Get PLL input frequency */ switch (clksrc) { case 0: pllinclk = LPC24XX_OSCILLATOR_INTERNAL; break; case 1: pllinclk = LPC24XX_OSCILLATOR_MAIN; break; case 2: pllinclk = LPC24XX_OSCILLATOR_RTC; break; default: while (1) { /* Spin forever */ } return 0; } /* Get PLL output frequency */ if (IS_FLAG_SET( PLLSTAT, PLLSTAT_PLLC)) { uint32_t pllcfg = PLLCFG; unsigned n = GET_PLLCFG_NSEL( pllcfg) + 1; unsigned m = GET_PLLCFG_MSEL( pllcfg) + 1; pllclk = (pllinclk / n) * 2 * m; } else { pllclk = pllinclk; } /* Get CPU clock frequency */ cclk = pllclk / (GET_CCLKCFG_CCLKSEL( CCLKCFG) + 1); return cclk; } static void lpc24xx_pll_config( uint32_t val) { PLLCON = val; PLLFEED = 0xaa; PLLFEED = 0x55; } /** * @brief Sets the Phase Locked Loop (PLL). * * @param clksrc Selects the clock source for the PLL. * * @param nsel Selects PLL pre-divider value (sometimes named psel). * * @param msel Selects PLL multiplier value. * * @param cclksel Selects the divide value for creating the CPU clock (CCLK) * from the PLL output. * * @note All parameter values are the actual register field values. */ void lpc24xx_set_pll( unsigned clksrc, unsigned nsel, unsigned msel, unsigned cclksel) { bool pll_enabled = IS_FLAG_SET( PLLSTAT, PLLSTAT_PLLE); /* Disconnect PLL if necessary */ if (IS_FLAG_SET( PLLSTAT, PLLSTAT_PLLC)) { if (pll_enabled) { lpc24xx_pll_config( PLLCON_PLLE); } else { lpc24xx_pll_config( 0); } } /* Set CPU clock divider to a reasonable save value */ CCLKCFG = SET_CCLKCFG_CCLKSEL( 0, 1); /* Disable PLL if necessary */ if (pll_enabled) { lpc24xx_pll_config( 0); } /* Select clock source */ CLKSRCSEL = SET_CLKSRCSEL_CLKSRC( 0, clksrc); /* Set PLL Configuration Register */ PLLCFG = SET_PLLCFG_NSEL( 0, nsel) | SET_PLLCFG_MSEL( 0, msel); /* Enable PLL */ lpc24xx_pll_config( PLLCON_PLLE); /* Wait for lock */ while (IS_FLAG_CLEARED( PLLSTAT, PLLSTAT_PLOCK)) { /* Wait */ } /* Set CPU clock divider and ensure that we have an odd value */ CCLKCFG = SET_CCLKCFG_CCLKSEL( 0, cclksel | 1); /* Connect PLL */ lpc24xx_pll_config( PLLCON_PLLE | PLLCON_PLLC); }