void InitClock() { // If the internal load capacitors are being used, they should be selected // before enabling the oscillator. Application specific. 16pF and 8pF selected // in this example OSC_CR = OSC_CR_SC16P_MASK | OSC_CR_SC8P_MASK; // Enabling the oscillator for 8 MHz crystal // RANGE=1, should be set to match the frequency of the crystal being used // HGO=1, high gain is selected, provides better noise immunity but does draw // higher current // EREFS=1, enable the external oscillator // LP=0, low power mode not selected (not actually part of osc setup) // IRCS=0, slow internal ref clock selected (not actually part of osc setup) MCG_C2 = MCG_C2_RANGE(1) | MCG_C2_HGO_MASK | MCG_C2_EREFS_MASK; // Select ext oscillator, reference divider and clear IREFS to start ext osc // CLKS=2, select the external clock source // FRDIV=3, set the FLL ref divider to keep the ref clock in range // (even if FLL is not being used) 8 MHz / 256 = 31.25 kHz // IREFS=0, select the external clock // IRCLKEN=0, disable IRCLK (can enable it if desired) // IREFSTEN=0, disable IRC in stop mode (can keep it enabled in stop if desired) MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(3); // wait for oscillator to initialize while (!(MCG_S & MCG_S_OSCINIT_MASK)){} // wait for Reference clock to switch to external reference while (MCG_S & MCG_S_IREFST_MASK){} // Wait for MCGOUT to switch over to the external reference clock while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x2){} // Now configure the PLL and move to PBE mode // set the PRDIV field to generate a 4MHz reference clock (8MHz /2) MCG_C5 = MCG_C5_PRDIV(1); // PRDIV=1 selects a divide by 2 // set the VDIV field to 0, which is x24, giving 4 x 24 = 96 MHz // the PLLS bit is set to enable the PLL // the clock monitor is enabled, CME=1 to cause a reset if crystal fails // LOLIE can be optionally set to enable the loss of lock interrupt MCG_C6 = MCG_C6_CME_MASK | MCG_C6_PLLS_MASK; // wait until the source of the PLLS clock has switched to the PLL while (!(MCG_S & MCG_S_PLLST_MASK)){} // wait until the PLL has achieved lock while (!(MCG_S & MCG_S_LOCK_MASK)){} // set up the SIM clock dividers BEFORE switching to the PLL to ensure the // system clock speeds are in spec. // core = PLL (96MHz), bus = PLL/2 (48MHz), flexbus = PLL/2 (48MHz), flash = PLL/4 (24MHz) SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV3(1) | SIM_CLKDIV1_OUTDIV4(3); // Transition into PEE by setting CLKS to 0 // previous MCG_C1 settings remain the same, just need to set CLKS to 0 MCG_C1 &= ~MCG_C1_CLKS_MASK; // Wait for MCGOUT to switch over to the PLL while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x3){} // The USB clock divider in the System Clock Divider Register 2 (SIM_CLKDIV2) // should be configured to generate the 48 MHz USB clock before configuring // the USB module. SIM_CLKDIV2 |= SIM_CLKDIV2_USBDIV(1); // sets USB divider to /2 assuming reset // state of the SIM_CLKDIV2 register }
/** PLL initialization. */ static void pll_init(void) { // First move to FBE mode // Enable external oscillator, RANGE=0, HGO=, EREFS=, LP=, IRCS= MCG_C2 = 0; // Select external oscilator and Reference Divider and clear IREFS to start ext osc // CLKS=2, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0 MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(3); while (MCG_S & MCG_S_IREFST_MASK); // wait for Reference clock Status bit to clear while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x2); // Wait for clock status bits to show clock source is ext ref clk // ... FBE mode // Configure PLL Ref Divider, PLLCLKEN=0, PLLSTEN=0, PRDIV=0x18 // The crystal frequency is used to select the PRDIV value. Only even frequency crystals are supported // that will produce a 2MHz reference clock to the PLL. MCG_C5 = MCG_C5_PRDIV(REF_CLOCK_DIV - 1); // Ensure MCG_C6 is at the reset default of 0. LOLIE disabled, PLL disabled, clk monitor disabled, PLL VCO divider is clear MCG_C6 = 0; // Set system options dividers SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(CORE_DIV - 1) | // core/system clock SIM_CLKDIV1_OUTDIV2(BUS_DIV - 1) | // peripheral clock SIM_CLKDIV1_OUTDIV3(FLEXBUS_DIV - 1) | // FlexBus clock driven to the external pin (FB_CLK). SIM_CLKDIV1_OUTDIV4(FLASH_DIV - 1); // flash clock // Set the VCO divider and enable the PLL, LOLIE = 0, PLLS = 1, CME = 0, VDIV = MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(PLL_CLOCK_MUL - 24); // 2MHz * BSP_CLOCK_MUL while (!(MCG_S & MCG_S_PLLST_MASK)); // wait for PLL status bit to set while (!(MCG_S & MCG_S_LOCK_MASK)); // Wait for LOCK bit to set // ...running PBE mode // Transition into PEE by setting CLKS to 0 // CLKS=0, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0 MCG_C1 &= ~MCG_C1_CLKS_MASK; // Wait for clock status bits to update while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x3); // ...running PEE mode }
/*! * @brief PLL超频 * @param PLL_e 频率设置参数 * @return 超频频率(MHz) * @since v5.0 * @warning 此函数只能在 复位后没进行任何频率设置情况下调用,即MCG在FEI模式下才可调用 * Sample usage: uint8 clk = pll_init(PLL100); //超频 */ uint8 pll_init(PLL_e pll) { mcg_div_count( pll); //上电复位后,单片机会自动进入 FEI 模式,使用 内部参考时钟 //FEI -> FBE MCG_C2 &= ~MCG_C2_LP_MASK; MCG_C2 |= MCG_C2_RANGE(1); MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(7); while (MCG_S & MCG_S_IREFST_MASK) {}; //等待FLL参考时钟 为 外部参考时钟(S[IREFST]=0,表示使用外部参考时钟,) while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x2) {}; //等待选择外部参考时钟 //现在已经进入了 FBE模式 //FBE -> PBE set_sys_dividers(mcg_div.core_div, mcg_div.bus_div, mcg_div.flex_div, mcg_div.flash_div); //设置系统分频因子选项 MCG_C5 = MCG_C5_PRDIV(mcg_cfg[pll].prdiv); //分频, EXTAL_IN_MHz/( PRDIV+1) MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(mcg_cfg[pll].vdiv) ; //倍频, EXTAL_IN_MHz/( PRDIV+1) * (VDIV+24) while (!(MCG_S & MCG_S_PLLST_MASK)) {}; //等待时钟源选择PLL while (!(MCG_S & MCG_S_LOCK_MASK)) {}; //等待 PLL锁了(锁相环) // 现在已经进入了 PBE 模式 // PBE -> PEE MCG_C1 &= ~MCG_C1_CLKS_MASK; while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x3) {};//等待选择输出PLL // 现在已经进入了 PEE 模式 return mcg_cfg[pll].clk; } //pll_init
/* * LPLD_PLL_Setup * 初始化内核时钟及其他系统时钟 * * 参数: * core_clk_mhz--期望内核时钟频率 * |__PLLx--参见HAL_MCG.h中的PLL_option定义 * * 输出: * 内核频率,单位MHz */ uint8 LPLD_PLL_Setup(PllOptionEnum_Type core_clk_mhz) { uint8 pll_freq; uint8 prdiv, vdiv; uint8 core_div, bus_div, flexbus_div, flash_div; /* ************************************************* 【LPLD注解】MCG关键系数 prdiv(PLL分频系数): 0~31(1~32) vdiv(PLL倍频系数): 0~31(24~55) PLL参考时钟范围: 2MHz~4MHz PLL参考时钟 = 外部参考时钟(CPU_XTAL_CLK_HZ)/prdiv CoreClk = PLL参考时钟 x PLL倍频系数 /OUTDIV1 ************************************************* */ // 对于MK60DZ10来说,core_clk_mhz建议不要超过100,这里限制为最高200 core_clk_mhz = (PllOptionEnum_Type)(core_clk_mhz>200u?200u:core_clk_mhz); // 根据期望主频选择分频和倍频系数 switch(core_clk_mhz) { case PLL_48: prdiv = 24u; vdiv = 0u; break; case PLL_50: prdiv = 24u; vdiv = 1u; break; case PLL_96: prdiv = 24u; vdiv = 24u; break; case PLL_100: prdiv = 24u; vdiv = 26u; break; case PLL_120: prdiv = 19u; vdiv = 24u; break; case PLL_150: prdiv = 15u; vdiv = 24u; break; case PLL_180: prdiv = 14u; vdiv = 30u; break; case PLL_200: prdiv = 12u; vdiv = 28u; break; default: return LPLD_PLL_Setup(PLL_96); } pll_freq = core_clk_mhz * 1; core_div = 0; if((bus_div = (uint8)(core_clk_mhz/BUS_CLK_MHZ - 1u)) == (uint8)-1) { bus_div = 0; } else if(core_clk_mhz/(bus_div+1) > BUS_CLK_MHZ) { bus_div += 1; } if((flexbus_div = (core_clk_mhz/FLEXBUS_CLK_MHZ - 1u)) == (uint8)-1) { flexbus_div = 0; } else if(core_clk_mhz/(flexbus_div+1) > FLEXBUS_CLK_MHZ) { flexbus_div += 1; } if((flash_div = (core_clk_mhz/FLASH_CLK_MHZ - 1u)) == (uint8)-1) { flash_div = 0; } else if(core_clk_mhz/(flash_div+1) > FLASH_CLK_MHZ) { flash_div += 1; } // 这里假设复位后 MCG 模块默认为 FEI 模式 // 首先移动到 FBE 模式 MCG->C2 = 0; // 振荡器初始化完成后,释放锁存状态下的 oscillator 和 GPIO SIM->SCGC4 |= SIM_SCGC4_LLWU_MASK; LLWU->CS |= LLWU_CS_ACKISO_MASK; // 选择外部 oscilator 、参考分频器 and 清零 IREFS 启动外部osc // CLKS=2, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0 MCG->C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(3); while (MCG->S & MCG_S_IREFST_MASK){}; // 等待参考时钟清零 while (((MCG->S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x2){}; // 等待时钟状态显示为外部参考时钟(ext ref clk) // 进入FBE模式 // 配置 PLL 参考分频器, PLLCLKEN=0, PLLSTEN=0, PRDIV=5 // 用晶振频率来选择 PRDIV 值. 仅在有频率晶振的时候支持 // 产生 2MHz 的参考时钟给 PLL. MCG->C5 = MCG_C5_PRDIV(prdiv); // 设置 PLL 匹配晶振的参考分频数 // 确保MCG_C6处于复位状态,禁止LOLIE、PLL、和时钟控制器,清PLL VCO分频器 MCG->C6 = 0x0; //设置系统时钟分频系数 LPLD_Set_SYS_DIV(core_div, bus_div, flexbus_div, flash_div); //设置倍频系数 MCG->C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(vdiv); while (!(MCG->S & MCG_S_PLLST_MASK)){}; // wait for PLL status bit to set while (!(MCG->S & MCG_S_LOCK_MASK)){}; // Wait for LOCK bit to set // 已经进入PBE模式 // Transition into PEE by setting CLKS to 0 // CLKS=0, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0 MCG->C1 &= ~MCG_C1_CLKS_MASK; // Wait for clock status bits to update while (((MCG->S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x3){}; // 已经进入PEE模式 return pll_freq; }
void kinetis_pllconfig(void) { uint32_t regval32; uint8_t regval8; /* Transition to FLL Bypassed External (FBE) mode */ #ifdef BOARD_EXTCLOCK /* IRCS = 0 (Internal Reference Clock Select) * LP = 0 (Low Power Select) * EREFS = 0 (External Reference Select) * HGO = 0 (High Gain Oscillator Select) * RANGE = 0 (Oscillator of 32 kHz to 40 kHz) */ putreg8(0, KINETIS_MCG_C2); #else /* Enable external oscillator: * * IRCS = 0 (Internal Reference Clock Select) * LP = 0 (Low Power Select) * EREFS = 1 (External Reference Select) * HGO = 1 (High Gain Oscillator Select) * RANGE = 2 (Oscillator of 8 MHz to 32 MHz) */ putreg8(MCG_C2_EREFS | MCG_C2_HGO | MCG_C2_RANGE_VHIGH, KINETIS_MCG_C2); #endif /* Released latched state of oscillator and GPIO */ regval32 = getreg32(KINETIS_SIM_SCGC4); regval32 |= SIM_SCGC4_LLWU; putreg32(regval32, KINETIS_SIM_SCGC4); regval8 = getreg8(KINETIS_LLWU_CS); regval8 |= LLWU_CS_ACKISO; putreg8(regval8, KINETIS_LLWU_CS); /* Select external oscillator and Reference Divider and clear IREFS to * start the external oscillator. * * IREFSTEN = 0 (Internal Reference Stop Enable) * IRCLKEN = 0 (Internal Reference Clock Enable) * IREFS = 0 (Internal Reference Select) * FRDIV = 3 (FLL External Reference Divider, RANGE!=0 divider=256) * CLKS = 2 (Clock Source Select, External reference clock) */ putreg8(MCG_C1_FRDIV_DIV256 | MCG_C1_CLKS_EXTREF, KINETIS_MCG_C1); /* If we aren't using an oscillator input we don't need to wait for the * oscillator to initialize */ #ifndef BOARD_EXTCLOCK while ((getreg8(KINETIS_MCG_S) & MCG_S_OSCINIT) == 0); #endif /* Wait for Reference clock Status bit to clear */ while ((getreg8(KINETIS_MCG_S) & MCG_S_IREFST) != 0); /* Wait for clock status bits to show that the clock source is the * external reference clock. */ while ((getreg8(KINETIS_MCG_S) & MCG_S_CLKST_MASK) != MCG_S_CLKST_EXTREF); /* We are now in FLL Bypassed External (FBE) mode. Configure PLL * reference clock divider: * * PLLCLKEN = 0 * PLLSTEN = 0 * PRDIV = Determined by PLL reference clock frequency * * Either the external clock or crystal frequency is used to select the * PRDIV value. Only reference clock frequencies are supported that will * produce a 2MHz reference clock to the PLL. */ putreg8(MCG_C5_PRDIV(BOARD_PRDIV), KINETIS_MCG_C5); /* Ensure that MCG_C6 is at the reset default of 0: LOLIE disabled, PLL * disabled, clk monitor disabled, PLL VCO divider cleared. */ putreg8(0, KINETIS_MCG_C6); /* Set system options dividers based on settings from the board.h file. * * MCG = PLL * Core = MCG / BOARD_OUTDIV1 * bus = MCG / BOARD_OUTDIV2 * FlexBus = MCG / BOARD_OUTDIV3 * Flash clock = MCG / BOARD_OUTDIV4 */ kinesis_setdividers(BOARD_OUTDIV1, BOARD_OUTDIV2, BOARD_OUTDIV3, BOARD_OUTDIV4); /* Set the VCO divider, VDIV, is defined in the board.h file. VDIV * selects the amount to divide the VCO output of the PLL. The VDIV bits * establish the multiplication factor applied to the reference clock * frequency. Also set * * LOLIE = 0 (Loss of Lock Interrrupt Enable) * PLLS = 1 (PLL Select) * CME = 0 (Clock Monitor Enable) */ putreg8(MCG_C6_PLLS | MCG_C6_VDIV(BOARD_VDIV), KINETIS_MCG_C6); /* Wait for the PLL status bit to set */ while ((getreg8(KINETIS_MCG_S) & MCG_S_PLLST) == 0); /* Wait for the PLL LOCK bit to set */ while ((getreg8(KINETIS_MCG_S) & MCG_S_LOCK) == 0); /* We are now running in PLL Bypassed External (PBE) mode. Transition to * PLL Engaged External (PEE) mode by setting CLKS to 0 */ regval8 = getreg8(KINETIS_MCG_C1); regval8 &= ~MCG_C1_CLKS_MASK; putreg8(regval8, KINETIS_MCG_C1); /* Wait for clock status bits to update */ while ((getreg8(KINETIS_MCG_S) & MCG_S_CLKST_MASK) != MCG_S_CLKST_PLL); /* We are now running in PLL Engaged External (PEE) mode. */ }
/************************************************************************************************ * SetPLL_Kinetis * 系统的锁相环设定,其完成的主要工作为: 设定CoreClock、BusClock、FlexClock、FlashClock * (设置的具体频率在KinetisConfig.h中配置) ************************************************************************************************/ static void SetPLL_Kinetis(void) { K_int32u_t temp_reg; K_int8u_t i; // First move to FBE mode // Enable external oscillator, RANGE=2, HGO=1, EREFS=1, LP=0, IRCS=0 MCG_C2 = MCG_C2_RANGE(1) | MCG_C2_HGO_MASK | MCG_C2_EREFS_MASK; // after initialization of oscillator release latched state of oscillator and GPIO SIM_SCGC4 |= SIM_SCGC4_LLWU_MASK; LLWU_CS |= LLWU_CS_ACKISO_MASK; // Select external oscilator and Reference Divider and clear IREFS to start ext osc // CLKS=2, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0 MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(3); /* if we aren't using an osc input we don't need to wait for the osc to init */ while (MCG_S & MCG_S_IREFST_MASK){}; // wait for Reference clock Status bit to clear while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x2){}; // Wait for clock status bits to show clock source is ext ref clk // Now in FBE /* 设定PLL时钟 */ #if CORE_CLK_Kinetis <= 110 MCG_C5 = MCG_C5_PRDIV(REF_CLK_Kinetis/2 - 1); /* PLLCLK == 2MHz */ #else #if REF_CLK_Kinetis % 3 == 0 MCG_C5 = MCG_C5_PRDIV(REF_CLK_Kinetis/3 - 1); /* PLLCLK == 3MHz */ #elif REF_CLK_Kinetis % 4 == 0 MCG_C5 = MCG_C5_PRDIV(REF_CLK_Kinetis/4 - 1); /* PLLCLK == 4MHz */ #elif REF_CLK_Kinetis % 5 == 0 MCG_C5 = MCG_C5_PRDIV(REF_CLK_Kinetis*2/5 - 1); /* PLLCLK == 2.5MHz */ #endif #endif /* * Ensure MCG_C6 is at the reset default of 0. LOLIE disabled, * PLL disabled, clk monitor disabled, PLL VCO divider is clear */ MCG_C6 = 0x0; /* 设定各时钟的分频数 */ temp_reg = FMC_PFAPR; // store present value of FMC_PFAPR // set M0PFD through M7PFD to 1 to disable prefetch FMC_PFAPR |= FMC_PFAPR_M7PFD_MASK | FMC_PFAPR_M6PFD_MASK | FMC_PFAPR_M5PFD_MASK | FMC_PFAPR_M4PFD_MASK | FMC_PFAPR_M3PFD_MASK | FMC_PFAPR_M2PFD_MASK | FMC_PFAPR_M1PFD_MASK | FMC_PFAPR_M0PFD_MASK; // set clock dividers to desired value SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(DIV_BusClk_Kinetis - 1) | SIM_CLKDIV1_OUTDIV3(DIV_FlexClk_Kinetis - 1) | SIM_CLKDIV1_OUTDIV4(DIV_FlashClk_Kinetis - 1); // wait for dividers to change for (i = 0 ; i < DIV_FlashClk_Kinetis ; i++) {} FMC_PFAPR = temp_reg; // re-store original value of FMC_PFAPR /* 设置倍频数,倍频数为VDIV+24 */ #if CORE_CLK_Kinetis <= 110 MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(CORE_CLK_Kinetis/2 - 24); #else #if REF_CLK_Kinetis % 3 == 0 MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(CORE_CLK_Kinetis/3 - 24); #elif REF_CLK_Kinetis % 4 == 0 MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(CORE_CLK_Kinetis/4 - 24); #elif REF_CLK_Kinetis % 5 == 0 MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(CORE_CLK_Kinetis*2/5 - 24); #endif #endif while (!(MCG_S & MCG_S_PLLST_MASK)){}; // wait for PLL status bit to set while (!(MCG_S & MCG_S_LOCK_MASK)){}; // Wait for LOCK bit to set // Now running PBE Mode // Transition into PEE by setting CLKS to 0 // CLKS=0, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0 MCG_C1 &= ~MCG_C1_CLKS_MASK; // Wait for clock status bits to update while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x3){}; }
/*lint -esym(765,Cpu_Interrupt) Disable MISRA rule (8.10) checking for symbols (Cpu_Interrupt). */ void __init_hardware(void) { /*** !!! Here you can place your own code before PE initialization using property "User code before PE initialization" on the build options tab. !!! ***/ /*** ### MK60DN512ZVLQ10 "Cpu" init code ... ***/ /*** PE initialization code after reset ***/ SCB_VTOR = (uint32_t)(&__vect_table); /* Set the interrupt vector table position */ /* Disable the WDOG module */ /* WDOG_UNLOCK: WDOGUNLOCK=0xC520 */ WDOG_UNLOCK = WDOG_UNLOCK_WDOGUNLOCK(0xC520); /* Key 1 */ /* WDOG_UNLOCK: WDOGUNLOCK=0xD928 */ WDOG_UNLOCK = WDOG_UNLOCK_WDOGUNLOCK(0xD928); /* Key 2 */ /* WDOG_STCTRLH: ??=0,DISTESTWDOG=0,BYTESEL=0,TESTSEL=0,TESTWDOG=0,??=0,STNDBYEN=1,WAITEN=1,STOPEN=1,DBGEN=0,ALLOWUPDATE=1,WINEN=0,IRQRSTEN=0,CLKSRC=1,WDOGEN=0 */ WDOG_STCTRLH = WDOG_STCTRLH_BYTESEL(0x00) | WDOG_STCTRLH_STNDBYEN_MASK | WDOG_STCTRLH_WAITEN_MASK | WDOG_STCTRLH_STOPEN_MASK | WDOG_STCTRLH_ALLOWUPDATE_MASK | WDOG_STCTRLH_CLKSRC_MASK; /* System clock initialization */ /* SIM_CLKDIV1: OUTDIV1=0,OUTDIV2=1,OUTDIV3=3,OUTDIV4=3,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0 */ SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0x00) | SIM_CLKDIV1_OUTDIV2(0x01) | SIM_CLKDIV1_OUTDIV3(0x03) | SIM_CLKDIV1_OUTDIV4(0x03); /* Set the system prescalers to safe value */ /* SIM_SCGC5: PORTC=1,PORTA=1 */ SIM_SCGC5 |= (SIM_SCGC5_PORTC_MASK | SIM_SCGC5_PORTA_MASK); /* Enable clock gate for ports to enable pin routing */ /* SIM_CLKDIV1: OUTDIV1=0,OUTDIV2=0,OUTDIV3=1,OUTDIV4=1,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0,??=0 */ SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0x00) | SIM_CLKDIV1_OUTDIV2(0x00) | SIM_CLKDIV1_OUTDIV3(0x01) | SIM_CLKDIV1_OUTDIV4(0x01); /* Update system prescalers */ /* SIM_CLKDIV2: USBDIV=0,USBFRAC=1 */ SIM_CLKDIV2 = (uint32_t)((SIM_CLKDIV2 & (uint32_t)~(uint32_t)( SIM_CLKDIV2_USBDIV(0x07) )) | (uint32_t)( SIM_CLKDIV2_USBFRAC_MASK )); /* Update USB clock prescalers */ /* SIM_SOPT2: PLLFLLSEL=0 */ SIM_SOPT2 &= (uint32_t)~(uint32_t)(SIM_SOPT2_PLLFLLSEL_MASK); /* Select FLL as a clock source for various peripherals */ /* SIM_SOPT1: OSC32KSEL=0 */ SIM_SOPT1 &= (uint32_t)~(uint32_t)(SIM_SOPT1_OSC32KSEL_MASK); /* System oscillator drives 32 kHz clock for various peripherals */ /* Switch to FEI Mode */ /* MCG_C1: CLKS=0,FRDIV=0,IREFS=1,IRCLKEN=1,IREFSTEN=0 */ MCG_C1 = MCG_C1_CLKS(0x00) | MCG_C1_FRDIV(0x00) | MCG_C1_IREFS_MASK | MCG_C1_IRCLKEN_MASK; /* MCG_C2: ??=0,??=0,RANGE=0,HGO=0,EREFS=0,LP=0,IRCS=0 */ MCG_C2 = MCG_C2_RANGE(0x00); /* MCG_C4: DMX32=0,DRST_DRS=0 */ MCG_C4 &= (uint8_t)~(uint8_t)((MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS(0x03))); /* OSC_CR: ERCLKEN=1,??=0,EREFSTEN=0,??=0,SC2P=0,SC4P=0,SC8P=0,SC16P=0 */ OSC_CR = OSC_CR_ERCLKEN_MASK; /* SIM_SOPT2: MCGCLKSEL=0 */ SIM_SOPT2 &= (uint32_t)~(uint32_t)(SIM_SOPT2_MCGCLKSEL_MASK); /* MCG_C5: ??=0,PLLCLKEN=0,PLLSTEN=0,PRDIV=0 */ MCG_C5 = MCG_C5_PRDIV(0x00); /* MCG_C6: LOLIE=0,PLLS=0,CME=0,VDIV=0 */ MCG_C6 = MCG_C6_VDIV(0x00); while((MCG_S & MCG_S_IREFST_MASK) == 0x00U) { /* Check that the source of the FLL reference clock is the internal reference clock. */ } while((MCG_S & 0x0CU) != 0x00U) { /* Wait until output of the FLL is selected */ } /*** End of PE initialization code after reset ***/ /*** !!! Here you can place your own code after PE initialization using property "User code after PE initialization" on the build options tab. !!! ***/ }
/** * Initialize the system * * @param none * @return none * * @brief Setup the microcontroller system. * Initialize the System. */ void SystemInit (void) { // system dividers SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV3(2) | SIM_CLKDIV1_OUTDIV4(5); // after reset, we are in FEI mode // enable external clock source - OSC0 #if __SYS_OSC_CLK <= 8000000 MCG_C2 = MCG_C2_LOCRE0_MASK | MCG_C2_RANGE(RANGE0_VAL) | (/*hgo_val*/0 << MCG_C2_HGO_SHIFT) | (/*erefs_val*/0 << MCG_C2_EREFS_SHIFT); #else // On rev. 1.0 of silicon there is an issue where the the input bufferd are enabled when JTAG is connected. // This has the affect of sometimes preventing the oscillator from running. To keep the oscillator amplitude // low, RANGE = 2 should not be used. This should be removed when fixed silicon is available. MCG_C2 = MCG_C2_LOCRE_MASK | MCG_C2_RANGE(2) | (/*hgo_val*/0 << MCG_C2_HGO_SHIFT) | (/*erefs_val*/0 << MCG_C2_EREFS_SHIFT); // MCG_C2 = MCG_C2_LOCRE_MASK | MCG_C2_RANGE(1) | (/*hgo_val*/0 << MCG_C2_HGO_SHIFT) | (/*erefs_val*/0 << MCG_C2_EREFS_SHIFT); #endif // select clock mode, we want FBE mode // CLKS = 2, FRDIV = frdiv_val, IREFS = 0, IRCLKEN = 0, IREFSTEN = 0 MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(FRDIV_VAL); /* wait until the MCG has moved into the proper mode */ // if the external oscillator is used need to wait for OSCINIT to set // for (i = 0 ; i < 10000 ; i++) // { // if (MCG_S & MCG_S_OSCINIT_MASK) break; // jump out early if OSCINIT sets before loop finishes // } // if (!(MCG_S & MCG_S_OSCINIT_MASK)) return 0x23; // check bit is really set and return with error if not set // wait for reference clock status bit is cleared and clock source is ext ref clk while ((MCG_S & MCG_S_IREFST_MASK) || MCG_S_CLKST(2) != (MCG_S & MCG_S_CLKST_MASK)); // ... FBE mode // enable clock monitor for osc0 MCG_C6 = MCG_C6_CME_MASK; // PLL0 MCG_C5 = MCG_C5_PRDIV(PRDIV_VAL - 1); // set PLL0 ref divider, osc0 is reference MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(VDIV_VAL - 16); // set VDIV and enable PLL // wait to lock... while (!(MCG_S & MCG_S_PLLST_MASK)); while (!(MCG_S & MCG_S_LOCK_MASK)); // // Use actual PLL settings to calculate PLL frequency // prdiv = ((MCG_C5 & MCG_C5_PRDIV_MASK) + 1); // vdiv = ((MCG_C6 & MCG_C6_VDIV_MASK) + 16); // ... PBE mode MCG_C1 &= ~MCG_C1_CLKS_MASK; // CLKS = 0, select PLL as MCG_OUT while (MCG_S_CLKST(3) != (MCG_S & MCG_S_CLKST_MASK)); // ... PEE mode /* ToDo: add code to initialize the system do not use global variables because this function is called before reaching pre-main. RW section maybe overwritten afterwards. */ SystemCoreClock = __SYSTEM_CLOCK; }
//锁相环频率为60M测试函数 void pllinit60M(void) { uint32_t temp_reg; //使能IO端口时钟 SIM_SCGC5 |= (SIM_SCGC5_PORTA_MASK | SIM_SCGC5_PORTB_MASK | SIM_SCGC5_PORTC_MASK | SIM_SCGC5_PORTD_MASK | SIM_SCGC5_PORTE_MASK ); //这里处在默认的FEI模式 //首先移动到FBE模式 MCG_C2 = 0; //MCG_C2 = MCG_C2_RANGE(2) | MCG_C2_HGO_MASK | MCG_C2_EREFS_MASK; //初始化晶振后释放锁定状态的振荡器和GPIO SIM_SCGC4 |= SIM_SCGC4_LLWU_MASK; LLWU_CS |= LLWU_CS_ACKISO_MASK; //选择外部晶振,参考分频器,清IREFS来启动外部晶振 //011 If RANGE = 0, Divide Factor is 8; for all other RANGE values, Divide Factor is 256. MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(3); //等待晶振稳定 //while (!(MCG_S & MCG_S_OSCINIT_MASK)){} //等待锁相环初始化结束 while (MCG_S & MCG_S_IREFST_MASK){} //等待时钟切换到外部参考时钟 while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x2){} //进入FBE模式, //0x18==25分频=2M, //0x11==18分频=2.7778M //0x12==19分频=2.63M, //0x13==20分频=2.5M MCG_C5 = MCG_C5_PRDIV(0x18); //确保MCG_C6处于复位状态,禁止LOLIE、PLL、和时钟控制器,清PLL VCO分频器 MCG_C6 = 0x0; //保存FMC_PFAPR当前的值 temp_reg = FMC_PFAPR; //通过M&PFD置位M0PFD来禁止预取功能 FMC_PFAPR |= FMC_PFAPR_M7PFD_MASK | FMC_PFAPR_M6PFD_MASK | FMC_PFAPR_M5PFD_MASK | FMC_PFAPR_M4PFD_MASK | FMC_PFAPR_M3PFD_MASK | FMC_PFAPR_M2PFD_MASK | FMC_PFAPR_M1PFD_MASK | FMC_PFAPR_M0PFD_MASK; ///设置系统分频器 //MCG=PLL, core = MCG, bus = MCG/2, FlexBus = MCG/2, Flash clock= MCG/4 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV3(1) | SIM_CLKDIV1_OUTDIV4(3); //从新存FMC_PFAPR的原始值 FMC_PFAPR = temp_reg; //设置VCO分频器,使能PLL为100MHz, LOLIE=0, PLLS=1, CME=0, VDIV=26 MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(6); //VDIV = 31 (x55) //VDIV = 26 (x50) //VDIV = 6 (x30) while (!(MCG_S & MCG_S_PLLST_MASK)){}; // wait for PLL status bit to set while (!(MCG_S & MCG_S_LOCK_MASK)){}; // Wait for LOCK bit to set //进入PBE模式 //通过清零CLKS位来进入PEE模式 // CLKS=0, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0 MCG_C1 &= ~MCG_C1_CLKS_MASK; //等待时钟状态位更新 while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x3){}; //SIM_CLKDIV2 |= SIM_CLKDIV2_USBDIV(1); //设置跟踪时钟为内核时钟 SIM_SOPT2 |= SIM_SOPT2_TRACECLKSEL_MASK; //在PTA6引脚上使能TRACE_CLKOU功能 PORTA_PCR6 = ( PORT_PCR_MUX(0x7)); //使能FlexBus模块时钟 SIM_SCGC7 |= SIM_SCGC7_FLEXBUS_MASK; //在PTA6引脚上使能FB_CLKOUT功能 PORTC_PCR3 = ( PORT_PCR_MUX(0x5)); }
/************************************************************************* * 野火嵌入式开发工作室 * * 函数名称:pll_init * 功能说明:锁相环函数,用于设定频率。 * 参数说明:crystal_val 晶体选项,这里没用到 * 函数返回:无 * 修改时间:2012-1-20 * 备 注:根据 全局变量 mcg_div 保存的分频因子来分频 *************************************************************************/ unsigned char pll_init(clk_option opt) { unsigned char pll_freq; if(opt != PLLUSR ) //自定义模式,直接加载全局变量mcg_div的值 { //设置MCG时钟 switch(opt) { case PLL48: mcg_div.prdiv = 24; mcg_div.vdiv = 0; break; case PLL50: mcg_div.prdiv = 24; mcg_div.vdiv = 1; break; case PLL96: mcg_div.prdiv = 24; mcg_div.vdiv = 24; break; case PLL100: mcg_div.prdiv = 24; mcg_div.vdiv = 26; break; case PLL110: mcg_div.prdiv = 24; mcg_div.vdiv = 31; break; case PLL120: mcg_div.prdiv = 19; mcg_div.vdiv = 24; break; case PLL125: mcg_div.prdiv = 19; mcg_div.vdiv = 26; break; case PLL130: mcg_div.prdiv = 19; mcg_div.vdiv = 28; break; case PLL140: mcg_div.prdiv = 14; mcg_div.vdiv = 18; break; case PLL150: mcg_div.prdiv = 14; mcg_div.vdiv = 21; break; case PLL160: mcg_div.prdiv = 14; mcg_div.vdiv = 24; break; case PLL170: mcg_div.prdiv = 14; mcg_div.vdiv = 27; break; case PLL180: mcg_div.prdiv = 14; mcg_div.vdiv = 30; break; case PLL200: mcg_div.prdiv = 12; mcg_div.vdiv = 28; break; case PLL225: mcg_div.prdiv = 11; mcg_div.vdiv = 30; break; case PLL250: mcg_div.prdiv = 10; mcg_div.vdiv = 31; break; default: return pll_init(PLL100); //这情况不会发生。 } //设置分频 mcg_div.core_div = 0; // core = MCG /* 这里提示警告,但是安全的,是为了安全才故意添加进去 */ if (opt <= 1 * MAX_BUS_CLK) mcg_div.bus_div = 0; // bus = MCG else if(opt <= 2 * MAX_BUS_CLK) mcg_div.bus_div = 1; // bus = MCG/2 else if(opt <= 3 * MAX_BUS_CLK) mcg_div.bus_div = 2; // bus = MCG/3 else if(opt <= 4 * MAX_BUS_CLK) mcg_div.bus_div = 3; // bus = MCG/4 这里提示警告,不过没关系 else mcg_div.bus_div = 15; // bus = MCG/16 mcg_div.flex_div = mcg_div.bus_div; // flex = bus /* 这里提示警告,但是安全的,是为了安全才故意添加进去 */ if (opt <= 1 * MAX_FLASH_CLK) mcg_div.flash_div = 0; // flash = MCG else if(opt <= 2 * MAX_FLASH_CLK) mcg_div.flash_div = 1; // flash = MCG/2 else if(opt <= 3 * MAX_FLASH_CLK) mcg_div.flash_div = 2; // flash = MCG/3 else if(opt <= 4 * MAX_FLASH_CLK) mcg_div.flash_div = 3; // flash = MCG/4 else if(opt <= 5 * MAX_FLASH_CLK) mcg_div.flash_div = 4; // flash = MCG/5 else if(opt <= 6 * MAX_FLASH_CLK) mcg_div.flash_div = 5; // flash = MCG/6 else if(opt <= 7 * MAX_FLASH_CLK) mcg_div.flash_div = 6; // flash = MCG/7 else if(opt <= 8 * MAX_FLASH_CLK) mcg_div.flash_div = 7; // flash = MCG/8 else if(opt <= 9 * MAX_FLASH_CLK) mcg_div.flash_div = 8; // flash = MCG/9 这里提示警告,不过没关系 else if(opt <= 10 * MAX_FLASH_CLK) mcg_div.flash_div = 9; // flash = MCG/10 else mcg_div.flash_div = 15; // flash = MCG/16 } pll_freq = (u8)(( (u16)50 * (u16)( mcg_div.vdiv + 24 )) / (u16)( mcg_div.prdiv + 1 ) ); // 50/ ( prdiv +1 ) * ( mcg_div.vdiv + 24 ) //上电复位后,单片机会自动进入 FEI 模式,使用 内部参考时钟 //为了使用外部时钟参考源,我们要先进入 FBE 模式: #if (defined(K60_CLK) || defined(ASB817)) MCG_C2 = 0; #else // Enable external oscillator, RANGE=2, HGO=1, EREFS=1, LP=0, IRCS=0 MCG_C2 = MCG_C2_RANGE(2) | MCG_C2_HGO_MASK | MCG_C2_EREFS_MASK; #endif //初始化晶振后释放锁定状态的振荡器和GPIO SIM_SCGC4 |= SIM_SCGC4_LLWU_MASK; LLWU_CS |= LLWU_CS_ACKISO_MASK; // Select external oscilator and Reference Divider and clear IREFS to start ext osc // CLKS=2, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0 MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(3); /* if we aren't using an osc input we don't need to wait for the osc to init */ #if (!defined(K60_CLK) && !defined(ASB817)) while (!(MCG_S & MCG_S_OSCINIT_MASK)) {}; //等待晶振稳定 #endif while (MCG_S & MCG_S_IREFST_MASK) {}; // wait for Reference clock Status bit to clear while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x2) {}; // Wait for clock status bits to show clock source is ext ref clk //进入FBE模式 分频后结果必须在 :2 MHz ~ 4 MHz. // n (n+1)分频 50M/(n+1) n为12~24之间 MCG_C5 = MCG_C5_PRDIV(mcg_div.prdiv); // prdiv +1 分频 :2M MCG_C6 = 0x0; // Ensure MCG_C6 is at the reset default of 0. LOLIE disabled, PLL disabled, clk monitor disabled, PLL VCO divider is clear // 设置系统分频因子选项 //MCG=PLL, core = MCG/(mcg_div.core_div + 1), bus = MCG/(mcg_div.bus_div + 1), //FlexBus = MCG/(mcg_div.flex_div + 1), Flash clock= MCG/(mcg_div.flash_div + 1) set_sys_dividers(mcg_div.core_div, mcg_div.bus_div, mcg_div.flex_div, mcg_div.flash_div); // Set the VCO divider and enable the PLL for 48MHz, LOLIE=0, PLLS=1, CME=0, VDIV=0 // n (n+24)倍频 n为0~31之间 MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(mcg_div.vdiv) ; // mcg_div.vdiv + 1 倍频 while (!(MCG_S & MCG_S_PLLST_MASK)) {}; // wait for PLL status bit to set while (!(MCG_S & MCG_S_LOCK_MASK)) {}; // Wait for LOCK bit to set // 现在已经进入了 PBE 模式 // Transition into PEE by setting CLKS to 0 // CLKS=0, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0 MCG_C1 &= ~MCG_C1_CLKS_MASK; // Wait for clock status bits to update while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x3) {}; // 现在已经进入了 PEE 模式 return pll_freq; } //pll_init
void PLL_Init (unsigned char clk_option, unsigned char crystal_val) { if (clk_option > 3) { return; } //return if one of the available options is not selected if (crystal_val > 24) { return; } // return if one of the available crystal options is not available //This assumes that the MCG is in default FEI mode out of reset. // First move to FBE mode #if (defined(K60_CLK) || defined(ASB817)) MCG_C2 = 0; #else // Enable external oscillator, RANGE=2, HGO=1, EREFS=1, LP=0, IRCS=0 MCG_C2 = MCG_C2_RANGE(2) | MCG_C2_HGO_MASK | MCG_C2_EREFS_MASK; #endif // Select external oscilator and Reference Divider and clear IREFS to start ext osc // CLKS=2, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0 MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(3); /* if we aren't using an osc input we don't need to wait for the osc to init */ #if (!defined(K60_CLK) && !defined(ASB817)) while (!(MCG_S & MCG_S_OSCINIT_MASK)){}; // wait for oscillator to initialize #endif while (MCG_S & MCG_S_IREFST_MASK){}; // wait for Reference clock Status bit to clear while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x2){}; // Wait for clock status bits to show clock source is ext ref clk // Now in FBE // Configure PLL Ref Divider, PLLCLKEN=0, PLLSTEN=0, PRDIV=5 // The crystal frequency is used to select the PRDIV value. Only even frequency crystals are supported // that will produce a 2MHz reference clock to the PLL. MCG_C5 = MCG_C5_PRDIV(crystal_val); // Set PLL ref divider to match the crystal used // Ensure MCG_C6 is at the reset default of 0. LOLIE disabled, PLL disabled, clk monitor disabled, PLL VCO divider is clear MCG_C6 = 0x0; // Select the PLL VCO divider and system clock dividers depending on clocking option switch (clk_option) { case 0: // Set system options dividers //MCG=PLL, core = MCG, bus = MCG, FlexBus = MCG, Flash clock= MCG/2 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) | SIM_CLKDIV1_OUTDIV3(0) | SIM_CLKDIV1_OUTDIV4(1); // Set the VCO divider and enable the PLL for 50MHz, LOLIE=0, PLLS=1, CME=0, VDIV=1 MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(1); //VDIV = 1 (x25) break; case 1: // Set system options dividers //MCG=PLL, core = MCG, bus = MCG/2, FlexBus = MCG/2, Flash clock= MCG/4 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV3(1) | SIM_CLKDIV1_OUTDIV4(3); // Set the VCO divider and enable the PLL for 100MHz, LOLIE=0, PLLS=1, CME=0, VDIV=26 MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(26); //VDIV = 26 (x50) break; case 2: // Set system options dividers //MCG=PLL, core = MCG, bus = MCG/2, FlexBus = MCG/2, Flash clock= MCG/4 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV3(1) | SIM_CLKDIV1_OUTDIV4(3); // Set the VCO divider and enable the PLL for 96MHz, LOLIE=0, PLLS=1, CME=0, VDIV=24 MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(24); //VDIV = 24 (x48) break; case 3: // Set system options dividers //MCG=PLL, core = MCG, bus = MCG, FlexBus = MCG, Flash clock= MCG/2 SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) | SIM_CLKDIV1_OUTDIV2(0) | SIM_CLKDIV1_OUTDIV3(0) | SIM_CLKDIV1_OUTDIV4(1); // Set the VCO divider and enable the PLL for 48MHz, LOLIE=0, PLLS=1, CME=0, VDIV=0 MCG_C6 = MCG_C6_PLLS_MASK; //VDIV = 0 (x24) break; } while (!(MCG_S & MCG_S_PLLST_MASK)){}; // wait for PLL status bit to set while (!(MCG_S & MCG_S_LOCK_MASK)){}; // Wait for LOCK bit to set // Now running PBE Mode // Transition into PEE by setting CLKS to 0 // CLKS=0, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0 MCG_C1 &= ~MCG_C1_CLKS_MASK; // Wait for clock status bits to update while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x3){}; // Now running PEE Mode } //pll_init
static unsigned char pll_init(void) { void (*fcn_ram_call)(uint_32); uint_32 fcn_thumb_flag; uint_32 fcn_rom_addr; uint_32 fcn_ram_addr; /* * Allocate stack space for set_sys_dividers() function copy * The sizeof(set_sys_dividers_ram_copy) must be enough to * fit whole set_sys_dividers() function. */ uint_32 fcn_ram_copy[64]; uint_32 SIM_CLKDIV1_COPY; /* * Copy set_sys_dividers() function to stack @ function_copy address * Because Thumb-2 instruction mode is used its necessary to set * bit[0] correctly to represent the opcode type of the branch target. * For details see: * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka12545.html */ fcn_thumb_flag = (uint_32)set_sys_dividers & 0x01; fcn_rom_addr = (uint_32)set_sys_dividers & ~(uint_32)0x01; fcn_ram_addr = (uint_32)fcn_ram_copy | (fcn_rom_addr & 0x02); _mem_copy ((pointer)fcn_rom_addr, (pointer)fcn_ram_addr, sizeof(fcn_ram_copy)-3); /* Get pointer of set_sys_dividers function to run_in_ram_fcn */ fcn_ram_call = (void (*)(uint_32))(fcn_ram_addr | fcn_thumb_flag); /* * First move to FBE mode * Enable external oscillator, RANGE=2, HGO=1, EREFS=1, LP=0, IRCS=0 */ MCG_C2 = MCG_C2_RANGE(2) | MCG_C2_HGO_MASK | MCG_C2_EREFS_MASK | MCG_C2_IRCS_MASK; /* Select external oscillator and Reference Divider and clear IREFS * to start external oscillator * CLKS = 2, FRDIV = 3, IREFS = 0, IRCLKEN = 0, IREFSTEN = 0 */ MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(3); /* Wait for oscillator to initialize */ while (!(MCG_S & MCG_S_OSCINIT_MASK)){}; /* Wait for Reference Clock Status bit to clear */ while (MCG_S & MCG_S_IREFST_MASK) {}; /* Wait for clock status bits to show clock source * is external reference clock */ while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x2) {}; /* Now in FBE * Configure PLL Reference Divider, PLLCLKEN=1, PLLSTEN=0, PRDIV=8 * The crystal frequency is used to select the PRDIV value. * Only even frequency crystals are supported * that will produce a 2MHz reference clock to the PLL. */ MCG_C5 = MCG_C5_PRDIV(BSP_REF_CLOCK_DIV - 1) | MCG_C5_PLLCLKEN_MASK; /* Ensure MCG_C6 is at the reset default of 0. LOLIE disabled, * PLL disabled, clock monitor disabled, PLL VCO divider is clear */ MCG_C6 = 0; /* Calculate mask for System Clock Divider Register 1 SIM_CLKDIV1 */ SIM_CLKDIV1_COPY = SIM_CLKDIV1_OUTDIV1(BSP_CORE_DIV - 1) | SIM_CLKDIV1_OUTDIV2(BSP_BUS_DIV - 1) | SIM_CLKDIV1_OUTDIV3(BSP_FLEXBUS_DIV - 1) | SIM_CLKDIV1_OUTDIV4(BSP_FLASH_DIV - 1); /* * Set system clock dividers by function running from RAM * This routine must be placed in RAM. It is a workaround for errata e2448. */ fcn_ram_call(SIM_CLKDIV1_COPY); /* Set the VCO divider and enable the PLL, * LOLIE = 0, PLLS = 1, CME = 0, VDIV = 2MHz * BSP_CLOCK_MUL */ MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(BSP_CLOCK_MUL - 24); /* wait for PLL status bit to set */ while (!(MCG_S & MCG_S_PLLST_MASK)) {}; /* Wait for LOCK bit to set */ while (!(MCG_S & MCG_S_LOCK_MASK)) {}; /* Now running PBE Mode */ /* Transition into PEE by setting CLKS to 0 * CLKS=0, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0 */ MCG_C1 &= ~MCG_C1_CLKS_MASK; /* Wait for clock status bits to update */ while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x3) {}; /* Now running PEE Mode */ return MQX_OK; }
/***************************************************************************** * @name MCG_Init * * @brief: Initialization of the Multiple Clock Generator. * * @param : None * * @return : None ***************************************************************************** * Provides clocking options for the device, including a phase-locked * loop(PLL) and frequency-locked loop (FLL) for multiplying slower reference * clock sources ****************************************************************************/ static void MCG_Init() { SIM_SCGC5 |= SIM_SCGC5_MCG_MASK; #ifndef EXTERNAL_OSC SIM_SCGC5 |= SIM_SCGC5_OSC2_MASK; #endif /* First move to FBE mode */ /* Enable external oscillator, RANGE=1, HGO=1, EREFS=1, LP=0, IRCS=0 */ #ifdef EXTERNAL_OSC MCG_C2 = 0; #else MCG_C2 = MCG_C2_RANGE(1) | MCG_C2_HGO_MASK | MCG_C2_EREFS_MASK; #endif /* Select external oscillator and Reference Divider and clear IREFS to start ext. osc. */ // CLKS=2, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0 MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(3); /* Wait for oscillator to initialize */ #ifndef EXTERNAL_OSC while (!(MCG_S & MCG_S_OSCINIT_MASK)) {;} #endif /* Wait for Reference clock Status bit to clear */ while (MCG_S & MCG_S_IREFST_MASK) {;} /* Wait for clock status bits to show clock source is ext. ref. clk. */ while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x2) {;} /* Configure PLL Ref Divider, PLLCLKEN=0, PLLSTEN=0, PRDIV=5 The crystal frequency is used to select the PRDIV value. Only even frequency crystals are supported that will produce a 2MHz reference clock to the PLL. */ MCG_C5 = MCG_C5_PRDIV(BSP_REF_CLOCK_DIV); // Set PLL ref. divider to match the crystal used /* Ensure MCG_C6 is at the reset default of 0. LOLIE disabled, PLL disabled, clk. monitor disabled, PLL VCO divider is clear */ MCG_C6 = 0x0; /* Set system options dividers MCG=PLL, core = MCG */ SIM_CLKDIV0 = SIM_CLKDIV0_OUTDIV(0); /* Set the VCO divider and enable the PLL for 48MHz, LOLIE=0, PLLS=1, CME=0, VDIV=0 */ MCG_C6 = MCG_C6_PLLS_MASK; //VDIV = 0 (x24) /* Wait for PLL status bit to set */ while (!(MCG_S & MCG_S_PLLST_MASK)) {;} /* Wait for LOCK bit to set */ while (!(MCG_S & MCG_S_LOCK_MASK)) {;} /* Now running PBE Mode */ /* Transition into PEE by setting CLKS to 0 CLKS=0, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0 */ MCG_C1 &= ~MCG_C1_CLKS_MASK; /* Wait for clock status bits to update */ while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x3) {;} /* Now running PEE Mode */ SIM_SOPT3 |= SIM_SOPT3_RWE_MASK; SIM_SOPT1 |= SIM_SOPT1_REGE_MASK; SIM_SOPT7 |= 0x80; /* Ensure PLL is selected as USB CLK source */ SIM_CLKDIV1 = 0x00; }