学习笔记(二)Linux嵌入式裸机开发-时钟配置
IMX6ULL时钟介绍
对于开发板的各个外设均有对应的不同的时钟,通过时钟树我们就可以看到不同的外设与不同的时钟源
可以简单理解为最左边提供时钟源,中间多路选择器由进行分配,然后分配到最右边的不同外设上。PPL又会下分各种PFD时钟源。
时钟源涉及到的寄存器也有很多,并且各司其职,不同的时钟源有不同的用处。
这里简单描述一下各个作用(这里直接引用正点原子教程手册中内容):
①、 ARM_PLL(PLL1),此路 PLL 是供 ARM 内核使用的, ARM 内核时钟就是由此 PLL生成的,此 PLL 通过编程的方式最高可倍频到 1.3GHz。
②、 528_PLL(PLL2),此路 PLL 也叫做 System_PLL,此路 PLL 是固定的 22 倍频,不可编程修改。因此,此路 PLL 时钟=24MHz * 22 = 528MHz,这也是为什么此 PLL 叫做 528_PLL 的原因。此 PLL 分出了 4 路 PFD,分别为: PLL2_PFD0~PLL2_PFD3,这 4 路 PFD 和 528_PLL共同作为其它很多外设的根时钟源。通常 528_PLL 和这 4 路 PFD 是 I.MX6U 内部系统总线的时钟源,比如内处理逻辑单元、 DDR 接口、 NAND/NOR 接口等等。
③、 USB1_PLL(PLL3),此路 PLL 主要用于 USBPHY,此 PLL 也有四路 PFD,为:PLL3_PFD0~PLL3_PFD3, USB1_PLL 是固定的 20 倍频,因此 USB1_PLL=24MHz *20=480MHz。USB1_PLL虽然主要用于USB1PHY,但是其和四路PFD同样也可以作为其他外设的根时钟源。
④、 USB2_PLL(PLL7,没有写错!就是 PLL7,虽然序号标为 4,但是实际是 PLL7),看名字就知道此路PLL是给USB2PHY 使用的。同样的,此路PLL固定为20倍频,因此也是480MHz。
⑤、 ENET_PLL(PLL6),此路 PLL 固定为 20+5/6 倍频,因此 ENET_PLL=24MHz * (20+5/6)= 500MHz。此路 PLL 用于生成网络所需的时钟,可以在此 PLL 的基础上生成 25/50/100/125MHz的网络时钟。
⑥、 VIDEO_PLL(PLL5),此路 PLL 用于显示相关的外设,比如 LCD,此路 PLL 的倍频可以调整, PLL 的输出范围在 650MHz~1300MHz。此路 PLL 在最终输出的时候还可以进行分频,可选 1/2/4/8/16 分频。
⑦、 AUDIO_PLL(PLL4),此路 PLL 用于音频相关的外设,此路 PLL 的倍频可以调整, PLL的输出范围同样也是 650MHz~1300MHz,此路 PLL 在最终输出的时候也可以进行分频,可选1/2/4 分频。
那么想要操作时钟就很简单了,只需要选择表上你想要操作的外设,然后找到它的参考手册里对应的寄存器,再把中间的线路寄存器选择好就行,类似于左右连线,作为操作者我们需要把时钟源与外设按照时钟树连接好即可。具体选择哪些需要根据时钟树与参考手册进行设置。但是各个时钟也是有限制范围的不可以随意设置频率,在参考手册有更具体的推荐范围,切勿超过阈值修改频率,这样会造成损坏。
更改主时钟频率
这里详细介绍一下如何修改主时钟,也就是时钟树最上面的ARM_CLK_ROOT的频率值,通过时钟树可以看出来,他是由PLL1经过一个寄存器进行二分频后直接得出,灰色部分表示可进行也可不进行二分频的寄存器所以忽略。
这里还有一个小点需要注意,主时钟频率相当于系统的心脏需要时刻运行,当我们修改主时钟频率时需要给他先换上备用心脏,等主心脏调好后再给她换回来。
通过上面两个原理图我们道理已经理解了,如果我们要修改主时钟频率到528Mhz的话,PLL1 CLK = Fin *
div_seclec/2.0, Fin=24MHz。 PLL1 要输出 1056MHz 。大概的意思就是:
1.修改CCSR->step_sel寄存器切换到备用时钟
2.修改PPL1为1056Mhz
3.修改CACRR寄存器到二分频
4.接回主时钟
通过上面四步就可以把主时钟频率调到528Mhz了
这里我直接把相关寄存器的参考手册部分贴出来,在编写代码时我们需要自行在参考手册里寻找关键词来查看寄存器配置哪一位来实现各种功能:
上图为CCSR寄存器第八位控制时钟来源
上图前七位配置PLL频率,计算公式为Fout=Fin*div_select/2,div_select范围为54-108,根据我们的需求可以算出来需要写入88
上图可以看到若想要二分频只需要在前三位写入001
通过上面几步之后,最后我们把时钟切换回主时钟就可以实现主时钟频率为528Mhz啦。
更改多路PPL与PFD等其他时钟源配置
其他的时钟配置和上述的主时钟配置基本相同,其他的不需要选用备用时钟,直接操作即可。相比主时钟更简单了,但是时钟树上的连接线更繁琐了,我们只要专注观察线的颜色,从右往左依次链接,再把链接路上的寄存器查找参考手册一个一个配置好即可。这里简单描述一下AHB_CLK_ROOT的配置路线,注意观察图中我画红线的部分
按照我图上的画法,依次配置PFD2的频率值(也就是CCM_ANALOG_PLL_528n寄存器)CSCMR的PRE_RERIPG_CLK_SEL位,CBCDR的PERIPH_CLK_SEL位,CBCDR的AHB_PODF位即可,其他的时钟配置也是这种方式,这里直接把所有的配置代码贴出。
#include "bsp_clk.h"
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;
}
void imx6u_clkinit(void)
{
unsigned int reg;
/* enable PLL1 to 528Mhz*/
if(((CCM->CCSR >> 2) & 0x1) == 0) // if step_clk is not enabled
{
CCM->CCSR &= ~(0x1 << 8); // set step_clk to osc_clk(24Mhz)
CCM->CCSR |= (0x1 << 2); // set step_clk ENABLE
}
CCM_ANALOG->PLL_ARM = (1 << 13) | ((88 << 0) & 0x7F); //set PPL1 to 1056Mhz
CCM->CACRR = 1; //set PPL1 to 528Mhz
CCM->CCSR &= ~(0x1 << 2); //set PLL1 enable
reg = CCM_ANALOG->PFD_528;
reg &= ~(0x3F3F3F3F);// clear PFD_528
reg |= (32 << 24) | (24 << 16) | (16 << 8) | (27 << 0); // set PFD_528 to control all PPL2_PFD
CCM_ANALOG->PFD_528 = reg;
reg = CCM_ANALOG->PFD_480;
reg &= ~(0x3F3F3F3F);// clear PFD_480
reg |= (19 << 24) | (17 << 16) | (16 << 8) | (12 << 0); // set PFD_480 to control all PPL3_PFD
CCM_ANALOG->PFD_480 = reg;
//set AHB_CLK_ROOT = 132Mhz
CCM->CBCMR &= ~(3 << 18);
CCM->CBCMR |= (1 << 18);
CCM->CBCDR &= ~(1 << 25);
while(CCM->CDHIPR &(1 << 5))// wait for AHB_CLK_ROOT
//set IPG_CLK_ROOT = 66Mhz
CCM->CBCDR &= ~(3 << 8);
CCM->CBCDR |= (1 << 8);
//set PRECLK_CLK_ROOT = 66Mhz
CCM->CSCMR1 &= ~(1 << 6);
CCM->CSCMR1 &= ~(0x3f << 0);
}
最后把头文件声明一下就可以在BSP文件管理中使用了。具体的BSP结构参考我的学习笔记(一)。