09. 主频和时钟配置

硬件原理图分析

在这里插入图片描述

  1. 32.768kHz的晶振,供给RTC实时时钟工作。该晶振不会参与到系统时钟去
  2. 在6U的T16和T17这两个IO上,接一个24MHz的晶振,提供整个系统的时钟,是内核和其他外设的时钟源

7路PLL时钟源

I.MX6U 的外设很多,不同外设的时钟源不同,NXP将这些外设的是中原进行分组,一共7组
在这里插入图片描述

  1. ARM_PLL(PLL1),是供ARM内核使用的,可以通过编程的方式最高可倍频到1.3GHz
  2. 528_PLL(PLL2),也叫做System_PLL,是固定的22倍频,不可编程修改。此路PLL时钟=24MHz*22=528MHz。此路分出4路,PLL2_PFD0~PLL2_PFD3,这四路和528PLL共同作为其他很多外设的根时钟源,通常也是I.MX6U内部系统总线的时钟源
  3. USB1_PLL(PLL3),主要用于USBPHY,也有四路,PLL3_PFD0~PLL_PFD3。是固定的20倍频,也就是480MHz。虽然主要用于USB1PHY,但是和其他四路也可以作为其他外设的根时钟源
  4. USB2_PLL(PLL7),给USB2PHY使用,也是固定的22倍频
  5. ENET_PLL(PLL6),固定为20+5/6倍频,也就是500MHz。用于生成网络所需的时钟,可以在此基础上生成25/50/100/125MHz
  6. VIDEO_PLL(PLL5),用于显示相关的外设,比如LCD,倍频可以调整,范围是650MHz~1300MHz,最终输出的时候还可以进行分频,可选1/2/4/8/16
  7. AUDIO_PLL(PLL4),用于音频相关的外设,倍频可以调整,范围是650MHz~1300MHz,最终输出的时候还可以进行分频,可选1/2/4

时钟树简介

在这里插入图片描述
左边的 CLOCK_SWITCHER 就是我们上一小节讲解的那 7 路 PLL 和8 路 PFD,右边的 SYSTEM CLOCKS 就是芯片外设,中间的 CLOCK ROOT GENERATOR 给左边和右边进行牵线搭桥。就负责从7路PLL和8路PFD中选择合适的时钟源给外设用,具体操作就是配置相关寄存器

以ESAI为例,ESAI的时钟图

在这里插入图片描述

  1. 第一部分是时钟源选择器,ESAI有4个可选时钟源:PLL4、PLL5、PLL_PFD2和PLL3_SW_CLK。具体哪一路是由寄存器CCM->CSCMR2和ESAI_CLK_SEL位来决定的
    在这里插入图片描述
  2. 第二部分是ESAI的前级分频,分频值由寄存器CCM_CS1CDR的ESAI_CLK_PRED来确定的,可以设置1~8分频。假如选择PLL4=650MHz,前级选择2分频,那么此时就是650/2=325MHz
  3. 第三部分又是一个分频器。分频值由寄存器CCM_CS1CDR 的 ESAI_CLK_PODF 来决定,可设置 1~8 分频。假如我们设置为 8 分频的话,经过此分频器以后的时钟就是 325/8=40.625MHz。因此最终进入到 ESAI 外设的时钟就是40.625MHz。

内核时钟系统主频设置

ARM内核时钟树

  1. 通过CCM_CACRR的ARM_PODF位(bit3 ~ 0) 对PLL1进行分频,后面没有2分频。
  2. PLL1=pll1_sw_clk_sel,通过CCSR的pll1_sw_clk_sel(bit 2)选择,如果为1,就是main_clk,如果是0,就是step_clk。
  3. step_clk 通过CCSR的 step_sel 位(bit 8)有两路可以选择,如果是0,频率就是osc_clk,也就是晶振。
  4. 时钟切换为临时时钟,也就是step_clk 后 就可以通过寄存器CCM_ANALOG_PLL_ARM的DIV_SELECT位(bit 6~0)修改PLL1的频率。公式为:PLL=24*div_select/2,单位是MHz。例如如果要设置PLL为1056,那么div_select就设置为88。还要设置enable 位(bit 13)为1,也就是使能输出
  5. 在切换回PLL1之前,设置CACRR为main_clk

