06_I.MX6ULL主频时钟配置实验

  • Post author:
  • Post category:其他



目录


系统时钟来源


7路PPL时钟源


时钟树简介


系统主频配置


PFD时钟设置


AHB、IPG和PERCLK根时钟设置


实验源码


系统时钟来源



从图









可以看出I.MX6U的系统时钟来源于两部分




:




32.768KHz和24MHz的晶振




,




其中 32.768KHz晶振是I.MX6的RTC时钟源




,




24MHz晶振是I.MX6内核和其它外设的时钟源








7路PPL时钟源




I.




MX6U的外设有很多,不同的外设时钟源不同, NXP将这些外设的时钟源进行了分组,一共有7组,这7组时钟源都是从24MHz晶振PLL而来的




,




因此也叫做7组PLL




,




这7组PLL结构如图




:



1.




ARM_PLL (PLL1),此路PLL是供ARM内核使用的, ARM内核时钟就是由此PLL生成的,此PLL通过编程的方式最高可倍频到1.3GHz








2.




528_PLL(PLL2),此路PLL也叫做System_PLL,此路PLL是固定的22倍频,不可编程修改。




因此,此路PLL时钟=24MHz * 22=528MHz,这也是为什么此PLL叫做528-PLL的原因。此 PLL分出了4路PFD,分别为: PLL2_PFDO-PLL2_PFD3,这4路PFD和528_PLL共同作为其它很多外设的根时钟源。通常528_PLL和这4路PFD是1.MX6U内部系统总线的时钟源,比如内处理逻辑单元、DDR接口、NAND/NOR接口等等。



3.




USB1_PLL(PLL3),此路PLL主要用于USBPHY,此PLL也有四路PFD,为:PLL3_PFDO~PLL3_PFD3




,




USB1_PLL是固定的20倍频




,



因此USB1_PLL=24MHz*20=480MHz。USB1_PLL 虽然主要用于USB1PHY




,




但是其和四路PFD同样也可以作为其他外设的根时钟源。



4.




USB2_PLL(PLL7,没有写错!就是PLL7,虽然序号标为4,但是实际是PLL7),看名字就知道此路PLL是给USB2PHY使用的。同样的




,




此路PLL固定为20倍频




,




因此也是480MHz








5.




ENET_PLL(PLL6),此路PLL固定为20+5/6 倍频,因此 ENET_PLL=24MHz * (20+5/6),= 500MHz。此路PLL用于生成网络所需的时钟,可以在此PLL的基础上生成25/50/100/125MHz的网络时钟。



6.




VIDEO_PLL(PLL5),此路PLL用于显示相关的外设,比如LCD,此路PLL的倍频可以调整, PLL的输出范围在650MHz-1300MHz。此路PLL在最终输出的时候还可以进行分频,可选 1/2/4/8/16分频。



7.




AUDIO-PLL(PLL4),此路PLL用于音频相关的外设,此路PLL的倍频可以调整, PLL的输出范围同样也是650MHz-1300MHz,此路PLL在最终输出的时候也可以进行分频,可选1/2/4分频。



时钟树简介




上面讲了PLL时钟,其实整个系统时钟逻辑是从24M的外部时钟源输入然后生成了7路的PLL时钟,PLL时钟又生成了PFD时钟源,PFD时钟源下面就是一些外设时钟源(PLL也可以作为外设时钟源)。



在图中一共有三部分: CLOCK_SWITCHER.CLOCK ROOT GENERATOR和SYSTEM CLOCKS。其中左边的CLOCK_SWITCHER就是那7路PLL和8路PFD,右边的SYSTEM CLOCKS就是芯片外设,中间的CLOCK ROOT GENERATOR是最”复杂的!这一部分就像




给农田浇灌一样,把PLL7路时钟源比喻成7个不同的水源




,给左边的CLOCK_SWITCHER和右边的SYSTEMCLOCKS进行




浇灌不同的水




。外设时钟源是有多路可以选择的




,




CLOCK ROOT GENERATOR就负责从7路PLL和8路PFD中选择合适的时钟源给外设使用。



系统主频配置


1.


内核时钟源来自于PLL1,假如此时PLL为996MHz。



2.




通过寄存器CCM_CACRR的ARM_PODF位对PLL1进行分频




,




可选择1/2/4/8分频




,




假如我们选择2分频,那么经过分频以后的时钟频率是996/2=498MHz。



3.




