30. 主频和时钟配置实验

一、硬件原理图分析
1、32.768khz的晶振,共给RTC使用。
2、在6U的T16和T17这两个IO上接了一个24MHz的晶振。

二、I.MX6U系统时钟分析
1、7路PLL
为了方便生成时钟,6从24MHz晶振生出来7路PLL。这7路PLL中有的又生出来PFD。
PLL1:ARM PLL供给ARM内核。
PLL2:sysytem PLL,528MHz,528_PLL,此路PLL分出了4路PFD,分别为PLL2_PFD0~PFD3
PLL3: USB1 PLL,480MHz 480_PLL,此路PLL分出了4路PFD,分别为PLL3_PFD0~PFD3。
PLL4: Audio PLL,主供音频使用。
PLL5: Video PLL,主供视频外设,比如RGB LCD接口,和图像处理有关的外设。
PLL6:ENET PLL,主供网络外设。
PLL7: USB2_PLL ,480MHz,无PFD。

2、各路PLL分出的PFD

3、时钟树

4、外设是如何选择合适的时钟
比如ESAI时钟源选择:
PLL4、PLL3_PFD2、PLL5、PLL3。

5、要初始化的PLL和PFD
PLL1,
PLL2,以及PLL2_PFD0~PFD3.
PLL3以及PLL3_PFD0~PFD3.
一般按照时钟树里面的值进行设置。

三、I.MX6U系统配置
1、系统主频的配置
①、要设置ARM内核主频为528MHz,设置CACRR寄存器的ARM_PODF位为2分频,然后设置PLL1=1056MHz即可。CACRR的bit30为ARM_PODF位,可设置07,分别对应1~8分频。应该设置CACRR寄存器的ARM_PODF=1。
②、设置PLL1=1056MHz。PLL1=pll1_sw_clk。pll1_sw_clk有两路可以选择,分别为pll1_main_clk,和step_clk,通过CCSR寄存器的pll1_sw_clk_sel位(bit2)来选择。为0的时候选择pll1_main_clk,为1的时候选额step_clk。
③、在修改PLL1的时候,也就是设置系统时钟的时候需要给6ULL一个临时的时钟,也就是step_clk。在修改PLL1的时候需要将pll1_sw_clk切换到step_clk上。
③、设置step_clk。Step_clk也有两路来源,由CCSR的step_sel位(bit8)来设置,为0的时候设置step_clk为osc=24MHz。为1的时候不重要,不用。
④、时钟切换成功以后就可以修改PLL1的值。
⑤、通过CCM_ANALOG_PLL_ARM寄存器的DIV_SELECT位(bit6~0)来设置PLL1的频率,公式位:
Output = frefDIV_SEL/2 1056=24DIV_SEL/2=>DIEV_SEL=88。
设置CCM_ANALOG_PLL_ARM寄存器的DIV_SELECT位=88即可。PLL1=1056MHz
还要设置CCM_ANALOG_PLL_ARM寄存器的ENABLE位(bit13)为1,也就是使能输出。
⑥、在切换回PLL1之前,设置置CACRR寄存器的ARM_PODF=1!!切记。

2、各个PLL时钟的配置
PLL2和PLL3。PLL2固定为528MHz,PLL3固定为480MHz。
①、初始化PLL2_PFD0~PFD3。寄存器CCM_ANALOG_PFD_528用于设置4路PFD的时钟。比如PFD0= 52818/PFD0_FRAC。设置PFD0_FRAC位即可。比如PLL2_PFD0=352M=52818/PFD0_FRAC,因此FPD0_FRAC=27。

②、初始化PLL3_PFD0~PFD3

3、其他外设时钟源配置
AHB_CLK_ROOT、PERCLK_CLK_ROOT以及IPG_CLK_ROOT。
因为PERCLK_CLK_ROOT和IPG_CLK_ROOT要用到AHB_CLK_ROOT,所以我们要初始化AHB_CLK_ROOT。
①、AHB_CLK_ROOT的初始化。
AHB_CLK_ROOT=132MHz。
设置CBCMR寄存器的PRE_PERIPH_CLK_SEL位,设置CBCDR寄存器的PERIPH_CLK_SEL位0。设置CBCDR寄存器的AHB_PODF位为2,也就是3分频,因此396/3=132MHz。

②、IPG_CLK_ROOT初始化
设置CBCDR寄存器IPG_PODF=1,也就是2分频。
③、PERCLK_CLK_ROOT初始化
设置CSCMR1寄存器的PERCLK_CLK_SEL位为0,表示PERCLK的时钟源为IPG。

4、代码
//bsp_clk.c

/*
 * @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 : 初始化系统时钟,设置系统时钟为528Mhz,并且设置PLL2和PLL3各个
                  PFD时钟,所有的时钟频率均按照I.MX6U官方手册推荐的值.
 * @param       : 无
 * @return      : 无
 */
