You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

212 lines
7.3 KiB

/**************************************************************************//**
* @file system.c
* @brief CMSIS Device System Source File for
* NXP LPC80xm Device Series
* @version V1.0
* @date 01. April 2017
*
******************************************************************************/
//----------------------------------------------------------------------------
// Important!
// Please configure the desired initial clock setup for your project in:
// $proj_name/inc/chip_setup.h
//----------------------------------------------------------------------------
#include <stdint.h>
#include "LPC8xx.h"
#include "swm.h"
#include "syscon.h"
#include "iocon.h"
#include "fro.h"
#include "rom_api.h"
#include "chip_setup.h"
//----------------------------------------------------------------------------
// Validate the the user's selctions
//----------------------------------------------------------------------------
#define CHECK_RANGE(val, min, max) ((val < min) || (val > max))
#define CHECK_RSVD(val, mask) (val & mask)
#if (CHECK_RANGE((FRO_FREQ_VAL), 0, 2))
#error "FRO_FREQ_VAL: Value out of range."
#endif
#if (CHECK_RSVD((MAINCLKSEL_VAL), ~0x00000003))
#error "MAINCLKSEL: Invalid values of reserved bits!"
#endif
#if (CHECK_RANGE((SYSAHBCLKDIV_VAL), 0, 255))
#error "SYSAHBCLKDIV: Value out of range!"
#endif
#if (CHECK_RANGE(CLKIN_CLK_VAL, 1000000, 25000000))
#error "CLKIN frequency is out of bounds"
#endif
//----------------------------------------------------------------------------
// Calculate internal clock node frequency initial values
//----------------------------------------------------------------------------
#define __LPOSC_CLK (1000000)
// determine output of the FRO_CLKDIV subsystem
#if FRO_FREQ_VAL == 0
#define __FRO_OSCOUT (18000000)
#elif FRO_FREQ_VAL == 2
#define __FRO_OSCOUT (30000000)
#else
#define __FRO_OSCOUT (24000000)
#endif
#define __FRO_DIVIDERS_OUT (__FRO_OSCOUT / 2)
#define __FRO_CLK __FRO_DIVIDERS_OUT
#define __FRO_DIV_CLK (__FRO_CLK / 2)
// determine external_clk
#define __SYS_OSC_CLK (0)
#define __CLKIN_CLK (CLKIN_CLK_VAL)
#define __EXTERNAL_CLK __CLKIN_CLK
// determine main_clk
#if MAINCLKSEL_VAL == 0
#define __MAIN_CLK __FRO_CLK
#elif MAINCLKSEL_VAL == 1
#define __MAIN_CLK __EXTERNAL_CLK
#elif MAINCLKSEL_VAL == 2
#define __MAIN_CLK __LPOSC_CLK
#else
#define __MAIN_CLK __FRO_DIV_CLK
#endif
// determine system_ahb_clk
#define __SYSTEM_AHB_CLK (__MAIN_CLK / SYSAHBCLKDIV_VAL)
//----------------------------------------------------------------------------
// Function name: SystemInit
// Sets up the initial chip clocking based on MACROs defined in chip_setup.h.
//----------------------------------------------------------------------------
void SystemInit (void) {
uint32_t i;
for (i = 1; i < 1; i++) __NOP(); // To avoid a warning if variable i is unused
// Enable clocks to IOCON and SWM upon entry, disable them upon exit
LPC_SYSCON->SYSAHBCLKCTRL[0] |= (SWM | IOCON);
// Step 0. Configure the FRO subsystem (choose the source for clocks fro and fro_div)
#if (FRO_FREQ_VAL == 0)
//temp |= (FRO_18MHZ << FRO_FREQ_SEL);
LPC_PWRD_API->set_fro_frequency(18000);
#elif (FRO_FREQ_VAL == 2)
//temp |= (FRO_30MHZ << FRO_FREQ_SEL);
LPC_PWRD_API->set_fro_frequency(30000);
#else
//temp |= (FRO_24MHZ << FRO_FREQ_SEL);
LPC_PWRD_API->set_fro_frequency(24000);
#endif
//temp = LPC_SYSCON->FROOSCCTRL; // Get the current register contents
//temp &= ~(FRO_FREQSEL_MASK); // Preserve all but the bits of interest [1:0]
///PC_SYSCON->FROOSCCTRL = temp; // Update the actual register
//LPC_SYSCON->FRODIRECTCLKUEN = 0; // Toggle the update register for the output mux
//LPC_SYSCON->FRODIRECTCLKUEN = 1;
//while (!(LPC_SYSCON->FRODIRECTCLKUEN & 1)) __NOP(); // Wait for update to take effect
// Configure clk_in, if needed for main_clk or other (e.g. clock out, ADC clk.)
#if ((MAINCLKSEL_VAL == 1) || (EXT_CLOCK_FORCE_ENABLE == 1))
LPC_IOCON->PIO0_1 &= (IOCON_MODE_MASK | MODE_INACTIVE); // Disable pull-up and pull-down
LPC_SWM->PINENABLE0 &= ~(CLKIN); // Enable CLKIN func.
#endif
// Step 2. Power up the LP OSC if it's needed for main_clk
#if (MAINCLKSEL_VAL == 2)
LPC_SYSCON->PDRUNCFG &= ~(LPOSC_PD); // Power up the LP OSC
for (i = 0; i < 200; i++) __NOP(); // Wait for osc to stabilize
#endif
// Step 4. Choose source for main_clk
LPC_SYSCON->MAINCLKSEL = MAINCLKSEL_VAL; // Update the actual register
LPC_SYSCON->MAINCLKUEN = 0; // Toggle update register
LPC_SYSCON->MAINCLKUEN = 1;
while (!(LPC_SYSCON->MAINCLKUEN & 1)) __NOP(); // Wait until updated
// Step 6. Configure the main_clock divider
LPC_SYSCON->SYSAHBCLKDIV = SYSAHBCLKDIV_VAL; // Update the actual register
LPC_SYSCON->SYSAHBCLKCTRL[0] &= ~(SWM | IOCON); // Turn off peripheral clocks before leaving
} // end of SystemInit
//----------------------------------------------------------------------------
// Global clock variable declarations and initial value assignments
//----------------------------------------------------------------------------
uint32_t main_clk = __MAIN_CLK;
uint32_t lposc_clk = __LPOSC_CLK;
uint32_t fro_clk = __FRO_CLK;
uint32_t fro_div_clk = __FRO_DIV_CLK;
uint32_t system_ahb_clk = __SYSTEM_AHB_CLK;
//----------------------------------------------------------------------------
// Function name: SystemCoreClockUpdate
// Determines the actual system_ahb_clk (core clock), main_clock,
// fro_clk, and fro_div_clk frequencies
// based on the current state of the device, and updates the associated
// global clock variables.
//----------------------------------------------------------------------------
void SystemCoreClockUpdate (void)
{
uint32_t external_clk;
uint32_t fro_oscout, fro_clock;
uint32_t temp;
// Set the fro_clk and fro_div_clk variables according to current register settings
temp = LPC_SYSCON->FROOSCCTRL;
switch (temp & FRO_FREQSEL_MASK) {
case 0: fro_oscout = 18000000; break;
case 1: fro_oscout = 24000000; break;
default:fro_oscout = 30000000; break;
}
fro_clock = 0;
if ((LPC_SYSCON->PDRUNCFG & (FROOUT_PD | FRO_PD)) == 0x0) {
fro_clock = fro_oscout;
}
fro_clk = fro_clock / 2;
fro_div_clk = fro_clk / 2;
// Set the external_clk variable according to current register values
//if (LPC_SYSCON->EXTCLKSEL == 0)
// external_clk = __SYS_OSC_CLK;
//else
external_clk = __CLKIN_CLK;
// Set the lposc_clk variable
if (!(LPC_SYSCON->PDRUNCFG & LPOSC_PD)) {
lposc_clk = __LPOSC_CLK;
}
else {
lposc_clk = 0;
}
// Set the main_clk variable according to current register values
switch (LPC_SYSCON->MAINCLKSEL & 0x3) {
case 0: main_clk = fro_clk; break;
case 1: main_clk = external_clk; break;
case 2: main_clk = lposc_clk; break;
case 3: main_clk = fro_div_clk; break;
}
// Set the system_ahb_clk (a.k.a SystemCoreClock) variable according to current register values
system_ahb_clk = main_clk / LPC_SYSCON->SYSAHBCLKDIV;
} // end of SystemCoreClockUpdate