大家不要被此处的2分频给骗了,此处没有进行2分频(我就被这个2分频骗了好久,主频一直配置不正确!)。



4.




经过第




2




步2分频以后的498MHz就是ARM的内核时钟




,




也就是I.MX6U的主频。经过上面几步的分析可知,假如我们要设置内核主频为528MHz,那么PLL1可以设置为1056MHz,寄存器CCM-CACRR的ARM-PODF位设置为2分频即可。同理,如果要将主频设置为696MHz,那么PLL1就可以设置为696MHz, CCM_CACRR的ARM_PODF设置为1分频即可。现在问题很清晰了,寄存器CCM_CACRR的ARM_PODF位很好设置, PLL1的频率可以通过寄存器CCM_ANALOG_PLL_ARMn来设置。接下来详细的看一下CCM_CACRR和CCM_ANALOG_PLL_ARMn 这两个寄存器



CCM_CACRR寄存器结构如图




:



寄存器CCM_CACRR只有ARM_PODF位,可以设置为0-7,分别对应1~8分频。如果要设置为2分频的话CCM_CACRR就要设置为1。



再来看一下寄存器CCM_ANALOG_PLL_ARMn,此寄存器结构如图示




:



在寄存器CCM_ANALOG_PLL_ARMn中重要的位如下




:




输出。




ENABLE:时钟输出使能位,此位设置为1使能PLL1输出,如果设置为0的话就关闭PLL1DIV_SELECT:此位设置PLL1的输出频率,可设置范围为: 54~108, PLLI CLK= Fin *div_seclec/2.0, Fin=24MHz。如果PLL1要输出1056MHz的话, div_select就要设置为88。在修改PLL1时钟频率的时候我们需要先将内核时钟源改为其他的时钟源




,




PLL1可选择的时钟源如图示




:

1.


pll




1_




sw




_




clk也就是PLL1的最终输出频率








2.




此处是一个选择器,选择pll1_sw_clk的时钟源,由寄存器CCM_CCSR的PLL1_SW_CLK_SEL位决定plll_sw_clk是选择pll1_main_clk还是step_clk。




正常情况下应该选择pll1_main_clk,但是如果要对pll1_main_clk(PLL1)的频率进行调整的话,比如我们要设置PLL1=1056MHz,此时就要先将plll_sw_clk切换到step_clk上。等 plll_main_clk调整完成以后再切换回来。



3.




此处也是一个选择器




,




选择step_clk的时钟源




,




由寄存器CCM_CCSR的STEP_SEL位来决定step_clk是选择osc_clk还是secondary_clk。




一般选择osc_clk,也就是24MHz的晶振。



寄存器CCM_CCSR,此寄存器结构如图示:



寄存器CCM_CCSR我们只用到了STEP_SEL、PLLI_SW_CLK_SEL这两个位,一个是用,来选择step




_




clk时钟源的,一个是用来选择pll1




_




sw




_




clk时钟源的。



到这里




,




修改I.MX6U主频的步骤就很清晰了




,




修改步骤如下




:



1.




设置寄存器CCSR的STEP_SEL位




,




设置step_clk的时钟源为24M的晶振。



2.




设置寄存器CCSR的PLL1_SW_CLK_SEL位,设置plll_sw_clk的时钟源为step_clk=24MHz,通过这一步我们就将I.MX6U的主频先设置为24MHz




,




直接来自于外部的24M晶振。



3.




设置寄存器CCM_ANALOG_PLL_ARMn,将pll1_main_clk(PLL1)设置为1056MHz。



4.




设置寄存器CCSR的PLLI SW CLK SEL位,重新将pll1 sw clk的时钟源切换回pll1




_




main




_




clk,切换回来以后的pll




1_




sw_clk就等于1056MHz。



5.




最后设置寄存器CCM_CACRR的ARM_PODF为2分频, I.MX6U的内核主频就为1056/2=528MHz。



PFD时钟设置




设置好主频以后还需要设置好其他的P




LL




和P




F




D时




钟,




PLL2、 PLL3和PLL7固定为528MHz、 480MHz和480MHz, PLL4-PLL6都是针对特殊外设的,用到的时候再设置。因此,接下来重点就是设置PLL2和PLL3的各自4路PFD, NXP推荐的这8路P




F




D频率



先设置PLL2的4路PFD频率,用到寄存器是CCM_ANALOG_PFD_528n,寄存器结构如图示:



从图可以看出,寄存器CCM




_




ANALOG




_




PFD




_