void imx6u_clkinit(void)
{
    
    
    unsigned int reg = 0;
    /* 1、设置ARM内核时钟为528MHz */
    /* 1.1、判断当前ARM内核是使用的那个时钟源启动的,正常情况下ARM内核是由pll1_sw_clk驱动的,而
     *      pll1_sw_clk有两个来源:pll1_main_clk和tep_clk(参考手册648页)。
     *      如果我们要让ARM内核跑到528M的话那必须选择pll1_main_clk作为pll1的时钟源。
     *      如果我们要修改pll1_main_clk时钟的话就必须先将pll1_sw_clk从pll1_main_clk切换到step_clk,
     *      当修改完pll1_main_clk以后在将pll1_sw_clk切换回pll1_main_clk。而step_clk的时钟源可以选择
     *      板子上的24MHz晶振。
     */
    
    if((((CCM->CCSR) >> 2) & 0x1 ) == 0)    /* 当前pll1_sw_clk使用的pll1_main_clk*/
    {
    
       
        CCM->CCSR &= ~(1 << 8);             /* 配置step_clk时钟源为24MH OSC */    
        CCM->CCSR |= (1 << 2);              /* 配置pll1_sw_clk时钟源为step_clk */
    }

    /* 1.2、设置pll1_main_clk为1056MHz,也就是528*2=1056MHZ,
     *      因为pll1_sw_clk进ARM内核的时候会被二分频!
     *      配置CCM_ANLOG->PLL_ARM寄存器
     *      bit13: 1 使能时钟输出
     *      bit[6:0]: 88, 由公式:Fout = Fin * div_select / 2.0,1056=24*div_select/2.0,
     *                      得出:div_select=    88  
     */
    CCM_ANALOG->PLL_ARM = (1 << 13) | ((88 << 0) & 0X7F);   /* 配置pll1_main_clk=1056MHz */
    CCM->CCSR &= ~(1 << 2);                                 /* 将pll_sw_clk时钟重新切换回pll1_main_clk */
    CCM->CACRR = 1;                                         /* ARM内核时钟为pll1_sw_clk/2=1056/2=528Mhz */

    /* 2、设置PLL2(SYS PLL)各个PFD */
    reg = CCM_ANALOG->PFD_528;
    reg &= ~(0X3F3F3F3F);       /* 清除原来的设置                      */
    reg |= 32<<24;              /* PLL2_PFD3=528*18/32=297Mhz   */
    reg |= 24<<16;              /* PLL2_PFD2=528*18/24=396Mhz(DDR使用的时钟,最大400Mhz) */
    reg |= 16<<8;               /* PLL2_PFD1=528*18/16=594Mhz   */
    reg |= 27<<0;               /* PLL2_PFD0=528*18/27=352Mhz   */
    CCM_ANALOG->PFD_528=reg;    /* 设置PLL2_PFD0~3                */

    /* 3、设置PLL3(USB1)各个PFD */
    reg = 0;                    /* 清零   */
    reg = CCM_ANALOG->PFD_480;
    reg &= ~(0X3F3F3F3F);       /* 清除原来的设置                          */
    reg |= 19<<24;              /* PLL3_PFD3=480*18/19=454.74Mhz    */
    reg |= 17<<16;              /* PLL3_PFD2=480*18/17=508.24Mhz    */
    reg |= 16<<8;               /* PLL3_PFD1=480*18/16=540Mhz       */
    reg |= 12<<0;               /* PLL3_PFD0=480*18/12=720Mhz       */
    CCM_ANALOG->PFD_480=reg;    /* 设置PLL3_PFD0~3                    */  

    /* 4、设置AHB时钟 最小6Mhz, 最大132Mhz (boot rom自动设置好了可以不用设置)*/
    CCM->CBCMR &= ~(3 << 18);   /* 清除设置*/ 
    CCM->CBCMR |= (1 << 18);    /* pre_periph_clk=PLL2_PFD2=396MHz */
    CCM->CBCDR &= ~(1 << 25);   /* periph_clk=pre_periph_clk=396MHz */
    while(CCM->CDHIPR & (1 << 5));/* 等待握手完成 */
        
    /* 修改AHB_PODF位的时候需要先禁止AHB_CLK_ROOT的输出,但是
     * 我没有找到关闭AHB_CLK_ROOT输出的的寄存器,所以就没法设置。
     * 下面设置AHB_PODF的代码仅供学习参考不能直接拿来使用!!
     * 内部boot rom将AHB_PODF设置为了3分频,即使我们不设置AHB_PODF,
     * AHB_ROOT_CLK也依旧等于396/3=132Mhz。
     */
#if 0
    /* 要先关闭AHB_ROOT_CLK输出,否则时钟设置会出错 */
    CCM->CBCDR &= ~(7 << 10);   /* CBCDR的AHB_PODF清零 */
    CCM->CBCDR |= 2 << 10;      /* AHB_PODF 3分频,AHB_CLK_ROOT=132MHz */
    while(CCM->CDHIPR & (1 << 1));/
* 等待握手完成 */
#endif
    
    /* 5、设置IPG_CLK_ROOT最小3Mhz,最大66Mhz (boot rom自动设置好了可以不用设置)*/
    CCM->CBCDR &= ~(3 << 8);    /* CBCDR的IPG_PODF清零 */
    CCM->CBCDR |= 1 << 8;       /* IPG_PODF 2分频,IPG_CLK_ROOT=66MHz */
    
    /* 6、设置PERCLK_CLK_ROOT时钟 */
    CCM->CSCMR1 &= ~(1 << 6);   /* PERCLK_CLK_ROOT时钟源为IPG */
    CCM->CSCMR1 &= ~(7 << 0);   /* PERCLK_PODF位清零,即1分频 */
}

猜你喜欢

转载自blog.csdn.net/lljss1980/article/details/115147621