时钟控制模块
锁相环电路简单的理解
https://www.bilibili.com/video/BV1yS4y1n7vV/?spm_id_from=333.337.search-card.all.click&vd_source=712cdb762d6632543eeeadb56271617a
一 时钟是从哪里来的
- 时钟晶振(32.768KHz)供给RTC使用
- 在IMX6ULL的T16和T17这两个IO上接了一个24MHz的晶振。
以上这些在原理图上没找到?
(用户手册p350)为了根据不同外设需要的时钟频率。芯片从24MHz晶振生出来7路PLL,有的PLL又会生成PFD
7路PLL分别为
PLL1:ARM PLL供给ARM内核
PLL2:system PLL,528MHz,528PLL,此路PLL分出了4路PFD,分别为PLL2_PFD0~PFD3
PLL3:USB1PLL,480MHz,480PLL,此路PLL分出了4路PFD,分别为PLL3_PFD0~PFD3
PLL4:Audio PLL,主攻音频使用
PLL5:Video PLL,主供视频外设,如RGB LCD接口,和图像处理有关的外设
PLL6:ENET PLL,主供网络外设
PLL7:USB2_PLL,480MHz,无PFD
二 时钟树
图上橙色梯形的为多路选择器,蓝色的/2和/8分频的数值是可以设置的,不是固定的。
三 要初始化的PLL和PFD
对于PLL1-PLL3以及对应的PFD是要初始化的。
对于要初始化的PLL和PFD要设置的时钟频率是多少那?
一般按照时钟树图表中的值,设置即可。对于图上的右边的外设的根时钟,例如EASI_CLK_ROOT的值,这些的值按照手册(P638)最大的频率设置即可。
设置PLL1输出时钟
根据图上此时PLL1位996MHz,经过CACRR[ARM_PODF]寄存器设置为2分频,此时ARM内核的主频就是996/2为498MHz。
此时若想设置ARM内核为528MHz,设置CACRR寄存器2分频,则PLL1需要为1056MHz,也要注意看下手册里PLL1的值,是否在范围内。
设置分频值
CACRR寄存器(手册p666)的bit0-3,为ARM_PODF位,可设置数字,0-7,即1-8分频。此处二分频设置ARM_PODF为1。
主频时钟的修改
由下图可知主频时钟的来自pll1_sw_clk,pll1_sw_clk的时钟来源有两路,分别是PLL1、step_clk。若要修改主频时钟,修改PLL1的值就可以了,但是在修改PLL1的值之前,pll1_sw_clk要临时使用step_clk时钟。
设置PLL1输出时钟
(手册P644)
由上图知,PLL1来自24MHz的参考时钟,PLL1的输出频率范围为650MHz-1.3GHz。PLL1的输出频率计算公式如下:
PLL output frequency = Fref*DIV_SEL/2
Fref参数:
Fref参数的值为24MHz
DIV_SEL的参数和CCM_ANALOG_PLL_ARM寄存器的DIV_SELECT(0-6bit)有关,见(手册715)如下图
看完上面的内容后。
1 设置PLL1=1056MHz。PLL1=pll1_sw_clk。pll1_sw_clk有两路来源,一路是pll1_main_clk,将CCSR寄存器的pll1_sw_clk_sel位置为1。另一路是,step_clk,将CCSR寄存器的pll1_sw_clk_sel置为0。
2 在修改PLL1的时候,也就是设置系统时钟的时候需要给IMX6ull一个临时的时钟,也就是step_clk。在修改PLL1的时候需要将pll1_sw_clk切换到step_clk。
3 设置step_clk。step_clk也有两路来源,由寄存器CCSR(手册P664)的step_sel位决定,为0使用osc_clk=24MHz,为1使用其他,这个暂时不考虑。
4 时钟切换成功以后就可以修改PLL1的值。
5 通过CCM_ANALOG_PLL_ARM寄存器(手册P714)的DIV_SELECT位(bit0-6)来设置PLL1的频率,设置公式为
Output = fref**DIV_SEL/2 ,1056 = 24*DIV_SEL/2 =>DIEV_SEL = 88
设置CCM_ANALOG_PLL_ARM寄存器(手册P714)的DIV_SELECT位=88即可。PLL1=105MHz。
还要设置这个寄存器的ENABLE位,使能。
6 在切换回PLL1之前,设置CACRR寄存器的ARM_PODF=1,设置成2分频,一定不要忘记先分频!!
/*初始化时钟*/
void imx6u_clkinit(void)
{/*初始化6U的主频为528MHz*//*CCM->CCSR 右移2位,就是pll1_sw_clk_sel位,若为1,说明使用的是pll1_main_clk*/if(((CCM->CCSR >> 2) & 0X1) == 0){/*使用osc_clk作为临时的时钟,先设置CCSR的step_sel位(bit8)为0,在设置CCSR的pll1_sw_clk_sel 位(bit2)为1*//*设置step_sel位为0*/CCM->CCSR &= ~(1<<8);/*设置pll_sw_clk_sel位为1*/CCM->CCSR |= (1<<2); }/*设置PLL1的频率为1056MHz*//*bit13为1,是使能PLL_ARM,bit0-6置为88*/CCM_ANALOG->PLL_ARM = (1<<13) | (88<<0 & 0x7f);/*设置CACRR寄存器分频值为2*/CCM->CACRR &= (1<<0);/*切换为PLL1,将CCSR的pll1_sw_clk_sel(bit2)位设置为0*/CCM->CCSR &= ~(1<<2);}
设置PLL2输出时钟
(手册645)
对于PLL2(System PLL)也来自24MHz的参考时钟,虽然也有分频DIV_SELECT(0bit)。但是PLL2默认输出频率设置为528MHz。
PLL2的使能,将上面的寄存器中bit13置为1即可。设置PLL2的输出频率为528MHz,将上面寄存器中bit0置为1,使用公式PLL2 = Fref*22 = 24*528。
设置PLL2的PFD输出
PFD的使能
查看寄存器CCM_ANALOG_PLL_SYS_SS(手册721页),通过使这个寄存器的ENABLE,可以使能PLL2的PFD。
PFD的使能,将上面寄存器的bit15置为1即可。
设置PFD的分频系数为0,将上面寄存器的bit0-29置为0即可。
PFD的输出频率
(手册P736)
寄存器CCM_ANALOG_PFD_528用于设置4路PFD的输出频率。
PFD相关的输出频率根据时钟树上的值设置即可,输出频率计算公式 PFD = 528*18/PFD0_FRAC 。
设置PFD0的输出频率为352MHz。
根据上面图片寄存器,PFD0_FRAC的值为27,设置bit5-0为0X1B
设置PFD1的输出频率为594MHz。
根据上面公式PFD1_FRAC的值应为16,设置bit13-8为0X10
设置PFD2的输出频率为400MHz。
根据上面公式PFD2_FRAC的值应为24,设置bit21-16为0X18
设置PFD3的输出频率为297MHz。
根据上面公式PFD3_FRAC的值应为32,设置bit29-24为0X20
设置PLL3(USB PLL) 输出时钟
(手册645)
PLL3来自24MHz的参考时钟,PLL3时钟的输出频率为480MHz。
设置PLL3的输出频率为480MHz,将上面寄存器的bit1-0置为1,即使用公式PLL3 out = 24*20=480
PLL3输出使能,将bit13置为1。
PLL3上电使能,将bit12置为1。
USBPHY使能,将bit6置为1。
PFD的输出频率
(手册734)
寄存器CCM_ANALOG_PFD_480用于设置4路PFD的输出频率。
PFD相关的输出频率根据时钟树上的值设置即可,输出频率计算公式 PFD = 480*18/PFD0_FRAC 。
设置PFD0的输出频率为720MHz。
根据上面图片寄存器,PFD0_FRAC的值为12,设置bit5-0为0XC
设置PFD1的输出频率为540MHz。
根据上面公式PFD1_FRAC的值应为16,设置bit13-8为0X10
设置PFD2的输出频率为508.2MHz。
根据上面公式PFD2_FRAC的值应为11,设置bit21-16为0XB
设置PFD3的输出频率为454.7MHz。
根据上面公式PFD3_FRAC的值应为19,设置bit29-24为0X13
四 其他外设时钟配置
这里我们设置PERCLK_CLK_ROOT、IPG_CLK_ROOT。由于这两个外设时钟的来源是AHB,所以设置这两个外设之前,先设置PERCLK_CLK_ROOT外设。
外设时钟频率该设置为多少
对于外设相关时钟输出频率值根据手册来设置(手册642)。
1 设置AHB_CLK_ROOT时钟
根据(手册p642)的参考值,设置AHB_CLK_ROOT频率为132MHz,根据时钟有多路来源,这里我们就选中其中一种进行设置。选择PLL2的PFD2输出频率为396MHz。
根据时钟树从左到右,我们需要操作的寄存器为CBCMR、CBCDR。
设置CBCMR寄存器(手册p669)的PRE_PERIPH_CLK_SEL位(bit18-19)为01,
设置多路选择CBCDR寄存器(手册p666)的PERIPH_CLK_SEL(bit25)为0,
设置CBCDR寄存器AHB_PODF位(bit10-12)为010,设置分频值3。
因此AHB_CLK_ROOT的输出频率为PFD2/3 即396/3=132MHz。
void AHB_CLK_ROOT_132(void)
{/*设置AHB_CLK_ROOT=132MHz*//*先将bit18-19位清0*/CCM->CBCMR &= ~(3<<18);/*设置bit18-19为1*/CCM->CBCMR |= (1<<18);/*bit25值为0*/CCM->CBCDR &= ~(1<<25);/*这里根据手册(手册)提示,操作此寄存器要等待握手信号*/while(CCM->CDHIPR & (1<<5));}
2 设置IPG_CLK_ROOT时钟
AHB时钟输出为132MHz已经设置好了。接下来设置CBCDR寄存器(手册p666)的IPG_PODF位(bit8-9)01,设置2分频,这里IPG_CLK_ROOT就完成了66MHz的输出。
void IPG_CLK_ROOT_66()
{ /*将bit8-9清0*/CCM->CBCDR &= ~(3 << 8);/*设置2分频*/CCM->CBCDR |= (1 << 8);
}
3 设置PERCLK_CLK_ROOT时钟
在设置IPG_CLK_ROOT时钟的时候已经设置CBCDR寄存器的IPG_PODF位,设置为2分频。所以现在这里是66MHz。
设置多路选择寄存器CBCMR(P669)的PRE_PERIPH_CLK_SEL位(bit18-19)为01,选择IPG_CLK_ROOT来源。
设置CSCMR1时钟PERCLK_PODF位(bit0-5)为0,1分频。这就完成了PERCLK_CLK_ROOT的时钟设置。
void PERCLK_CLK_ROOT_66()
{ /*先将bit6置为0,选择时钟源为IPG_CLK_ROOT*/CCM->CSCMR1 &= ~(1<<6);/*先将bit0-5清0,然后置为0,即设置分频值为1*/CCM->CSCMR1 &= ~(0X3F << 0);
}