MCG成为多用途时钟信号发生器,该模块为MCU和芯片内部各个模块提供时钟信号。MCG模块通过对输入的参考时钟进行分频和倍频处理,可以输出各种频率的时钟信号,并达到超频运行的目的。输入的参考时钟可以来自内部也可以来自外部时钟或外部晶振。输入的参考时钟一般经过分频后进入FLL(锁频环)或PLL(锁相环)进行倍频处理,当然也可以不通过FLL或PLL,而直接输出给各个模块。一般情况下,我们会选择外部晶振的参考时钟,分频后由PLL倍频的方法来达到超频运行的目的。
MCG模块框图如图1.1所示。
图1.1 MCG模块框图
MCG的核心是一个FLL(锁频环)和一个PLL(锁相环)。FLL和PLL都可以对输入的参考时钟倍频并锁定后输出,输出的时钟在SIM模块的控制下提供给CPU和各个模块。锁频环FLL的核心是一个DCO(数字控制振荡器),锁相环PLL的核心是一个VCO(电压控制振荡器)。如图1.2所示。
注意:MCG模块可输出多个时钟,比如MCGFFCLK、MCGPLLCLK、MCGOUTCLK等,详见图1.1。这些时钟可以为其它模块提供更多的时钟选择。在这些时钟中,最主要的是MCGOUTCLK。这个时钟是核心时钟、总线时钟、FLASH时钟的时钟来源。我们要实现PLL超频最终得到的也是MCGOUTCLK。
图1.2 MCG模块
不同的参考时钟,以及不同的对参考时钟的处理方式的组合,使得MCG模块有9种不同的工作模式。9种模式及相互之间的转换如图1.3所示。
图1.3 MCG模块的工作模式及相互转换
这9种模式我们未必都用到,一般情况下,我们都会使用PEE模式,PEE模式是选择外部晶振经过PLL倍频后输出时钟,可以达到较高的时钟频率。而上电复位后,MCG工作在FEI模式下。我们必须通过设置相关的寄存器,实现FEI到FBE的转换,再由FBE转换到PBE,最后再转换到PEE。下面我们就介绍一下我们用到的几种模式及在转换过程中用到的寄存器。
Bit |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
Read |
CLKS |
FRDIV |
IREFS |
IRCLKEN |
IREFSTEN |
|||
Write |
||||||||
Reset |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
图1.4 MCG_C1寄存器
CLKS:时钟源选择。该位用于选择MCG的输出时钟MCGOUTCLK从何而来。在MCG的模式转换过程中,每一步都牵涉到CLKS的设置。注意,每次改变CLKS,输出的时钟并不是马上发生变化,而是有一个过程,必需查询相关的标志位以确保转换完成才能进行下一步设置,需查询的相关标志位在MCG_S寄存器中,有关该寄存器的内容稍后介绍。
图1.5 CLKS选择输出时钟
CLKS选择时钟如表1.1所示
CLKS |
描述 |
00 |
选择PLL或FLL输出 |
01 |
选择内部参考时钟 |
10 |
选择外部参考时钟 |
11 |
保留,缺省为00 |
表1.1CLKS选择输出时钟
FRDIV:锁频环FLL外部参考分频。当FLL的输入参考时钟来自外部晶振时,可通过设置FRDIV对这个来自晶振的参考时钟分频。分频后的时钟可以提供给FLL再倍频,并且这个时钟也可以提供给MCGFFCLK输出。对于有些模块,比如FTM,MCGFFCLK也是可供选择的一个时钟选项。FRDIV的分频系数和外部晶振的频率范围有关,频率范围在MCG_C2寄存器中的RANGE设置。
RANGE=0,分频比=2^FRDIV(FRDIV<=7),如果外部晶振RANGE!=0,则分频比=2^(FRDIV+5)。
注意:分频后提供给FLL倍频的参考时钟不得超过32K。
IREFS:FLL参考时钟源选择。FLL对输入的参考时钟倍频,而这个参考时钟可以来自芯片自带的内部慢速参考时钟,速率为32k,也可以来自外部晶振经由FRDIV设置的分频比分频后的时钟。选择哪一个输入到FLL由IREFS设置。
IREFS=0:选择外部时钟;
IREFS=1: 选择内部慢速参考时钟源。
注意,上电复位时,IREFS默认为1,即FLL对32K内部慢速时钟倍频后输出。
IRCLKEN、IREFSTEN:前面提到,MCG模块有多个时钟输出,其中一个就是MCGIRCLK,这个时钟来自于芯片内部自带的参考时钟,这个时钟也可以提供给某些模块作为时钟选项。IRCLKEN和IREFSTEN就是和这个时钟有关。如图1.6所示。如需要这个时钟,可设置IRCLKEN=1,如希望在停止模式下,该时钟也可以使用,则可设置IREFSTEN=1。在超频过程中,这两位可暂时忽略。
图1.6 MCGIRCLK输出设置
图1.7 MCG_C2寄存器
RANGE:晶振频率范围选择,用于为使用的外部晶振选择频率范围,具体如表1.2所示
RANGE
描述
00
为晶振选择低频范围1K~32K
01
为晶振选择高频范3M~8M
1X
为晶振选择甚高频范围8M~32M
表1.2 RANGE选择
注意:一般情况下,如果使用32K晶振,则可选择RANGE=00,如晶振频率为3~32MHz,则可选择RANGE=01,如果使用更高频率的晶振,则可选择RANGE=1X。
HGO:高增益振荡器选择
HGO=0:设置晶振为低功耗操作;
HGO=1:设置晶振为高增益操作。
EREFS:外部参考选择。来自外部的时钟信号可以是外部直接输入的时钟脉冲,或来自晶体振荡器,可通过EREFS选择。
EREFS=0:外部参考时钟;
EREFS=1:外部振荡器。
注意:一般情况下,我们使用都是外部晶振,该位置1即可。
LP:低功耗选择,用于选择在bypass等模式下,FLL和PLL是否工作,主要出于省电考虑,超频过程中,该位可暂不考虑,默认即可。
IRCS:内部参考时钟选择。如果我们选择把芯片自带的内部时钟作为MCGOUTCLK输出,即设置MCG_C1寄存器中的CLKS=01,则有两个选择,一个是32K的慢速时钟,一个是2M的快速时钟,由IRCS选择。在PLL超频过程中,该位可忽略。
IRCS=0:选择慢速内部参考时钟;
IRCS=1:选择快速内部参考时钟。
图1.8 MCG_C5寄存器
PLLCLKEN:PLL时钟使能。MCGPLLCLK也是MCG模块输出的一个时钟选项。如果要使能这个时钟输出,则设置PLLCKEN=1即可。PLLCLKEN和我们要超频输出的MCGOUTCLK无关,在PLL超频过程中可忽略。如果使用MCGPLLCLK的话,需要注意,置位PLLCLKEN之前,PRDIV需要设置合适的分频系数以产生2~4M的PLL参考时钟,置位PLLCLKEN将使能外部振荡器。每次置位PLLCLKEN使能PLL时钟,并且外部振荡器作为参考时钟,都需要检查OSCINIT位。
PLLSTEN:设置stop模式下,PLL是否使能。PLL超频过程中,该位可忽略。
PRDIV:PLL外部参考时钟分频。我们选择外部晶振作为参考时钟输入到PLL时,需要先分频到2~4MHz的范围内才可以由PLL倍频后输出。PRDIV就是设置对外部时钟的分频系数。
分频系数=PRDIV+1,注意PRDIV<=24。
注意:通过设置PRDIV,结果频率应在2M~4M范围内,当PLL使能,即将PLLCLKEN置1后,在锁相环PLL未锁定频率之前,不可改变PRDIV的值。
图1.9 MCG_C6寄存器
LOLIE:当时钟失去锁定时,是否发生中断请求。
LOLIE=0:禁止中断请求;
LOLIE=1:允许中断请求。
PLLS:PLL选择,选择PLL还是FLL作为MCG的时钟源。当CLKS[1:0]=00时,我们可以选择MCGOUTCLK来自PLL或者FLL。到底是PLL还是FLL则由PLLS指定。
PLLS=0:选择FLL;
PLLS=1:选择PLL,设置PLLS之前,需要设置合适的PRDIV以产生2~4M的参考时钟。
CME:时钟监控使能,设置当失去外部时钟时,是否产生中断。
VDIV:PLL压控振荡器倍频系数,VDIV决定参考时钟的倍数。当我们最终选择PLL倍频后输出到MCGOUTCLK时,需要设置VDIV得到我们需要的时钟频率。
倍数=VDIV+24,且VDIV<=31。
注意:PLL最大55倍频,参考时钟最大4MHz,也就是PLL超频最高到220MHz。
这个寄存器中包含反映MCG状态的标志位,供程序查询。在MCG的模式转换过程中,我们必须查询该寄存器中的某些标志位以确保转换完成。
1.10 MCG_S寄存器
LOLS:该位反映锁相环的锁定状态,失锁时置 1,写1清除,该位置1时,由MCG_CR6中的LOLIE决定是否产生中断。
LOCK:该位置1表示锁相环已经锁定。在锁定过程中,MGC的PLL时钟被禁止输出,直到LOCK置位。LOCK置位后,任何改变PRDIV或VDIV的操作都会清除LOCK位直到再次锁定频率。
PLLST:该位指示,PLLS的时钟源是来自FLL时钟还是PLL时钟。当我们改变PLLS在PLL和FLL时钟之间切换时,时钟输出的变化需要查询该位以确保切换完成。
PLLST=0:FLL时钟;
PLLST=1:PLL时钟。
IREFST:FLL内部参考时钟状态。当我们改变IREF,对FLL的参考时钟的来源切换时,需要查询该位以确保切换完成才可进行下一步。
IREFST=0:FLL参考时钟来自外部;
IREFST=1:FLL参考时钟来自内部。
CLKST:指示当前的时钟模式。当我们改变CLKS,改变MCGOUTCLK的时钟来源时,需要查询该位以确保切换完成才可进行下一步。
CLKST=00:选择FLL输出;
CLKST=01:选择内部参考时钟;
CLKST=10:选择外部参考时钟;
CLKST=11:选择PLL输出。
OSCINT:晶振初始化状态,该位置1表示晶振完成初始化。
IRCST:内部参考时钟状态。如改变IRCS,则须查询该位,该位和PLL超频无关。
IRCST=0:选择慢速内部时钟,32K;
IRCST=1:选择快速内部时钟,2M。
MCG模块和PLL超频有关的寄存器都已经列出来,还有些寄存器和PLL超频无关,不做详细介绍,如想进一步了解可参考数据手册,K10P100M100SF2RM.pdf第24章。
如图1.3所示,我们必须通过设置相关的寄存器,实现FEI到FBE的转换,再由FBE转换到PBE,最后再转换到PEE。
FEI模式下,时钟的产生如图1.11所示。FEI是系统复位后MCG默认的工作模式,输出的时钟MCGOUTCLK来自FLL。FLL的参考时钟来自内部32K慢速时钟,FLL倍频后大约20MHz。
图1.11 FEI模式下时钟产生流程
FBE模式下,时钟的产生如图1.12所示。在FBE模式下,MCGOUTCLK来自外部参考时钟,此时,FLL仍正常工作,但是FLL的参考时钟输入从内部慢速时钟切换到外部时钟。此时FLL产生的时钟并不输出。
图1.12 FBE模式下时钟产生流程
从FEI到FBE的转换,主要改变的是MCGOUTCLK的来源从FLL切换到外部晶振,即MCG_C1寄存器的CLKS从00切换到10。同时FLL的参考时钟也从内部32K慢速时钟切换到晶振分频后的时钟,即MCG_C2寄存器中RANGE、HGO和EREFS都需要设置,而且MCG_C1寄存器中的FRDIV也需要合理设置以保证外部晶振分频后得到不大于32KHz的参考时钟提供给FLL。
以4MHz外部晶振为例,首先设置MCG_C2寄存器,代码如下:
MCG_C2 = MCG_C2_RANGE(1) | MCG_C2_HGO_MASK | MCG_C2_EREFS_MASK;
使用4MHz晶振,RANGE设置为1;HGO置1,选择高增益;EREFS置1,选择外部晶振。在这段代码中,大量采用系统自带的宏定义,具体和查询头文件MK10X256VMD100.h。使用系统自带的宏定义可防止自己计算二进制出错,当然,也可以不使用,宏定义,而直接定义:
MCG_C2=0X1C;
接下来设置,MCG_C1寄存器,代码如下:
MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(3);
CLKS设为10,选择外部参考时钟输出到MCGOUTCLK;FRDIV置为3,对4MHz晶振256分频。注意分频后的时钟只需要小于32KHz即可,由于FBE只是过渡状态,所以不必详细计算。同样,上面的代码我们也使用了系统自带的宏定义。
当设置完毕后,需查询MCG_S中的几个状态位以确保状态切换完成,才能进行后面的操作,查询状态位的代码如下:
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){} //等待MCGOUTCLK切换到外部时钟输出
PBE模式下,MCGOUTCLK输出时钟不变,仍然是外部晶振直接输出,所以MCG_C1中的CLKS不必改变。也就是PBE下的时钟产生和图1.2是一样的。但是,在这一步,我们开始启用PLL工作,并计算好我们需要超频的倍率。在PBE模式下,PLL虽然已正常工作,PLL的时钟并不输出。在这一步,我们只要设置MCG_C5和MCG_C6两个寄存器。
MCG_C5 = MCG_C5_PRDIV(1);//分频在2~4MHz之间,分频后频率2MHz MCG_C6 = MCG_C6_PLLS_MASK |MCG_C6_VDIV(26); //选择PLL,倍频50倍
这里我们需要设置好MCGOUTCLK提供给系统核心、总线和FLASH的时钟分频,通过SIM模块的SIM_CLKDIV1来设置,由MCGOUTCLK提供给几个主要模块的时钟分频比,分别是CORE、BUS、FLEXBUS、FLASH。注意FLASH模块不可超过25MHz,否则出错。
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0)| SIM_CLKDIV1_OUTDIV2(1) | SIM_CLKDIV1_OUTDIV3(1) |SIM_CLKDIV1_OUTDIV4(3); //MCG=PLL, core = MCG, bus = MCG/3,FlexBus = MCG/3, Flash clock= MCG/8
如按以上分频设置,当最终转换到FEE模式后,则系统核心频率为100MHz,BUS和FLEXBUS都为50MHz,FLASH为25MHz。
设置完毕后,需查询标志位以确保转换完成。代码如下:
while (!(MCG_S &MCG_S_PLLST_MASK)){}; // 等待切换到PLL while (!(MCG_S &MCG_S_LOCK_MASK)){}; //等待PLL锁定频率
在上面完成后,PLL输出的时钟已经准备完毕,只需要最后通过设置MCG_C1中的CLKS,把MCGOUTCLK的来源从外部晶振切换到PLL时钟即可。代码如下:
MCG_C1 &= ~MCG_C1_CLKS_MASK;//CLKS=00,PLL输出 while (((MCG_S & MCG_S_CLKST_MASK)>> MCG_S_CLKST_SHIFT) != 0x3){};//等待切换完毕。