/**************************************************************************//** * @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 #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