CCM_CACRR

在这里插入图片描述
ARM_PODF可以设置0 ~ 7,分别对应1 ~ 8分频。如果要设置内核主频为528MHz,设置2分频,PLL1=1056MHz;如果要设置内核主频为696MHz,就设置1分频,PLL1=696MHz,因为PLL1有最低值和最高值。如果要设置700MHz,只能寻找最接近的值设置

CCSR

在这里插入图片描述
通过CCSR寄存器的 pll1_sw_clk_sel 进行数据选择。在修改PLL1的时候,也就是设置系统时钟的时候需要给6ULL一个临时的时钟,也就是step_clk ,在修改PLL1的时候需要将 pll1_sw_clk_sel 修改为 step_clk。

CCM_ANALOG_PLL_ARMn

在这里插入图片描述

  • ENABLE:时钟输出使能位,设置为1,使能PLL1输出,设置为0就关闭PLL1输出
  • DIV_SELECT:设置PLL1的输出频率,范围54~108。CLK=Fin*div_select/2,Fin=24MHz
    修改PLL1时钟频率时要先将内核时钟源改为其他的时钟源,可选时钟源如下:
    在这里插入图片描述

代码实例

// 使能外设时钟
void clk_enable()
{
	CCM->CCGR0=0xffffffff;
	CCM->CCGR1=0xffffffff;
	CCM->CCGR2=0xffffffff;
	CCM->CCGR3=0xffffffff;
	CCM->CCGR4=0xffffffff;
	CCM->CCGR5=0xffffffff;
	CCM->CCGR6=0xffffffff;
}
// 初始化时钟
void imx6u_clkinit()
{
	if((((CCM_CCSR)>>2)&0x1)==0) // 如果此位为0,就是main_clk,需要切换为1
	{
		CCM->CCSR &= ~(1<<8); // 设置step_clk=osc_clk
		CCM->CCSR |= (1<<2);  // 切换为step_clk,就可以修改PLL1
	}
	
	// 设置PLL1为1056MHz
	CCM_ANALOG->PLL_ARM = (1<<13)|((88<<0)&0x7f); // &0x7f就是取低7位
	CCM->CACRR = 1; // 设置为2分频
	CCM->CCSR &= ~(1<<2); // 切换回时钟
}

PFD时钟设置

在这里插入图片描述

PLL2的4路设置

用到的寄存器是CCM_ANALOG_PFD_528n
在这里插入图片描述

  • PFD0_FRAC:设置分频数,PLL2_PFD0 计算公式为528*18/PFD0_FRAC,可设置范围12~35
  • PFD0_STABLE:此位为只读位,判断PLL2_PFD0是否稳定
  • PFD0_CLKGATE:输出使能位,为1的时候关闭PLL2_PFD0的输出,为0的时候使能输出

PLL3的4路设置

用到的寄存器是CCM_ANALOG_PFD_480n
在这里插入图片描述
结构类似,只是计算公式不同。PLL3_PFDX=480*18/PFDX_FRAC

代码实例

	reg = CCM_ANALOG->PFD_528;
	reg &= ~(0x3f3f3f3f); // 将所有位全部清0
	reg |=32<<24); // PLL2_PFD3=297
	reg |=24<<16); // PLL2_PFD2=396
	reg |=16<<8);  // PLL2_PFD1=594
	reg |=27<<0);  // PLL2_PFD0=352
	CCM_ANALOG->PFD_528=reg;

	reg = CCM_ANALOG->PFD_490;
	reg &= ~(0x3f3f3f3f); // 将所有位全部清0
	reg |=19<<24); // PLL3_PFD3=720
	reg |=17<<16); // PLL3_PFD2=508.2
	reg |=16<<8);  // PLL3_PFD1=540
	reg |=12<<0);  // PLL3_PFD0=720
	CCM_ANALOG->PFD_480=reg;

AHB、IPG和PERCLK根时钟设置

因为PERCLK_CLK_ROOT 和 IPG_CLK_ROOT 要用到AHB_CLK_ROOT.
I.MX6U外设根时钟可设置范围如下,一般直接设置为最大,让性能最大
在这里插入图片描述

AHB_CLK_ROOT 和 IPG_CLK_ROOT