528n其实分为四组,分别对应PFD




0




-PFD3




,




每组8个bit,我们就以PFD




0




为例




,




看一下如何设置PLL2_PFD




0




的频率。PFD




0




对应的寄存器位如下




:



PFDO_FRAC: PLL2_PFD




0




的分频数, PLL2_PFD




0




的计算公式为528*18/PFDO_FRAC




,




此为可设置的范围为12-35。




如果PLL2_PFD




0




的频率要设置为352MHz的话PFD




0_




FRAC




=




528*18/352




=




27



PFDO_STABLE




:




此位为只读位




,




可以通过读取此位判断PLL2_PFD




0




是否稳定。



PFDO_CLKGATE




:




PLL2_PFD




0




输出使能位




,




为1的时候关闭PLL2_PFD




0




的输出




,




为0 的时候使能输出。



如果我们要设置PLL2_PFD




0




的频率为352MHz的话就需要设置PFD




0




_FRAC为27




,




PFDO_CLKGATE为0。



PLL2_PFD1-PLL2_PFD3设置类似


,


频率计算公式都是528*18/PFDX FRAC(X=1~3)


,


因此PLL2_PFD1=594MHz的话


,


PFD1_FRAC=16;



PLL2_PFD2=400MHz的话 PFD2_FRAC不能整除




,




因此取最近的整数值




,




即PFD2_FRAC=24




,




这样PLL2




_




PFD2实际为396MHz: PLL2




_




PFD3




=




297MH的话, PFD3




_




FRAC




=




32








接下来设置PLL3_PFD




0~




PLL3_PFD3这4路PFD的频率




,




使用到的寄存器是CCM




_




ANALOG




_




PFD_480n,此寄存器结构如图示:



从图可以看出,寄存器CCM_ANALOG_PFD_480n和CCM_ANALOG_PFD_528n的结构是一模一样的,只是一个是PLL2的,一个是PLL3的。寄存器位的含义也是一样的,只是频率计算公式不同




,




比如PLL3_PFDX=480*18/PFDX_FRAC(X=0-3)。如果PLL3_PFDO=720MHz 的话




,




PFDO_FRAC=12




;




如果PLL3_PFD1=540MHz的话




,




PFD1_FRAC=16;如果 PLL3_PFD2=508.2MHz的话




,




PFD2_FRAC=17




;




如果PLL3_PFD3=454.7MHz的话




,




PFD3_FRAC=19








AHB、IPG和PERCLK根时钟设置




7路PLL和8路PFD设置完成以后最后还需要设置AHB_CLK_ROOT和IPG_CLK_ROOT的时钟




,




I




.




MX




6U




外设根时钟可设置范围如示




:



图给出了大多数外设的根时钟设置范围, AHB_CLK_ROOT最高可以设置132MHz,IPG_CLK_ROOT和PERCLK_CLK_ROOT最高可以设置66MHz。那我们就将AHB_CLK_ROOTIPG_CLK_ROOT 和 PERCLK_CLK_ROOT分别设置为132MHz、 66MHz、 66MHz。AHB CLK ROOT 和IPG CLK ROOT 的设计如图所示:

1.


此选择器用来选择pre_periph_clk的时钟源,可以选择PLL2、PLL2_PFD2、PLL2_PFD




0




和PLL2_PFD2/2。寄存器CCM_CBCMR的PRE_PERIPH_CLK_SEL位决定选择哪一个,默认选择PLL2




_




PFD2,因此pre




_




periph




_




clk




=




PLL2




_




PFD2




=




396MHz








2.




此选择器用来选择 periph_clk的时钟源




,




由寄存器CCM_CBCDR的PERIPH_CLK_SEL位与 PLL_bypass_en2组成的或来选择。




当CCM_CBCDR的PERIPH_CLK_SEL位为0的时候periph clk




=




pr




_




periph




_




clk=396MHz。



3.




通过CBCDR的AHB-PODF位来设置”AHB_CLK_ROOT的分频值,可以设置1-8分频




,




如果想要AHB_CLK_ROOT=132MHz的话就应该设置为3分频: 396/3=132MHz。图中虽然写的是默认4分频




,




但是I.MX6U的内部boot rom 将其改为了3分频




!



4.




通过CBCDR的IPG_PODF位来设置IPG_CLK_ROOT的分频值




,




可以设置1-4分频




,




IPG_CLK_ROOT时钟源是AHB_CLK_ROOT,要想IPG_CLK_ROOT=66MHz的话就应该设置2分频




