让K60N512在50Mhz外部有源振荡器下跑到了100M(转)
0赞让K60N512在50Mhz外部有源振荡器下跑到了100M
无论在IAR或MDK下,随开发板提供的例子都是使用的内部时钟,并且使用的是96M主频。我开始使用的是MDK,系统提供的启动文件system_mk60n512vmd100.c根本没有考虑到外部有源振荡器.可选择的COLCK_SETUP=1时,使用的是8Mhz晶体,而OSC可选用的晶体的最高频率是32Mh,所以50Mhz只能使用外部有源振荡器。所以,比较好的方案是在其中增加一个选项,CLOCK_SETUP=3
#elif (CLOCK_SETUP == 3)
#define CPU_XTAL_CLK_HZ 50000000u /* Value of the external crystal or oscillator clock frequency in Hz */
#define CPU_XTAL32k_CLK_HZ 32768u /* Value of the external 32k crystal or oscillator clock frequency in Hz */
#define CPU_INT_SLOW_CLK_HZ 32768u /* Value of the slow internal oscillator clock frequency in Hz */
#define CPU_INT_FAST_CLK_HZ 4000000u /* Value of the fast internal oscillator clock frequency in Hz */
#define DEFAULT_SYSTEM_CLOCK 100000000u /* Default System clock value */
#endif /* (CLOCK_SETUP == 3) */
MDK的程序好像有点问题,不知道程序中去设置哪些FDIV干啥,FPE模式根本不用FLL,FBE,PBE模式系统都是直接使用的外部参考时钟,只是这个是一个流程,所以FLL设置到多少没多大关系,最终会切换到PEE,IAR程序中就没有设置DSC部分,并且有个问题是在切换flash clock 前没有关闭预先取指令,会导致死机。参考IAR重新写了这部分,并和IAR一样,增加了个函数set_sys_divider,有人说要放到RAM中,但是我试着将这个函数编译出来的*.O文件放入RAM,运行时久崩溃了。放到flash中测试了一下,测试了很多次都没有问题,OK.现在,一切OK,system/core clock=100Mhz,flash clock=25Mhz,其他的50Mhz.要看是否外部振荡器是否起作用,很简单,把J6拔掉,如果是闪烁灯的程序停止,插上继续闪动,证明OK了。
#elif (CLOCK_SETUP == 3) //add by leequng
/* Switch to FBE Mode */
/* MCG->C2: ??=0,??=0,RANGE=0,HGO=0,EREFS=0,LP=0,IRCS=0 */
MCG->C2 = 0;
// after initialization of oscillator release latched state of oscillator and GPIO
SIM->SCGC4 |= SIM_SCGC4_LLWU_MASK;
LLWU->CS |= LLWU_CS_ACKISO_MASK;
/* MCG->C1: CLKS=2,FRDIV=3,IREFS=0,IRCLKEN=0,IREFSTEN=0 */
MCG->C1 = (uint8_t)0x98u;
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){};
/* Switch to PBE Mode */
/* MCG->C5: ??=0,PLLCLKEN=0,PLLSTEN=0,PRDIV=19 */
MCG->C5 = (uint8_t)0x13u; //50/20=2.5M
MCG->C6 = 0;
set_sys_dividers(0,1,1,3);
/* MCG->C6: LOLIE=0,PLLS=1,CME=0,VDIV=16 */
MCG->C6 = (uint8_t)0x50u; //2.5X40=100M
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
//===增加的函数 by leequng==============================
void set_sys_dividers(uint32_t outdiv1, uint32_t outdiv2, uint32_t outdiv3, uint32_t outdiv4)
{
uint32_t temp_reg;
uint8_t i;
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(outdiv1) | SIM_CLKDIV1_OUTDIV2(outdiv2)
| SIM_CLKDIV1_OUTDIV3(outdiv3) | SIM_CLKDIV1_OUTDIV4(outdiv4);
// wait for dividers to change
for (i = 0 ; i < outdiv4 ; i++)
{}
FMC->PFAPR = temp_reg; // re-store original value of FMC_PFAPR
return;
} // set_sys_dividers
MDK确实对K60支持太差了,那么IAR呢?开始FSL的FAE让我下载网上的最新IAR例子,说只要修改K60_tower.h,将其中的PLL96改为PLL100就OK,事实如此吗?这是FAE的回信。
I would recommend customer to download Kinetis example project from below link:
KINETIS512_SC : Kinetis family example projects
http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=TWR-K60N512-KIT&fpsp=1&tab=Design_Tools_Tab
Customer could modify #define CORE_CLK_MHZ PLL100 in <k60_tower.h> file to set PLL run at 100MHz.
If customer use K60 tower example, which is using external 50MHz external clock as PLL reference clock.
实际上,打开下载的触摸按键例子(很多同学找不到这个好玩的例子,这下有了,我也是找了半天),这样修改后同样不能运行。看来K60确实太新了,FSL的FAE也不太清楚情况。只有自己想办法了,仔细分析,原来,还需要修改一些东西,主要是分频比部分,这部分在MCG.c中的pll_init函数中,我修改成了如下的样子:
unsigned char pll_init(unsigned char clk_option, unsigned char crystal_val)
{
unsigned char pll_freq;
if (clk_option > 3) {return 0;} //return 0 if one of the available options is not selected
if (crystal_val > 15) {return 1;} // return 1 if one of the available crystal options is not available
//This assumes that the MCG is in default FEI mode out of reset.
#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
// 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 */
#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
#if (defined(K60_CLK))
MCG_C5 = MCG_C5_PRDIV(0x13); //50/20=2.5Mhz modify by leequng
#else
// 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
#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;
// 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
set_sys_dividers(0,0,0,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)
pll_freq = 50;
break;
case 1:
// Set system options dividers
//MCG=PLL, core = MCG, bus = MCG/2, FlexBus = MCG/2, Flash clock= MCG/4
set_sys_dividers(0,1,1,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(16); //VDIV = 16 (x40) //modify by leequng
pll_freq = 100;
break;
case 2:
// Set system options dividers
//MCG=PLL, core = MCG, bus = MCG/2, FlexBus = MCG/2, Flash clock= MCG/4
set_sys_dividers(0,1,1,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)
pll_freq = 96;
break;
case 3:
// Set system options dividers
//MCG=PLL, core = MCG, bus = MCG, FlexBus = MCG, Flash clock= MCG/2
set_sys_dividers(0,0,0,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)
pll_freq = 48;
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
return pll_freq;
} //pll_init
编译,下载,OK,一切正常了,拔掉J6,程序停止运行,插上就恢复,证明系统正使用外部50Mhz有源振荡器。
另外要注意的就是,CMSIS 的DSP LIB 2.0也存在BUG,在程序中没有判断大小端,在小端模式下,很多矩阵运算的结果直接变成0.我下载了 cmsis 2.1,一切OK,我看源代码中,加入了大小端得编译控制宏语句,2.0的库源代码中就没有。
这是我拿到板子2周摸索出来的结果,总的来说,作为新出来的芯片,软件方面很不完善。另外,如果你不能用到想矩阵乘法、除法、滤波、FFT等一类的能使用DSP加速指令,他就是一个主频稍高的M3。我测试了矩阵运算,使用DSP库,9万次乘法和累加,大概耗时4.7ms,75Mhz的M3,大概耗时在28ms,加速效果不错,这多归于DSP指令功劳。当然,他的TSI不错,手一划过,灯全熄灭了,再一划全开,有点IPAD的感觉,呵呵。
写出这些,希望对大家有帮助。感觉K60真的很难搞,估计等到软件完善需要一段时间了。
其实我觉得ST的做法比较好,他家的驱动太完善了,至少,你不需要很仔细的研究硬件,凭借他的库函数,你就可以把所有设备轻松的初始化,搭建好软件平台,而开发者的主要精力可以放在应用上而不是研究厂家的硬件结构上面。