• 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); // 切换回时钟
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    1. IPG_CLK_ROOT 初始化
    • 设置CBCDR寄存器IPG_PODF = 1,也就是2分频
    	CCM->CBCDR &= ~(3<<8);
    	CCM->CBCDR |= (1<<8);
    
    • 1
    • 2
    1. PERCLK_CLK_ROOT 初始化
      • 设置CSCMR1 寄存器的PERCLK_CLK_SEL 位为0,表示PERCLK的时钟源为IPG
    	CCM->CSCMR1 &= ~(1<<6);
    	CCM->CSCMR1 &= ~(0x3f<<0); // 1分频就是置0
    
    • 1
    • 2
  • 相关阅读:
    anylogic 学习(3)—— 智能体相关操作
    Kafka学习总结
    dd命令用法学习,是一个功能强大的工具
    XtraBackup 搭建从库的一般步骤及 XtraBackup 8.0 的注意事项
    SpringBoot单元测试
    Redis之主从复制,哨兵模式,集群
    如何优化你的Vue.js应用以获得最佳性能
    27、Flink 的SQL之SELECT (窗口聚合)介绍及详细示例(4)
    Java中ConcurrentHashMap 和 Hashtable
    影响服务器性能的主要因素是什么?
  • 原文地址:https://blog.csdn.net/m0_63667883/article/details/134009538