在线时间11 小时
UID2108887
注册时间2014-11-15
NXP金币0
该用户从未签到
注册会员

- 积分
- 178
- 最后登录
- 2018-6-1
|
Kinetis内部的时钟系统比较复杂,对于很多新用户来说,用起来比较吃力。前些天帮客户解决时钟不起振的问题,自己就一句句读了一下启动代码,顺手标注了一下,此处Post出来,以免忘记,也希望能帮助一些新的很对的芯片是Kinetis K60D10。
#include <stdint.h>
#include "device/fsl_device_registers.h"
#define CLOCK_SETUP 4
/* ----------------------------------------------------------------------------
-- Core clock
---------------------------------------------------------------------------- */
uint32_t SystemCoreClock = DEFAULT_SYSTEM_CLOCK;
/* ----------------------------------------------------------------------------
-- SystemInit()
---------------------------------------------------------------------------- */
void SystemInit (void) {
/* Watchdog disable */
#if (DISABLE_WDOG)
/* 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,?=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_WAITEN_MASK |
WDOG_STCTRLH_STOPEN_MASK |
WDOG_STCTRLH_ALLOWUPDATE_MASK |
WDOG_STCTRLH_CLKSRC_MASK |
0x0100U;
#endif /* (DISABLE_WDOG) */
/* 判断是否是从VLLSx唤醒 */
if((RCM->SRS0 & RCM_SRS0_WAKEUP_MASK) != 0x00U)
{
/* 如果是从VLLS唤醒 */
if((PMC->REGSC & PMC_REGSC_ACKISO_MASK) != 0x00U)
{
PMC->REGSC |= PMC_REGSC_ACKISO_MASK; /* **ACKISO位释放IO和内部模块的Hold状态,只会对VLLSx状态恢复有影响(经过复位流程).*/
}
} else {
/* RTC 初始化 */
#ifdef SYSTEM_RTC_CR_VALUE /*在SDK中,默认使能了RTC振荡器和RTC32输出,如果使用低功耗,需要考虑*/
SIM->SCGC6 |= SIM_SCGC6_RTC_MASK;
if ((RTC->CR & RTC_CR_OSCE_MASK) == 0x00U) { /* 如果RTC没有使能,之所以有这段是考虑到选择外部时钟时可能选择RTC,而非OSCCLK */
RTC->CR = (uint32_t)((RTC->CR & (uint32_t)~(uint32_t)(RTC_CR_SC2P_MASK | RTC_CR_SC4P_MASK | RTC_CR_SC8P_MASK | RTC_CR_SC16P_MASK)) | (uint32_t)SYSTEM_RTC_CR_VALUE);
RTC->CR |= (uint32_t)RTC_CR_OSCE_MASK;
RTC->CR &= (uint32_t)~(uint32_t)RTC_CR_CLKO_MASK;
}
#endif
}
/* 允许低功耗模式*/
#ifdef SYSTEM_SMC_PMPROT_VALUE
SMC->PMPROT = SYSTEM_SMC_PMPROT_VALUE;
#endif
/* 系统时钟初始化*/
/* 内部参考时钟值trim初始化 */
#if defined(SLOW_TRIM_ADDRESS)
if ( *((uint8_t*)SLOW_TRIM_ADDRESS) != 0xFFU) { /* 如果non-volatile flash memory被擦除跳过此段 */
MCG->C3 = *((uint8_t*)SLOW_TRIM_ADDRESS);
#endif /* defined(SLOW_TRIM_ADDRESS) */
#if defined(SLOW_FINE_TRIM_ADDRESS)
MCG->C4 = (MCG->C4 & ~(MCG_C4_SCFTRIM_MASK)) | ((*((uint8_t*) SLOW_FINE_TRIM_ADDRESS)) & MCG_C4_SCFTRIM_MASK);
#endif
#if defined(FAST_TRIM_ADDRESS)
MCG->C4 = (MCG->C4 & ~(MCG_C4_FCTRIM_MASK)) |((*((uint8_t*) FAST_TRIM_ADDRESS)) & MCG_C4_FCTRIM_MASK);
#endif
#if defined(SLOW_TRIM_ADDRESS)
}
#endif /* defined(SLOW_TRIM_ADDRESS) */
/* 设置系统预分频和时钟源*/
SIM->CLKDIV1 = SYSTEM_SIM_CLKDIV1_VALUE; /* 设置系统预分频,CLKDIV1=内核,CLKDIV2=BUS,CLKDIV3= FlexBUS,CLKDIV4=Flash */
SIM->SOPT1 = ((SIM->SOPT1) & (uint32_t)(~(SIM_SOPT1_OSC32KSEL_MASK))) | ((SYSTEM_SIM_SOPT1_VALUE) & (SIM_SOPT1_OSC32KSEL_MASK)); /* 所有配置中都选择ERCLK32K时钟源为10=RTC32K,因为OSC32K外部是8M; 00=OSC32K, 01=Reserve,10=RTC32K,11=1K LPO*/
SIM->SOPT2 = ((SIM->SOPT2) & (uint32_t)(~(SIM_SOPT2_PLLFLLSEL_MASK))) | ((SYSTEM_SIM_SOPT2_VALUE) & (SIM_SOPT2_PLLFLLSEL_MASK)); /* 根据配置选择PLL或者FLL作为MCGCLKOUT输出的前一级 */
#if ((MCG_MODE == MCG_MODE_FEI) || (MCG_MODE == MCG_MODE_FBI) || (MCG_MODE == MCG_MODE_BLPI))
/* 设置MCG和OSC */ /* 如果外部主时钟振荡器使能,或者PLL使能并且外部参考时钟选择的是OSCCLK */
#if ((((SYSTEM_OSC_CR_VALUE) & OSC_CR_ERCLKEN_MASK) != 0x00U) || ((((SYSTEM_MCG_C5_VALUE) & MCG_C5_PLLCLKEN0_MASK) != 0x00U) && (((SYSTEM_MCG_C7_VALUE) & MCG_C7_OSCSEL_MASK) == 0x00U)))
/* SIM_SCGC5: PORTA=1 */ /* 使能EXTAL和XTAL的引脚功能*/
SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK;
/* PORTA_PCR18: ISF=0,MUX=0 */
PORTA->PCR[18] &= (uint32_t)~(uint32_t)((PORT_PCR_ISF_MASK | PORT_PCR_MUX(0x07)));
if (((SYSTEM_MCG_C2_VALUE) & MCG_C2_EREFS0_MASK) != 0x00U) { /* 如果外部选择的是振荡器,不是时钟 */
/* PORTA_PCR19: ISF=0,MUX=0 */
PORTA->PCR[19] &= (uint32_t)~(uint32_t)((PORT_PCR_ISF_MASK | PORT_PCR_MUX(0x07)));
}
#endif
MCG->SC = SYSTEM_MCG_SC_VALUE; /* Set SC (fast clock internal reference divider) */
MCG->C1 = SYSTEM_MCG_C1_VALUE; /* Set C1 (clock source selection, FLL ext. reference divider, int. reference enable etc.) */
/* Check that the source of the FLL reference clock is the requested one. */
if (((SYSTEM_MCG_C1_VALUE) & MCG_C1_IREFS_MASK) != 0x00U) {
while((MCG->S & MCG_S_IREFST_MASK) == 0x00U) {
}
} else {
while((MCG->S & MCG_S_IREFST_MASK) != 0x00U) {
}
}
MCG->C2 = (SYSTEM_MCG_C2_VALUE) & (uint8_t)(~(MCG_C2_LP_MASK)); /* Set C2 (freq. range, ext. and int. reference selection etc.; low power bit is set later) */
MCG->C4 = ((SYSTEM_MCG_C4_VALUE) & (uint8_t)(~(MCG_C4_FCTRIM_MASK | MCG_C4_SCFTRIM_MASK))) | (MCG->C4 & (MCG_C4_FCTRIM_MASK | MCG_C4_SCFTRIM_MASK)); /* Set C4 (FLL output; trim values not changed) */
OSC->CR = SYSTEM_OSC_CR_VALUE; /* Set OSC_CR (OSCERCLK enable, oscillator capacitor load) */
MCG->C7 = SYSTEM_MCG_C7_VALUE; /* Set C7 (OSC Clock Select) */
#else /* MCG_MODE */ /* 对选择了选择外部时钟*/
/* 设置MCG和OSC */ /* 如果外部主时钟振荡器使能,或者外部参考时钟选择的是OSCCLK, SDK中全部使能了ERCLK*/
#if (((SYSTEM_OSC_CR_VALUE) & OSC_CR_ERCLKEN_MASK) != 0x00U) || (((SYSTEM_MCG_C7_VALUE) & MCG_C7_OSCSEL_MASK) == 0x00U)
/* SIM_SCGC5: PORTA=1 */
SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK;
/* PORTA_PCR18: ISF=0,MUX=0 */
PORTA->PCR[18] &= (uint32_t)~(uint32_t)((PORT_PCR_ISF_MASK | PORT_PCR_MUX(0x07)));
if (((SYSTEM_MCG_C2_VALUE) & MCG_C2_EREFS0_MASK) != 0x00U) {
/* PORTA_PCR19: ISF=0,MUX=0 */
PORTA->PCR[19] &= (uint32_t)~(uint32_t)((PORT_PCR_ISF_MASK | PORT_PCR_MUX(0x07)));
}
#endif
MCG->SC = SYSTEM_MCG_SC_VALUE; /* 设置内部4M晶振的分频值,4M用于输出到MCGCLKOUT*/
MCG->C2 = (SYSTEM_MCG_C2_VALUE) & (uint8_t)(~(MCG_C2_LP_MASK)); /* LOCRE0=0,RANGE0=2 外部时钟范围,HGO0=0,EREFS0=0外部参考选择 clock=0 或者振荡器=1,IRCS=0 慢速内部参考选择,LP位在后面的Common初始化中设置) */
OSC->CR = SYSTEM_OSC_CR_VALUE; /* OSC 震荡使能 ERCLKEN=1,EREFSTEN=0,SC2P=0,SC4P=0,SC8P=0,SC16P=0 */
MCG->C7 = SYSTEM_MCG_C7_VALUE; /* 选择OSCCLK或者RTC32作为外部输入时钟 OSCSEL=0 OSCCLK =1 RTC32K */
#if (MCG_MODE == MCG_MODE_PEE)
MCG->C1 = (SYSTEM_MCG_C1_VALUE) | MCG_C1_CLKS(0x02); /*CLKS=2 选择外部时钟作为MCGOUTCLK,FRDIV=5 FLL分频,IREFS=0 FLL输入选择 =0外部 =1内部32K,,IRCLKEN=1,IREFSTEN=0 */
#else
MCG->C1 = SYSTEM_MCG_C1_VALUE; /*CLKS=0 选择FLL/PLL作为MCGOUTCLK,FRDIV=5 FLL分频,IREFS=0 FLL输入选择 =0外部 =1内部32K,,IRCLKEN=1,IREFSTEN=0 */
#endif
if ((((SYSTEM_MCG_C2_VALUE) & MCG_C2_EREFS0_MASK) != 0x00U) && (((SYSTEM_MCG_C7_VALUE) & MCG_C7_OSCSEL_MASK) == 0x00U)) {
while((MCG->S & MCG_S_OSCINIT0_MASK) == 0x00U) { /* Check that the oscillator is running */
}
}
/* 查看FLL输入源是外部/FRDIV 还是RTC32K, REFS=0 FLL输入选择 =0外部 =1内部32K*/
if (((SYSTEM_MCG_C1_VALUE) & MCG_C1_IREFS_MASK) != 0x00U) {
while((MCG->S & MCG_S_IREFST_MASK) == 0x00U) {
}
} else {
while((MCG->S & MCG_S_IREFST_MASK) != 0x00U) {
}
}
MCG->C4 = ((SYSTEM_MCG_C4_VALUE) & (uint8_t)(~(MCG_C4_FCTRIM_MASK | MCG_C4_SCFTRIM_MASK))) | (MCG->C4 & (MCG_C4_FCTRIM_MASK | MCG_C4_SCFTRIM_MASK)); /* Set C4 (FLL output; trim values not changed) */
#endif /* MCG_MODE */
/* 所有MCG Mode 的通用设置 */
/* 使能PLL模块,因为PLL clock 可以用来为一些内部外设提供时钟,即便MCGOUTCLK选择的不是PLL。 此处必须先 Disable PLL,并把MCGOUTCLK的选择切换到FLL,再使能PLL*/
MCG->C5 = (SYSTEM_MCG_C5_VALUE) & (uint8_t)(~(MCG_C5_PLLCLKEN0_MASK)); /* Disable PLL模块,PLLCLKEN0=0,PLLSTEN0=0,PRDIV0=0x18设置分频 =25*/
MCG->C6 = (SYSTEM_MCG_C6_VALUE) & (uint8_t)~(MCG_C6_PLLS_MASK); /* PLL和FLL选择时,选择FLL , LOLIE0=0,PLLS=1,CME0=0,VDIV0=0x18 倍频值*/
if ((SYSTEM_MCG_C5_VALUE) & MCG_C5_PLLCLKEN0_MASK) {
MCG->C5 |= MCG_C5_PLLCLKEN0_MASK; /* 使能PLL模块 in mode other than PEE or PBE */
}
/* 切换到BLPI和BLPE MCG Mode,需要额外做的特定设置 */
#if ((MCG_MODE == MCG_MODE_BLPI) || (MCG_MODE == MCG_MODE_BLPE))
MCG->C2 |= (MCG_C2_LP_MASK); /* Disable FLL 和 PLL in bypass mode */
/* 切换到PEE和PBE MCG Mode,需要额外做的特定设置 */
#elif ((MCG_MODE == MCG_MODE_PBE) || (MCG_MODE == MCG_MODE_PEE))
MCG->C6 |= (MCG_C6_PLLS_MASK); /* PLL和FLL选择时,=1设置选择PLL */
while((MCG->S & MCG_S_LOCK0_MASK) == 0x00U) { /* 等待PLL locked*/
}
#if (MCG_MODE == MCG_MODE_PEE)
MCG->C1 &= (uint8_t)~(MCG_C1_CLKS_MASK); /* CLKS可以选择FLL/PLL、内部时钟和外部时钟,此处选择FLL/PLL*/ /*为何此处不需要通过PLLS选择FLL和PLL,*/
#endif
#endif
/* 时钟模式状态检查 */
#if ((MCG_MODE == MCG_MODE_FEI) || (MCG_MODE == MCG_MODE_FEE))
while((MCG->S & MCG_S_CLKST_MASK) != 0x00U) { /* 查看FLL是否是最终的MCGOUTCLK输出,FLL/内部时钟/外部时钟/PLL*/
}
/* 使用LPTMR计时1s等待FLL时钟稳定 */
SIM->SCGC5 |= SIM_SCGC5_LPTIMER_MASK; /* 允许软件控制LPMTR */
LPTMR0->CMR = LPTMR_CMR_COMPARE(0); /*默认1 LPO tick */
LPTMR0->CSR = (LPTMR_CSR_TCF_MASK | LPTMR_CSR_TPS(0x00));
LPTMR0->PSR = (LPTMR_PSR_PCS(0x01) | LPTMR_PSR_PBYP_MASK); /* 时钟源LPO, 预分频bypass使能*/
LPTMR0->CSR = LPTMR_CSR_TEN_MASK; /* LPMTR enable */
while((LPTMR0->CSR & LPTMR_CSR_TCF_MASK) == 0u) {
}
LPTMR0->CSR = 0x00; /* Disable LPTMR */
SIM->SCGC5 &= (uint32_t)~(uint32_t)SIM_SCGC5_LPTIMER_MASK;
#elif ((MCG_MODE == MCG_MODE_FBI) || (MCG_MODE == MCG_MODE_BLPI))
while((MCG->S & MCG_S_CLKST_MASK) != 0x04U) { /* 查看内部参考时钟是否是最终的MCGOUTCLK输出,FLL/内部时钟/外部时钟/PLL*/
}
#elif ((MCG_MODE == MCG_MODE_FBE) || (MCG_MODE == MCG_MODE_PBE) || (MCG_MODE == MCG_MODE_BLPE))
while((MCG->S & MCG_S_CLKST_MASK) != 0x08U) { /* 查看外部参考时钟是否是最终的MCGOUTCLK输出,FLL/内部时钟/外部时钟/PLL*/
}
#elif (MCG_MODE == MCG_MODE_PEE)
while((MCG->S & MCG_S_CLKST_MASK) != 0x0CU) { /* 查看PLL是否是最终的MCGOUTCLK输出,FLL/内部时钟/外部时钟/PLL*/
}
#endif
/* 使能VLP时钟模式 */
#if (((SYSTEM_SMC_PMCTRL_VALUE) & SMC_PMCTRL_RUNM_MASK) == (0x02U << SMC_PMCTRL_RUNM_SHIFT))
SMC->PMCTRL = (uint8_t)((SYSTEM_SMC_PMCTRL_VALUE) & (SMC_PMCTRL_RUNM_MASK)); /* 使能VLPR模式 */
while(SMC->PMSTAT != 0x04U) { /* 等待系统最终进入VLPR模式 */
}
#endif
#if defined(SYSTEM_SIM_CLKDIV2_VALUE) /* USB时钟设置,USB时钟选择可以是MCGFLLCLK和MCGPLLCLK,Divider output clock = Divider input clock × [ (USBFRAC+1) / (USBDIV+1) ]*/
SIM->CLKDIV2 = ((SIM->CLKDIV2) & (uint32_t)(~(SIM_CLKDIV2_USBFRAC_MASK | SIM_CLKDIV2_USBDIV_MASK))) | ((SYSTEM_SIM_CLKDIV2_VALUE) & (SIM_CLKDIV2_USBFRAC_MASK | SIM_CLKDIV2_USBDIV_MASK)); /* Selects the USB clock divider. */
#endif
/* PLL失去锁定中断请求初始化*/
if (((SYSTEM_MCG_C6_VALUE) & MCG_C6_LOLIE0_MASK) != 0U) { /*如果已经使能PLL模块的失锁中断请求*/
NVIC_EnableIRQ(MCG_IRQn); /* 使能IRQ中断 */
}
}
/* ----------------------------------------------------------------------------
-- SystemCoreClockUpdate()
---------------------------------------------------------------------------- */
void SystemCoreClockUpdate (void) {
uint32_t MCGOUTClock; /* Variable to store output clock frequency of the MCG module */
uint16_t Divider;
if ((MCG->C1 & MCG_C1_CLKS_MASK) == 0x00U) {
/* Output of FLL or PLL is selected */
if ((MCG->C6 & MCG_C6_PLLS_MASK) == 0x00U) {
/* FLL is selected */
if ((MCG->C1 & MCG_C1_IREFS_MASK) == 0x00U) {
/* External reference clock is selected */
if((MCG->C7 & MCG_C7_OSCSEL_MASK) == 0x00U) {
MCGOUTClock = CPU_XTAL_CLK_HZ; /* System oscillator drives MCG clock */
} else {
MCGOUTClock = CPU_XTAL32k_CLK_HZ; /* RTC 32 kHz oscillator drives MCG clock */
}
if (((MCG->C2 & MCG_C2_RANGE0_MASK) != 0x00U) && ((MCG->C7 & MCG_C7_OSCSEL_MASK) != 0x01U)) {
switch (MCG->C1 & MCG_C1_FRDIV_MASK) {
case 0x38U:
Divider = 1536U;
break;
case 0x30U:
Divider = 1280U;
break;
default:
Divider = (uint16_t)(32LU << ((MCG->C1 & MCG_C1_FRDIV_MASK) >> MCG_C1_FRDIV_SHIFT));
break;
}
} else {/* ((MCG->C2 & MCG_C2_RANGE_MASK) != 0x00U) */
Divider = (uint16_t)(1LU << ((MCG->C1 & MCG_C1_FRDIV_MASK) >> MCG_C1_FRDIV_SHIFT));
}
MCGOUTClock = (MCGOUTClock / Divider); /* Calculate the divided FLL reference clock */
} else { /* (!((MCG->C1 & MCG_C1_IREFS_MASK) == 0x00U)) */
MCGOUTClock = CPU_INT_SLOW_CLK_HZ; /* The slow internal reference clock is selected */
} /* (!((MCG->C1 & MCG_C1_IREFS_MASK) == 0x00U)) */
/* Select correct multiplier to calculate the MCG output clock */
switch (MCG->C4 & (MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) {
case 0x00U:
MCGOUTClock *= 640U;
break;
case 0x20U:
MCGOUTClock *= 1280U;
break;
case 0x40U:
MCGOUTClock *= 1920U;
break;
case 0x60U:
MCGOUTClock *= 2560U;
break;
case 0x80U:
MCGOUTClock *= 732U;
break;
case 0xA0U:
MCGOUTClock *= 1464U;
break;
case 0xC0U:
MCGOUTClock *= 2197U;
break;
case 0xE0U:
MCGOUTClock *= 2929U;
break;
default:
break;
}
} else { /* (!((MCG->C6 & MCG_C6_PLLS_MASK) == 0x00U)) */
/* PLL is selected */
Divider = (((uint16_t)MCG->C5 & MCG_C5_PRDIV0_MASK) + 0x01U);
MCGOUTClock = (uint32_t)(CPU_XTAL_CLK_HZ / Divider); /* Calculate the PLL reference clock */
Divider = (((uint16_t)MCG->C6 & MCG_C6_VDIV0_MASK) + 24U);
MCGOUTClock *= Divider; /* Calculate the MCG output clock */
} /* (!((MCG->C6 & MCG_C6_PLLS_MASK) == 0x00U)) */
} else if ((MCG->C1 & MCG_C1_CLKS_MASK) == 0x40U) {
/* Internal reference clock is selected */
if ((MCG->C2 & MCG_C2_IRCS_MASK) == 0x00U) {
MCGOUTClock = CPU_INT_SLOW_CLK_HZ; /* Slow internal reference clock selected */
} else { /* (!((MCG->C2 & MCG_C2_IRCS_MASK) == 0x00U)) */
Divider = (uint16_t)(0x01LU << ((MCG->SC & MCG_SC_FCRDIV_MASK) >> MCG_SC_FCRDIV_SHIFT));
MCGOUTClock = (uint32_t) (CPU_INT_FAST_CLK_HZ / Divider); /* Fast internal reference clock selected */
} /* (!((MCG->C2 & MCG_C2_IRCS_MASK) == 0x00U)) */
} else if ((MCG->C1 & MCG_C1_CLKS_MASK) == 0x80U) {
/* External reference clock is selected */
if((MCG->C7 & MCG_C7_OSCSEL_MASK) == 0x00U) {
MCGOUTClock = CPU_XTAL_CLK_HZ; /* System oscillator drives MCG clock */
} else {
MCGOUTClock = CPU_XTAL32k_CLK_HZ; /* RTC 32 kHz oscillator drives MCG clock */
}
} else { /* (!((MCG->C1 & MCG_C1_CLKS_MASK) == 0x80U)) */
/* Reserved value */
return;
} /* (!((MCG->C1 & MCG_C1_CLKS_MASK) == 0x80U)) */
SystemCoreClock = (MCGOUTClock / (0x01U + ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT)));
}
|
|