:




132/2=66MHz。



最后要设置的就是PERCLK_CLK_ROOT时钟频率




,




其时钟结构图如图所示




:



从图可以看出, PERCLK_CLK_ROOT来源有两种:




OSC(24MHz)和IPG_CLK_ROOT,由寄存器 CCM_CSCMR1的PERCLK_CLK_SEL位来决定




,




如果为




0




的话PERCLK_CLK_ROOT的时钟源就是IPG_CLK_ROOT=66MHz。可以通过寄存器CCM_CSCMR1的PERCLK_PODF位来设置分频




,




如果要设置PERCLK_CLK_ROOT为66MHz的话就要设置为1分频。



寄存器CCM_CBCDR各个位的含义如下




:



PERIPH_CLK2_PODF




:




periph2 时钟分频




,




可设置0-7




,




分别对应1~8分频。



PERIPH2_CLK_SEL:选择peripheral2的主时钟,如果为0的话选择PLL2,如果为1的话选择 periph2_clk2_clk。修改此位会引起一次与MMDC的握手




,




所以修改完成以后要等待握手完成,握手完成信号由寄存器CCM CDHIPR中指定位表示。



PERIPH_CLK_SEL: peripheral主时钟选择,如果为0的话选择PLL2,如果为1的话选择 periph_clk2_clock。




修改此位会引起一次与 MMDC 的握手,所以修改完成以后要等待握手完成,握手完成信号由寄存器CCM_CDHIPR中指定位表示。



AXI-PODF: axi时钟分频,可设置0-7,分别对应1-8分频。



AHB_PODF




:




ahb时钟分频




,




可设置0~7




,




分别对应1~8分频。修改此位会引起一次与MMDC的握手




,




所以修改完成以后要等待握手完成,握手完成信号由寄存器CCM_CDHIPR中指定位表示。



PERIPH_CLK_SEL: peripheral主时钟选择,如果为0的话选择PLL2,如果为1的话选择 periph_clk2_clock。




修改此位会引起一次与MMDC的握手




,




所以修改完成以后要等待握手完成,握手完成信号由寄存器CCM_CDHIPR中指定位表示。



AXI-PODF: axi时钟分频,可设置0-7,分别对应1-8分频。



AHB_PODF




:




ahb时钟分频




,




可设置0~7




,




分别对应1~8 分频。修改此位会引起一次与MMDC的握手




,




所以修改完成以后要等待握手完成,握手完成信号由寄存器CCM_CDHIPR中指定位表示。


IPG_PODF: ipg时钟分频,可设置0-3,分别对应1-4分频。



AXI_ALT_CLK_SEL




:




axi_alt时钟选择




,




为0的话选择PLL2_PFD2




,




如果为1的话选择PLL3




_




PFD1。



AXI_CLK_SEL: axi时钟源选择,为0的话选择|periph_clk,为1的话选择axi_alt时钟。



FABRIC_MMDC_PODF: fabric/mmdc时钟分频设置,可设置0-7,分别对应1~8分频。



PERIPH2_CLK2_PODF: periph2_clk2 的时钟分频,可设置 0~7,分别对应 1~8 分频。



寄存器CCM_CBCMR寄存器结构如图所示




:



寄存器CCM_CBCMR各个位的含义如下




:



LCDIF1_PODF




:




ledifl的时钟分频




,




可设置0~7




,




分别对应1~8分频。



PRE_PERIPH2_CLK_SEL:pre_periph2时钟源选择




,




00选择PLL2,01选择PLL2_PFD2,10选择PLL2_PFD




0




,11选择PLL4。



PERIPH2_CLK2_SEL




:




periph2_clk2时钟源选择为0的时候选择pll3_sw_clk




,




为1的时候选择 OSC。



PRE-PERIPH_CLK_SEL: pre-periph时钟源选择, 00选择PLL2, 01选择PLL2-PFD2, 10选择PLL2_PFD




0




,11选择PLL2_PFD2/2。



PERIPH_CLK2_SEL




:




peripheral_clk2时钟源选择




,




00选择pll3_sw_clk




,




01选择osc_clk




,




10选择 pll2_bypass_clk。



寄存器CCM_CSCMR1




,




寄存器结构如图所示




:



此寄存器主要用于外设时钟源的选择,比如QSPI1、ACLK、GPMI、BCH等外设,我们重点看一下下面两个位:



PERCLK_CK_SEL




:




