Linux学习 主频和时钟配置实验

1.原理图

在这里插入图片描述
在这里插入图片描述

IMX6ULL_CORE_V1.6(核心板原理图).pdf

I.MX6U-ALPHA 开发板的系统时钟来源于两部分:32.768KHz 和24MHz 的晶振,其中 32.768KHz 晶振是 I.MX6U 的 RTC 时钟源,24MHz 晶振是 I.MX6U 内核和其它外设的时钟源

2.时钟分析

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.1 7 路 路 PLL 时钟源

![在这里插入图片描述](https://img-blog.csdnimg.cn/cd8766320c964235a632dc00363debe1.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaemYs-WFieS7lA==,size_20,color_FFFFFF,t_70,g_se,x_16
在这里插入图片描述
I.MX6ULL外设时钟有7组,这 7 组时钟源都是从 24MHz 晶振 PLL 而来的

  1. ARM_PLL(PLL1),此路 PLL 是供 ARM 内核使用的,ARM 内核时钟就是由此 PLL生成的,此 PLL 通过编程的方式最高可倍频到 1.3GHz。
  2. 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 接口等等
  3. USB1_PLL(PLL3),此路 PLL 主要用于 USBPHY,此 PLL 也有四路 PFD,为:
    PLL3_PFD0~PLL3_PFD3,USB1_PLL 是固定的 20 倍频,因此 USB1_PLL=24MHz *20=480MHz。
    USB1_PLL虽然主要用于USB1PHY,但是其和四路PFD同样也可以作为其他外设的根时钟源
  4. USB2_PLL(PLL7,没有写错!就是 PLL7,虽然序号标为 4,但是实际是 PLL7),看名
    字就知道此路PLL是给USB2PHY使用的。同样的,此路PLL固定为20倍频,因此也是480MHz
  5. ENET_PLL(PLL6),此路 PLL 固定为 20+5/6 倍频,因此 ENET_PLL=24MHz * (20+5/6)
    = 500MHz。此路 PLL 用于生成网络所需的时钟,可以在此 PLL 的基础上生成 25/50/100/125MHz
    的网络时钟
  6. VIDEO_PLL(PLL5),此路 PLL 用于显示相关的外设,比如 LCD,此路 PLL 的倍频可以
    调整,PLL 的输出范围在 650MHz~1300MHz。此路 PLL 在最终输出的时候还可以进行分频,
    可选 1/2/4/8/16 分频
  7. AUDIO_PLL(PLL4),此路 PLL 用于音频相关的外设,此路 PLL 的倍频可以调整,PLL
    的输出范围同样也是 650MHz~1300MHz,此路 PLL 在最终输出的时候也可以进行分频,可选
    1/2/4 分频

2.2 时钟树

在这里插入图片描述

  • CLOCK_SWITCHER就是7路PLL和8路PFD(PLL的分支),SYSTEM CLOCKS 就是芯片外设,CLOCK ROOT GENERATOR 是最复杂的,连接左边的CLOCK_SWITCHER和右边的SYSTEM CLOCKS。
    CLOCK ROOT GENERATOR负责选择合适 的 时钟源给外设使用

    以ESAI这个外设为例:
    在这里插入图片描述

    此部分是时钟源选择器,ESAI 有 4 个可选的时钟源:PLL4、PLL5、PLL3_PFD2 和pll3_sw_clk 。具体选择哪一路作为 ESAI 的时钟源是由寄存器 CCM->CSCMR2 的ESAI_CLK_SEL 位来决定的,用户可以自由配置
    

第一级: 在这里插入图片描述
第二级:
在这里插入图片描述
第三级:
在这里插入图片描述

2.3 内核时钟设置

设置主频,将主频设置为528MHz
在这里插入图片描述
假设PLL1为996MHz
在这里插入图片描述
经过二分频以后时钟频率为996/2 = 498MHz

在这里插入图片描述
pll1_sw_clk 也就是PLL1 的最终输出频率, CCM_CCSR中PLL1_SW_CLK_SEL 位决定 pll1_sw_clk 是选pll1_main_clk 还是 step_clk。正常情况下应该选择 pll1_main_clk,但是如果要对 pll1_main_clk(PLL1)的频率进行调整的话,比如我们要设置PLL1=1056MHz,此时就要先将 pll1_sw_clk 切换到step_clk 上。等pll1_main_clk 调整完成以后再切换回来

寄存器 CCM_CCSR 我们只用到了 STEP_SEL、PLL1_SW_CLK_SEL 这两个位,一个是用来选择step_clk 时钟源的,一个是用来选择 pll1_sw_clk 时钟源的。
在这里插入图片描述

内核时钟设置步骤
在这里插入图片描述

2.4 PFD时钟设置

PLL2、PLL3 和 PLL7 固定为 528MHz、480MHz 和 480MHz,PLL4~PLL6 都是针对特殊外设的,用到的时候再设置。因此,接下来重点就是设置 PLL2 和PLL3 的各自 4 路 PFD
在这里插入图片描述
在这里插入图片描述

实验代码分析

正点原子代码:

/*
 * @description	: 初始化系统时钟,设置系统时钟为792Mhz,并且设置PLL2和PLL3各个
 				  PFD时钟,所有的时钟频率均按照I.MX6U官方手册推荐的值.
 * @param 		: 无
 * @return 		: 无
 */
void imx6u_clkinit(void)
{
	unsigned int reg = 0;
	/* 1、设置ARM内核时钟为792MHz */
	/* 1.1、判断当前ARM内核是使用的那个时钟源启动的,正常情况下ARM内核是由pll1_sw_clk驱动的,而
	 *      pll1_sw_clk有两个来源:pll1_main_clk和tep_clk。
	 *      如果我们要让ARM内核跑到792M的话那必须选择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为792MHz
	 *      因为pll1_sw_clk进ARM内核的时候会被二分频!
	 *      配置CCM_ANLOG->PLL_ARM寄存器
	 *      bit13: 1 使能时钟输出
	 *      bit[6:0]: 66, 由公式:Fout = Fin * div_select / 2.0,792=24*div_select/2.0,
	 *              		得出:div_select=    66 
	 */
	CCM_ANALOG->PLL_ARM = (1 << 13) | ((66 << 0) & 0X7F); 	/* 配置pll1_main_clk=792MHz */
	CCM->CCSR &= ~(1 << 2);									/* 将pll_sw_clk时钟重新切换回pll1_main_clk */
	CCM->CACRR = 0;											/* ARM内核时钟为pll1_sw_clk/1=792/1=792Mhz */

	/* 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分频 */
}

野火代码:
在这里插入图片描述

#include  "clock.h"

void system_clock_init(void)
{
    /******************* 第一层时钟设置--晶振时钟***********************/
    if ((CCM->CCSR & (0x01 << 2)) == 0) //CPU 使用的是 ARM PLL    {
        /*将CPU时钟切换到XTAL (OSC) 时钟*/                   
        CCM->CCSR &= ~(0x01 << 8); //控制CCSR: step_sel ,选择 osc_clk 作为时钟源
        CCM->CCSR |= (0x01 << 2);  //设置GLITCHLESS MUX 选择 step_clk 作为时钟源
    }


   /******************* 第二层时钟设置--PLL时钟***********************/
   
    /*设置PLL1输出时钟为792MHz,它将作为CPU时钟*/
    CCM_ANALOG->PLL_ARM |= (0x42 << 0);

    /*将CPU 时钟重新切换到 ARM PLL*/
    CCM->CCSR &= ~(0x01 << 2);

    /*设置时钟分频系数为0,即不分频*/
    CCM->CACRR &= ~(0x07 << 0); //清零分频寄存器   不分频
   //CCM->CACRR |= (0x07 << 0);     // 8分频


    /*设置PLL2(System PLL) 输出时钟*/
    /* Configure SYS PLL to 528M */
    CCM_ANALOG->PLL_SYS_SS &= ~(0x8000);     //使能PLL2 PFD输出
    CCM_ANALOG->PLL_SYS_NUM &= ~(0x3FFFFFFF);//设置分频系数为0,即不分频。
    CCM_ANALOG->PLL_SYS |= (0x2000); //使能PLL2 输出
    CCM_ANALOG->PLL_SYS |= (1 << 0); //设置输出频率为528M
    while ((CCM_ANALOG->PLL_SYS & (0x80000000)) == 0) //等待设置生效
    {
    }

    /*设置PLL3(System PLL) 输出时钟*/
    /* Configure USB PLL to 480M */
    CCM_ANALOG->PLL_USB1 |= (0x2000);    //使能 PLL3时钟输出
    CCM_ANALOG->PLL_USB1 |= (0x1000);    //PLL3上电使能
    CCM_ANALOG->PLL_USB1 |= (0x40);      // 使能USBPHYn
    CCM_ANALOG->PLL_USB1 &= ~(0x01 << 0);//设置输出频率为480MHz
    while ((CCM_ANALOG->PLL_SYS & (0x80000000)) == 0)//等待设置生效
    {
    }

    /*关闭暂时不使用的 PLL4 、PLL5  、PLL6 、PLL7*/
    CCM_ANALOG->PLL_AUDIO = (0x1000);    //关闭PLL4
    CCM_ANALOG->PLL_VIDEO = (0x1000);    //关闭PLL5
    CCM_ANALOG->PLL_ENET =  (0x1000);    //关闭PLL6
    CCM_ANALOG->PLL_USB2 =  (0x00);           //关闭PLL7

 
    /******************第三层时钟设置--PFD*******************/
    /*禁用PLL2 的所有PFD输出*/
    CCM_ANALOG->PFD_528 |=(0x80U) ;      //关闭PLL2 PFD0
    CCM_ANALOG->PFD_528 |=(0x8000U) ;    //关闭PLL2 PFD1
    // CCM_ANALOG->PFD_528 |=(0x800000U) ;  //关闭PLL2 PFD2 ,DDR使用的是该时钟源,关闭后程序不能运行。暂时不关闭
    CCM_ANALOG->PFD_528 |=(0x80000000U); //关闭PLL2 PFD3
    
    /*设置PLL2 的PFD输出频率*/
    CCM_ANALOG->PFD_528 &= ~(0x3FU); //清零PLL2 PFD0 时钟分频
    CCM_ANALOG->PFD_528 &= ~(0x3F00U); //清零PLL2 PFD1 时钟分频
    CCM_ANALOG->PFD_528 &= ~(0x3F00U); //清零PLL2 PFD2 时钟分频
    CCM_ANALOG->PFD_528 &= ~(0x3F00U); //清零PLL2 PFD3 时钟分频

    CCM_ANALOG->PFD_528 |= (0x1B << 0); //设置PLL2 PFD0 输出频率为 352M
    CCM_ANALOG->PFD_528 |= (0x10 << 8); //设置PLL2 PFD0 输出频率为 594M
    CCM_ANALOG->PFD_528 |= (0x18 << 16); //设置PLL2 PFD0 输出频率为 396M
    CCM_ANALOG->PFD_528 |= (0x30 << 24); //设置PLL2 PFD0 输出频率为 198M

    /*启用PLL2 的所有PFD输出*/
    CCM_ANALOG->PFD_528 &= ~(0x80U) ;      //开启PLL2 PFD0
    CCM_ANALOG->PFD_528 &= ~(0x8000U) ;    //开启PLL2 PFD1
    CCM_ANALOG->PFD_528 &= ~(0x800000U) ;  //开启PLL2 PFD2
    CCM_ANALOG->PFD_528 &= ~(0x80000000U); //开启PLL2 PFD3


    /*禁用PLL3 的所有PFD输出*/
    CCM_ANALOG->PFD_480 |=(0x80U) ;      //关闭PLL3 PFD0
    CCM_ANALOG->PFD_480 |=(0x8000U) ;    //关闭PLL3 PFD1
    CCM_ANALOG->PFD_480 |=(0x800000U) ;  //关闭PLL3 PFD2
    CCM_ANALOG->PFD_480 |=(0x80000000U); //关闭PLL3 PFD3

    /*设置PLL3 的PFD输出频率*/
    CCM_ANALOG->PFD_480 &= ~(0x3FU);   //清零PLL3 PFD0 时钟分频
    CCM_ANALOG->PFD_480 &= ~(0x3F00U); //清零PLL3 PFD1 时钟分频
    CCM_ANALOG->PFD_480 &= ~(0x3F00U); //清零PLL3 PFD2 时钟分频
    CCM_ANALOG->PFD_480 &= ~(0x3F00U); //清零PLL3 PFD3 时钟分频

    CCM_ANALOG->PFD_480 |= (0xC << 0); //设置PLL3 PFD0 输出频率为 720M
    CCM_ANALOG->PFD_480 |= (0x10 << 8); //设置PLL3 PFD0 输出频率为 540M
    CCM_ANALOG->PFD_480 |= (0x11 << 16); //设置PLL3 PFD0 输出频率为 508.2M
    CCM_ANALOG->PFD_480 |= (0x13 << 24); //设置PLL3 PFD0 输出频率为 454.7M

    /*启用PLL3 的所有PFD输出*/
    CCM_ANALOG->PFD_480 &= ~(0x80U) ;      //开启PLL3 PFD0
    CCM_ANALOG->PFD_480 &= ~(0x8000U) ;    //开启PLL3 PFD1
    CCM_ANALOG->PFD_480 &= ~(0x800000U) ;  //开启PLL3 PFD2
    CCM_ANALOG->PFD_480 &= ~(0x80000000U); //开启PLL3 PFD3
  

    /******************第四层时钟设置--外设****************/
    CCM->CSCDR1 &= ~(0x01 << 6); //设置UART选择 PLL3 / 6 = 80MHz
    CCM->CSCDR1 &= ~(0x3F);     //清零
    CCM->CSCDR1 |= ~(0x01 << 0); //设置串口根时钟分频值为1,UART根时钟频率为:80M / (dev + 1) = 40MHz
}
#ifndef _CLOCK_H_
#define _CLOCK_H_

#include  "common.h" 
                   
void system_clock_init(void);

#endif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

i阳光仔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值