summaryrefslogblamecommitdiffstats
path: root/c/src/lib/libbsp/arm/lpc24xx/misc/system-clocks.c
blob: 6de7dd7d8d42ad51973dd0fda267d073fb777d3a (plain) (tree)



















                                                                            
                
                        







                                                   

                                            
      
 

                                           


      






























                                                                                          
                                                  

                                                            



















                                                     



                                
                                            





































                                                                                      
                                                         

                                   
                                            







                                                        
              















                                                                 
                                                    








                                                                  
/**
 * @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 <bsp.h>
#include <bsp/utility.h>
#include <bsp/lpc24xx.h>
#include <bsp/system-clocks.h>

/**
 * @brief Internal RC oscillator frequency in [Hz].
 */
#define LPC24XX_OSCILLATOR_INTERNAL 4000000U

#ifndef LPC24XX_OSCILLATOR_MAIN
  #error "unknown main oscillator frequency"
#endif

#ifndef LPC24XX_OSCILLATOR_RTC
  #error "unknown RTC oscillator frequency"
#endif

/**
 * @brief Delay for @a us micro seconds.
 *
 * @note Uses Timer 1.
 */
void lpc24xx_micro_seconds_delay( unsigned us)
{
  /* Stop and reset timer */
  T1TCR = 0x02;

  /* Set prescaler to zero */
  T1PR = 0x00;
  
  /* Set match value */
  T1MR0 = (uint32_t) ((uint64_t) 4000000 * (uint64_t) us / (uint64_t) lpc24xx_cclk()) + 1;

  /* Reset all interrupt flags */
  T1IR = 0xff;

  /* Stop timer on match */
  T1MCR = 0x04;

  /* Start timer */
  T1TCR = 0x01;
  
  /* Wait until delay time has elapsed */
  while ((T1TCR & 0x01) != 0) {
    /* Wait */
  }
}

/**
 * @brief Returns the CPU clock frequency in [Hz].
 *
 * Return zero in case of an unexpected PLL input frequency.
 */
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:
      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 = 0;

  /* 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);
}