perclk时钟源选择




,




为0的话选择ipg




_




clk




,




为1的话选择osc




clk。



PERCLK_PODF




:




perclk的时钟分频




,




可设置




0




~7




,




分别对应1~8分频。

实验源码

#include "bsp_clk.h"
/*
 * @description	: 使能I.MX6U所有外设时钟
 * @param 		: 无
 * @return 		: 无
 */
void clk_enable(void)
{
	CCM->CCGR0 = 0XFFFFFFFF;
	CCM->CCGR1 = 0XFFFFFFFF;
	CCM->CCGR2 = 0XFFFFFFFF;
	CCM->CCGR3 = 0XFFFFFFFF;
	CCM->CCGR4 = 0XFFFFFFFF;
	CCM->CCGR5 = 0XFFFFFFFF;
	CCM->CCGR6 = 0XFFFFFFFF;
}


/*
 * @description	: 初始化时钟
 * @param 		: 无
 * @return 		: 无
 */
void imx6u_clkinit(void)
{
	uint16_t reg = 0;

	/*初始化6u的主频为528MHz*/
	if (((CCM->CCSR >>2) & 0x01) == 0)/*当前时钟使用pll1_main_clk也就是PLL1*/
	{
		/*系统时钟切换*/
		CCM->CCSR &= ~(1 << 8); /*设置step_clk = osc_clk = 24M*/
		CCM->CCSR |= (1 << 2);  /*pll1_main_clk = step_clk = 24M*/
	}

	/*设置PLL1 = 1056MHZ*/
	CCM_ANALOG->PLL_ARM = (88 & 0x7f); /*24M*88=1056M*/
	CCM_ANALOG->PLL_ARM |= (1<<13);    /*时能时钟*/
	CCM->CACRR = 1;  /*1056/2=528Mhz*/

	/*切换为528MHz*/
	CCM->CCSR &= ~(1 << 2);/*将pll_sw_clk时钟切换回pll1_main_clkk = 1056/2=528Mhz*/

	/*设置PLL2的4路PFD*/
	reg = CCM_ANALOG->PFD_528;

	reg &= ~(0x3F3F3F3F);
	reg	|= (32 << 24);				/* PLL2_PFD3=297MHZ*/
	reg	|= (24 << 16);				/* PLL2_PFD2=396MHZ*/	
	reg	|= (16 << 8);				/* PLL2_PFD1=594MHZ*/
	reg	|= (27 << 0);				/* PLL2_PFD0=352MHZ*/
	CCM_ANALOG->PFD_528 = reg;

	/*设置PLL3的4路PFD*/
	reg = 0;
	reg = CCM_ANALOG->PFD_480;
	reg &= ~(0x3F3F3F3F);
	reg	|= (19 << 24);				/* PLL3_PFD3=454.7MHZ*/
	reg	|= (17 << 16);				/* PLL3_PFD2=508.2MHZ*/	
	reg	|= (16 << 8);				/* PLL3_PFD1=5540MHZ*/
	reg	|= (12 << 0);				/* PLL3_PFD0=720MHZ*/
	CCM_ANALOG->PFD_480 = reg;

	/*设置AHB_ROOT=132MHz*/
	CCM->CBCMR &= ~(3 << 18);
	CCM->CBCMR |= 1 << 18; /*pre_periph clock=PLL2_PFD2=396MHz*/
	CCM->CBCDR &= ~(1 << 25 );/*选择396MHz这条通道*/
	while(CCM->CDHIPR & (1 << 5));/*等待握手信号完成*/
	
	/*内部boot 已经设置好*/
//	CCM->CBCDR &= ~(7 <<10 );
//	CCM->CBCDR |= (2 <<10 ); /*396MHz/3=132M*/
//	while(CCM->CDHIPR & (1 << 1));/*等待握手信号完成*/

	/*设置IPG_CLK_ROOT最小3Mhz最大66Mhz*/
	CCM->CBCDR &= ~(3 << 8 );
	CCM->CBCDR |= (1 << 8 );  /*IPG_CLK_ROOT=AHB_CLK_ROOT/2=132/2=66MHz*/
	
	/*设置PERCLK_CLK_ROOT时钟66Mhz*/
	CCM->CSCMR1 &= ~(1 << 6); /* PERCLK_CLK_ROOT时钟源为IPG */
	CCM->CSCMR1 &= ~(0x3F << 0); /*1分频 */

}



版权声明:本文为Yuanghxb原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。