在这里插入图片描述
①此选择器用来选择 pre_periph_clk 的时钟源,可以选择 PLL2、 PLL2_PFD2、 PLL2_PFD0和 PLL2_PFD2/2。寄存器 CCM_CBCMR 的 PRE_PERIPH_CLK_SEL 位决定选择哪一个,默认选择 PLL2_PFD2,因此 pre_periph_clk=PLL2_PFD2=396MHz。
②此选择器用来选择 periph_clk 的时钟源,由寄存器 CCM_CBCDR 的 PERIPH_CLK_SEL位与 PLL_bypass_en2 组成的或来选择。当 CCM_CBCDR 的 PERIPH_CLK_SEL 位为 0 的时候,periph_clk=pr_periph_clk=396MHz。
③通过 CBCDR 的 AHB_PODF 位来设置 AHB_CLK_ROOT 的分频值,可以设置 1~8 分频,如果想要 AHB_CLK_ROOT=132MHz 的话就应该设置为 3 分频: 396/3=132MHz。图中虽然写的是默认 4 分频,但是 I.MX6U 的内部 boot rom 将其改为了 3 分频!
④通过 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

在这里插入图片描述

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 中指定位表示。
  • 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

在这里插入图片描述

  • LCDIF1_PODF: lcdif1 的时钟分频,可设置 0 ~ 7,分别对应 1~8 分频。
  • PRE_PERIPH2_CLK_SEL: pre_periph2 时钟源选择, 00 选择 PLL2, 01 选择 PLL2_PFD2,10 选择 PLL2_PFD0, 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_PFD0, 11 选择PLL2_PFD2/2。
  • PERIPH_CLK2_SEL: peripheral_clk2 时钟源选择, 00 选择 pll3_sw_clk, 01 选择 osc_clk,10 选择 pll2_bypass_clk。

CCM_CSCMR1

在这里插入图片描述

  • PERCLK_CK_SEL: perclk 时钟源选择,为 0 的话选择 ipg clk,为 1 的话选择 osc clk。
  • PERCLK_PODF: perclk 的时钟分频,可设置 0 ~ 7,分别对应 1~8 分频。
    在修改如下时钟选择器或者分频器的时候会引起与 MMDC 的握手发生:mmdc_podf、periph_clk_sel、periph2_clk_sel、arm_podf、ahb_podf。
    发生握手信号以后需要等待握手完成,寄存器 CCM_CDHIPR 中保存着握手信号是否完成,如果相应的位为 1 的话就表示握手没有完成,如果为 0 的话就表示握手完成,另外在修改 arm_podf 和 ahb_podf 的时候需要先关闭其时钟输出,等修改完成以后再打开,否则的话可能会出现在修改完成以后没有时钟输出的问题。

代码实例

  1. AHB_CLK_ROOT 初始化
  • 设置CMCBR寄存器的 PRE_PERIPH_CLK_SEL 位为0
  • 设置CMCDR寄存器的 AHB_PODF 位(bit 12~10)为2,也就是3分频
	// 设置AHB=132MHz
	CCM->CBCMR &= ~(3<<18);
	CCM->CBCMR |= (1<<18); // 设置pre_periph_clk=PLL2_CLK =396MHz
	CCM->CBCDR &= ~(1<<25);// periph_clk = pre_periph_clk=396MHz
	while(CCM->CDHIPR & (1<<5)); 
	
	// 设置3分频的时候如果没有关闭AHB_CLK_ROOT的输出,会出错,但是内部boot rom设置了3分频
	/*
	CCM->CBCDR &= ~(7<<10); // 将10~12位清零
	CCM->CBCDR |= (2<<10); // 设置3分频
	while(CCM->CDHIPR & (1<<1))); // 等待握手信号完成
	*/
  1. IPG_CLK_ROOT 初始化
  • 设置CBCDR寄存器IPG_PODF = 1,也就是2分频
	CCM->CBCDR &= ~(3<<8);
	CCM->CBCDR |= (1<<8);
  1. PERCLK_CLK_ROOT 初始化
    • 设置CSCMR1 寄存器的PERCLK_CLK_SEL 位为0,表示PERCLK的时钟源为IPG
	CCM->CSCMR1 &= ~(1<<6);
	CCM->CSCMR1 &= ~(0x3f<<0); // 1分频就是置0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值