正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-14-主频和时钟配置

前言:

本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM(MX6U)裸机篇”视频的学习笔记,在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。

引用:

正点原子IMX6U仓库 (GuangzhouXingyi) - Gitee.com

《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf》

正点原子资料下载中心 — 正点原子资料下载中心 1.0.0 文档

正文:

本文是 “正点原子[第二期]Linux之ARM(MX6U)裸机篇--第14.1, 14.2, 14.3 讲” 的读书笔记。第14讲主要是介绍I.MX6U处理器的主频和系统时钟配置。本节将参考正点原子的视频教程第14讲和配套的正点原子开发指南文档进行学习。

0. I.MX6U系统时钟总体介绍

在前几章的时延中我们都没有涉及到I.MX6U的时钟和主频的配置操作,全部使用默认的配置,默认配置I.MX6U上电启动芯片内部 boot ROM 会把处理器工作频率设置为 396MHz。但是 I.MX6U 系列标准的工作频率为 528MHz,有些型号甚至可以工作到696MHz。本章我们就学习I.MX6U的系统时钟,学习如何配置I.MX6U的系统时钟和其他的外设时钟,使其工作在 528MHz,其它的外设时钟都工作在NXP推荐的频率。

1. I.MX6U时钟系统详解

I.MX6U的系统主频为528MHz,有些型号伸着可以跑到696MHz,但是默认情况下内部 boot rom 会讲 I.MX6U 的主频设置为 396MHz,这个我们在 9.2 小节已经讲过了。我们在使用 I.MX6U 的时候肯定要发挥它的最大性能,那么主频肯定要设置到528MHz(其它型号可以设置的更高,比如696MHz),其它的外设时钟也要设置到NXP推荐的值。I.MX6U的系统时钟在I.MX6ULL/I.MX6UL 参考手册》的第 10 章“Chapter 10 Clock and Power Management”和第18 章“Chapter 18 Clock Controller Module (CCM)”这两章有详细的讲解。

1.1 系统时钟的来源

打开I.MX6U ALPHA/Mini 核心开发板原理图,开发板时钟如图 16.1.1.1 所示

从图 16.1.1.1 可以看出 I.MX6U ALPHA/Mini 开发板的系统时钟来源于两部分:32.768KHz和24MHz的晶振,其中 32.768KHz是I.MX6U的RTC时钟源,24MHz晶振是I.MX6U内核和其他外设的时钟源,也是我们重点要分析的。

1.2 7路PLL时钟源

I.MX6U的外设有很多,不同的外设时钟源不同,NXP将这些外设的时钟源做了分组,一共有7组,这7组时钟源都是从 24MHz 晶振 PLL 而来的,因此也叫做7组PLL,这7组PLL结构图如 图 16.1.1.2 所示:

图 16.1.1.2 展示了7个PLL的关系,我们依次来看一下这7个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_PHY 是固定的20倍频,因此USB1_PLL=24MHz*20=480MHz。USB1_PLL虽然主要用于USB1PHY,但是和其他四路PFD同样也可以用作其他外设的时钟源。
  • 4. USB2_PLL(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分频。
1.3 时钟树简介

在上一小节讲解了7路PLL,I.MX6U的所有外设时钟源都是从这7路PLL和有些PLL的PFD而来的,这些外设究竟是如何选择PLL或者PFD的?这就要借助《IMX6ULL 参考手册》里的时钟树了,在“Chapter 18 Clock Controller Module (CCM)”的 18.3 小节给出了 I.MX6U详细的时钟树图,如图 16.1.3.1 所示:

在图16.3.1中一共有三部分:CLOCK_SWITCHER,CLOCK ROOT GENERATOR 和 SYSTEM CLOCKS。其中左边的 CLOCK_SWITCHER 就是我们上一小节讲解的那7路PLL和8路PFD,右边的 SYSTEM CLOCK 就是芯片外设,中间的 CLOCK ROOT GENERATOR 是最复杂的,这一部分就像“月老”一样,给左边的 CLOCK_SWITCHER 和 右边的 SYSTEM CLOCKS 进行牵线搭桥。外设的时钟源有多路可以选择的,CLOCK ROOT GENERATOR 就扶着从7路PLL和8路PFD中选择合适的时钟源给外设使用。具体操作肯定是设置相应的寄存器,我们以EASI这个外设为例,EASI的时钟图如 16.1.3.2 所示:

在图 16.1.3.2 中我们分为了3部分,这3部分如下:

  1. 此部分是时钟选择源,ESAI有4个可选的时钟源:PLL5, PLL5, PLL3_PFD2 和 pll3_sw_clk。具体选择哪一路作为ESAI的时钟源是有寄存器 CCM->CSMR2 的 EASI_CLK_SEL 位来决定的,用户可以自由配置,配置如图 16.1.3.3 所示
  2. 此部分作为ESAI时钟的前级分频器,分频值由 CS1CDR的ESAI_CLK_PRED来确定,可以设置1~8分频,假如现在 PLL4=650MHz,我们选在PLL4作为ESAI时钟,前级分频器选择2分频,那么此时的时钟就是 650/2 = 325MHz
  3. 此部分又是一个分频器,对2中输入的时钟进一步分频,分频值由寄存器 CS1CDR 的 ESAI_CLK_PODF 来决定,可以设置1~8分频。假如我们设置为8分频的话,经过此分频器以后的时钟就是 325/8=40.625MHz。因此最终进入到 ESAI外设的时钟就是 40.625MHz。

上面我们以外设EASI为例讲解了如何根据图 16.1.3.1 来设置外设的时钟频率,其它的外设基本类似,大家可以自行分析一下其他的外设。关于外设时钟配置的内容全部都在《I.MX6ULL 参考手册》的第 18 章。

1.4 内核时钟设置

I.MX6U的系统故事中再前面几节已经分析的差不多了,现在就可以开始设置相应的时钟频率了。先从处理器主频开始,我们将 I.MX6U 的主频设置为 528MHz,根据根据图 16.1.3.2 的时钟树可以看到ARM 内核时钟如图 16.1.4.1 所示:

图 16.1.4.1 中各部分如下

序号描述
1内核时钟来源于PLL1,假设此时PLL1为960MHz
2通过寄存器 CCM_CACRR 的 ARM_PODF 位对PLL1进行分频,可选择1/2/4/8分频,假如我们选择了2分频,那么经过分频以后的时钟频率就是 996/2=498MHz
3大家不要被次数的2分频给骗了,此处没有进行2分频(我就被这个 2 分频骗了好久,主频一直配置不正确!
4经过第2步的分频之后的498MHz就是ARM的内核时钟,也就是I.MX6U的主频

经过上面的几步分析可知,假如我们要设置内核主频为528MHz,那么PLL1可以设置为 1056MHz,寄存器CCM_CACRR的 ARM_PODF 位设置为2。同理,如果要将主频设置为696Mhz,那么主频PLL1就可是设置696Mhz,CCM_CACRR的 ARM_PODF 位设置为1。现在问题很清楚了:

  • 寄存器CCM_CACRR的 ARM_PODF 位很好设置
  • PLL1的频率可以通过 CCM_ANALOG_PLL_ARMn 来设置。

CCM_CACRR寄存器的结构如下图所示:

1.4.1 PLL1 (ARM_PLL)倍频设置

《I.MX6ULL 参考手册》的章节 18.5.1.3.1 ARM PLL,说明了 PLL1 的是从外部 24MHz 晶振倍频而来,PLL1 的频率范围是从 650MHz ~ 1.3GHz,通过寄存器 'CCM_ANALOG_PLL_ARM' 的比特位 'DIV_SELECT' 可以选择输出的PLL1的倍频范围。

PLL1 的倍频输出计算公式为:

PLL output frequency = Fref * DIV_SEL/2

根据上面的计算公式,假如我们想要配置 PLL1 的倍频输出为 1056Mhz,计算出的的 'DIV_SEL' 值应该是 。

1056 Mhz = 24MHz*DIV_SEL/2;
DIV_SEL = (1056*2)/24 = 88

'CCM_ANALOG_PLL_ARM' 寄存器比特位 'DIV_SELECT' 定义如下:

寄存器 CCM_ANALOG_PLL_ARM 的关键位是:

  • bit[13] Enable:时钟输出使能位,此位设置为 1 使能 PLL1 输出,如果设置为 0 的话就关闭 PLL1输出
  • bit[6:0] DIV_SELECT,:此位设置 PLL1 的输出频率,可设置范围为: 54~108, PLL1 CLK = Fin *div_seclec/2.0, Fin=24MHz。如果 PLL1 要输出 1056MHz 的话, div_select 就要设置为 88。
1.4.2 PLL1 Clock Switcher 时钟源选择

在修改 PLL1 时钟频率的时候我们需要先将内核时钟源改为其他的时钟源, PLL1 可选择的
时钟源如图 16.1.4.4 所示,在《I.MX6ULL 参考手册》的章节 18.5.1.5.1 Clock Switcher 中:

思考:修改ARM主频为什么要切换时钟源?

为什么在设置 PLL1 (ARM_PLL) ARM 内核时钟的时候,要先将ARM内核时钟选择一个其他时钟源,然后修改PLL1的时钟频率,最后在将ARM内核的时钟源再切换到PLL1哪?

原因:

因为ARM内核(处理器)的运行每时每刻都需要时钟的驱动,I.MX6U 默认启动的时候使用的是 PLL1 的时钟源默认为396MHz,当我们需要修改系统主频,也就是修改PLL1的倍频频率为 596MHz的时候,要对PLL1进行修改而当前ARM内核当前正在使用的就是PLL1,修改PLL1时钟需要一个过程而在这个过程中ARM处理器就丢失了时钟无法运行。
这就像给人做心脏手术一样,在做对心脏做手术之前要接一个体外人工血液循环泵维持血液循环,在做完心脏手术之后再把血液循环接回到心脏。
也就是说在修改当前PLL之前,所有以依赖当前PLL的时钟源都需要切换到一个新的时钟源上,然后

图 16.1.4.4中:

1. pll_sw_clk 也就是PLL1的最终输出频率

2. 此处是一个选择器,选择 pll1_sw_clk 的时钟源,有寄存器 CCM_CCSR 的 PLL1_SW_CLK_SEL 位决定 pll1_sw_clk 是选择 pll1_mian_clk 还是 step_clk。正常情况下应该选择 pll1_main_clk,但是如果要对 pll1_main_clk(PLL1)的频率进行调整的话,比如我们要设置PLL1=1056MHz,此时就要先将 pll1_sw_clk 切换到 step_clk 上。等 pll1_main_clk 调整调整完成以后再切换回来。

3. 此处也是一个选择器,选择 step_clk 的时钟源,有寄存器 CCM_CCSR 的 SETP_SEL 位决定 setp_clk 是选择 osc_clk 还是 secondary_clk。一般选择 osc_clk,也就是 24MHz 的晶振。

这里我们用到了一个寄存器 CCM_CCSR,此寄存器的结构如下图所示:

寄存器 CCM_SSSR 我们只用到了 STEP_SEL 和 PLL1_SW_CLK_SEL 这两位,一个是用来选择 setp_clk 的时钟源,一个是用来选择 pll1_sw_clk 的时钟源。

到这里,修改 I.MX6U 主频的步骤就很清晰了,修改步骤如下:

  1. 设置寄存器 CCM_CCSR 的 STEP_SEL位,设置 setp_clk 的时钟源为 osc 24MHz 的晶振。
  2. 设置寄存器 CCM_CCSR 的 PLL1_SW_CLK_SEL 位,设置 pll1_sw_clk 的时钟源为 setp_clk=24MHz,通过这一步我们就将 I.MX6U 的主频先这是为 24MHz,直接来自于外部的24MHz晶振。
  3. 设置寄存器 CCM_ANALOG_AMRn,将 pll1_mian_clk(PLL1)设置为 1056MHz。
  4. 设置寄存器 CCSR 的 PLL1_SW_CLK_SEL 位,将 pll1_sw_clk 的时钟源重新切换会 pll1_main_clk ,切换回来之后的 pll1_sw_clk 就等于 1056MHz。
  5. 最后设置寄存器CCM_CACRR 的 ARM_PODF 为 2 分频,I.MX6U的内核主频就为 1056/2=528MHz。
1.4.3 PLL1 主频设置源码

按照上面1.4.2 分析的步骤

/* 初始化时钟 */
void imx6u_clkinit(void)
{/* 初始化 IMX6U 的主频为528MHz */if(((CCM->CCSR >> 2) & 0x1) == 0){				/* 判断PLL1_SW_CLK_SEL位为0,当前使用 pll1_main_clk */CCM->CCSR &= ~(1<<8);						/* 设置CCM_CCSR STEP_SEL位,0 step_clk 选择 osc_clk 24MHz晶振 */CCM->CCSR |= (1<<2);						/* 设置PLL1_SW_CLK_SEL位为1,pll1_sw_clk切换到step_clk */}/* 设置PLL1为1056MHz */CCM_ANALOG->PLL_ARM &= ~(1 << 13);			/* 清零ANANLOG_PLL_ARM bit[13],关闭 pll1_main_clk */CCM_ANALOG->PLL_ARM &= ~0x7f;				/* 清零ANANLOG_PLL_ARM bit[6:0] */CCM_ANALOG->PLL_ARM |= ((88 << 0) & 0x7f);	/* 设置ANANLOG_PLL_ARM bit[6:0], PLL1 frquencey=Frq*div_select/2 */CCM_ANALOG->PLL_ARM |= (1 << 13);			/* 设置ANANLOG_PLL_ARM bit[13] Enable=1, 开启 pll1_main_cl *//* pll1_sw_clk切换回pll1_main_clk(PLL1)*/CCM->CCSR &= ~(1<<2);/* 设置PLL1分频位2, 1056Mhz/2=528MHz */CCM->CACRR = 0x1;							/* ARM_PODF divide by 2 */}
1.4.4 编译修改主频后源码烧录SD卡验证

编译修改主频后源码烧录SD卡验证主频修改是否生效。将I.MX6U的主频从默认396MHz修改为 528MHz或者696Mhz之后,LED灯闪烁速度会变快,按下按键后蜂鸣器的鸣叫频率也尖锐。

我本地验证的结果是修改修改I.MX6U主频为528MHz/696MHz之后LED闪烁频率变快蜂鸣器鸣叫变快,实验修改主频成功。

2. PFD时钟设置

设置好主频之后我们好要设置好其它的PLL和PFD时钟,PLL1上一小节已经设置好了,PLL2, PLL3, PLL7 是固定为528MHz, 480MHz 和 480MHz,PLL4~PLL6 都是针对特殊外设的用到的时候再设置。

因此,接下来重点就是设置PLL2和PLL3的各自4路PFD,NXP推荐的这8路PFD频率如下表:

先设置PLL2的4路PFD,用到的寄存器是 CCM_ANLOG_PFD_528n,寄存器的结构如下图所示:

从 16.5.1 可以看出,寄存器 CCM_ANALOG_PFD_528n 其实分为四组,分别对应 PFD0~PFD3,每组8个bit,我们以 PFD0为例,看一下如何设置 PLL2_PFD0的频率。PFD0对应的寄存器位如下:

  • PFD0_FRAC:PLL2_PFD0的分频数,PLL2_PFD0的计算公式为 528*18/PFD0_FRAC,此位的可设置范围为 12-35。如果 PLL2_PFD0 的频率设置352MHz的话,PFD0_FRAC=528*18/252=27。
  • PFD0_STABLE :此位为只读位,可以通过此位判断PLL2_PFD0 是否稳定
  • PFD0_CLKGATE:PLL2_PFD0 输出是能位,为1的时候关闭PLL2_PFD0的输出,为0的时候使能输出。

如果我们设置PLL2_PFD0的频率为325MHz的话,就需要设置 PFD0_FRAC为27,PFD0_CLKGATE为0。PLL1~PLL3的设置类似,频率计算公式都是 528*18/PFDX_FRAC(X=1~3),因 此 PLL2_PFD1=594MHz 的 话 , PFD1_FRAC=16 ;PLL2_PFD2=400MHz 的话 PFD2_FRAC 不能整除,因此取最近的整数值,即 PFD2_FRAC=24,这样 PLL2_PFD2 实际为 396MHz; PLL2_PFD3=297MHz 的话, PFD3_FRAC=32。

接下来设置PLL3 PFD0~PFD3这4路PFD的频率,使用到的寄存器是CCM_ANALOG_PFD_480n,此寄存器的结构如下图所示:

从图 16.1.5.2 可以看出,寄存器 CCM_ANALOG_PFD_480n 和 CCM_ANALOG_PFD_528n
的结构是一模一样的,只是一个是 PLL2 的,一个是 PLL3 的。寄存器位的含义也是一样的,只
是 频 率 计 算 公 式 不 同 , 比 如 PLL3_PFDX=480*18/PFDX_FRAC(X=0~3) 。 如 果
PLL3_PFD0=720MHz 的话, PFD0_FRAC=12;如果 PLL3_PFD1=540MHz 的话, PFD1_FRAC=16;如果 PLL3_PFD2=508.2MHz 的话, PFD2_FRAC=17; 如果 PLL3_PFD3=454.7MHz 的话,PFD3_FRAC=19。

##PLL2 PFDx_FRAC
PLL2_PFD0_FRAC = 528*18/352 = 27
PLL2_PFD1_FRAC = 528*18/594 = 16
PLL2_PFD2_FRAC = 528*18/400 = 24 (400不能除尽,取一个最近的值396) 
PLL2_PFD3_FRAC = 528*18/200 = 47 ##PLL3 PFDx_FRAC
PLL3_PFD0_FRAC = 480*18/720   = 12
PLL3_PFD1_FRAC = 480*18/540   = 16
PLL3_PFD2_FRAC = 480*18/508.2 = 17
PLL3_PFD3_FRAC = 480*18/454.7 = 19

编写源码,设置 PLL2_PFD0~PLL2_PFD3,和 PLL3_PFD0~PLL3_PFD3。

/* 初始化时钟 */
void imx6u_clkinit(void)
{/* 初始化 IMX6U 的主频为528MHz */if(((CCM->CCSR >> 2) & 0x1) == 0){				/* 判断PLL1_SW_CLK_SEL位为0,当前使用 pll1_main_clk */CCM->CCSR &= ~(1<<8);						/* 设置CCM_CCSR STEP_SEL位,0 step_clk 选择 osc_clk 24MHz晶振 */CCM->CCSR |= (1<<2);						/* 设置PLL1_SW_CLK_SEL位为1,pll1_sw_clk切换到step_clk */}/* 设置PLL1为1056MHz */CCM_ANALOG->PLL_ARM &= ~(1 << 13);			/* 清零ANANLOG_PLL_ARM bit[13],关闭 pll1_main_clk */CCM_ANALOG->PLL_ARM &= ~0x7f;				/* 清零ANANLOG_PLL_ARM bit[6:0] *///CCM_ANALOG->PLL_ARM |= ((88 << 0) & 0x7f);	/* 设置ANANLOG_PLL_ARM bit[6:0], PLL1 frquencey=Frq*div_select/2 */CCM_ANALOG->PLL_ARM |= ((58 << 0) & 0x7f);	/* 设置PLL1为696MHz,  */CCM_ANALOG->PLL_ARM |= (1 << 13);			/* 设置ANANLOG_PLL_ARM bit[13] Enable=1, 开启 pll1_main_cl *//* pll1_sw_clk切换回pll1_main_clk(PLL1)*/CCM->CCSR &= ~(1<<2);/* 设置PLL1分频位2, 1056Mhz/2=528MHz *///CCM->CACRR = 0x1;							/* ARM_PODF divide by 2 */CCM->CACRR = 0x0;							/* ARM_PODF divide by 0 *///PLL2, System_PLL, PLL2_PFD0~PLL2_PFD3//CCM_ANALOG->PFD_528 &= ~(0xf3f3f3f3);		/* 清零PFD0~PFD3 FRAC */CCM_ANALOG->PFD_528 &= ~(0x3f3f3f3f);		/* 清零PFD0~PFD3 FRAC */CCM_ANALOG->PFD_528 |= (27U << 0)			/* PLL2_PFD0_FRAC=27 352MHz */CCM_ANALOG->PFD_528 |= (16U << 8)			/* PLL2_PFD1_FRAC=16 594MHz */CCM_ANALOG->PFD_528 |= (24U << 16)			/* PLL2_PFD2_FRAC=24 396MHz */CCM_ANALOG->PFD_528 |= (47U << 24)			/* PLL2_PFD3_FRAC=47 200MHz *///PLL3, USB1_PLL, 	PLL3_PFD0~PLL3_PFD3//CCM_ANALOG->PFD_480 &= ~(0xf3f3f3f3);		/* 清零PFD0~PFD3 FRAC */CCM_ANALOG->PFD_480 &= ~(0x3f3f3f3f);		/* 清零PFD0~PFD3 FRAC */CCM_ANALOG->PFD_480 |= (12U << 0)			/* PLL3_PFD0_FRAC=12 352MHz */CCM_ANALOG->PFD_480 |= (16U << 8)			/* PLL3_PFD1_FRAC=16 594MHz */CCM_ANALOG->PFD_480 |= (17U << 16)			/* PLL3_PFD2_FRAC=17 396MHz */CCM_ANALOG->PFD_480 |= (19U << 24)			/* PLL3_PFD3_FRAC=19 200MHz */}

实验遇到的错误记录:

这里我在做实验的写代码时还出了一个小的错误这里记录下来,我不小心讲清零 PFD0~PFD3 的代码 " PFD_528 &= ~(0x3f3f3f3f)",给错误的写成了 "PFD_528 &= ~(0xf3f3f3f3)",编译出来的 .bin 镜像收录到SD卡上后运行不正常。仔细分析 CCM_ANANLOG_PFD 的寄存器当使用 '0xf3’ 清零了 PFDx 的 PFDx_CLKGATE 后该 PFD时钟就被关闭了,因为 PLL2 的 PFD0~PFD3 是系统 System时钟给系统总线使用的,当错误的关闭了PFD0~PFD3后,处理器就运行不正常了。

 

3. AHB,IPG,PERCLK 根时钟设置

7路PLL和8路PFD设置完成以后,最后还需要设置 AHB_CLK_ROOT 和 IPG_CLK_ROOT的时钟,I.MX6U外设根时钟可以设置的范围见下表 "Table 18.4"。

缩写单词全程
AHB

Advanced High-performance Bus

高性能总线

IPG在NXP的I.MX6U文档里IPG是系统总线Bus的一种
PERCLK

Peripheral Clock

外设总线

AXI,AHB,IPG,PERCLK, 都是 I.MX6U 的总线时钟,本节我们将配置中配置这些总线失踪的频率为I.MX6U 参考手册中推荐的值,在I.MX6U 参考手册中推荐总线的频率见下表,我们会在本实验中将 AHB, IPG, PERCLK 的时钟设置为推荐的最大值。

表 "Table 18.4"给出了大多数外设的根时钟设置范围,AHB_CLK_ROOT的最高可以设置132MHz,IPG_CLK_ROOT和 PERCLK_CLK_ROOT 最高可以设置 66MHz。那么我们就将 AHB_CLOCK_ROOT, IPG_CLOCK_ROOT 和 PERCLK_CLK_ROOT 分别设置为 132MHz, 66Mhz 和 66Mhz。

AHB_CLK_ROOT 和 IPG_CLK_ROOT 的设计如下图所示。(I.MX6ULL参考手册》中 "Figure 18-5. BUS clock generation"):

图 18.5 中就是 AHB_CLK_ROOT 和 IPG_CLK_ROOT 的时钟图,图中分为了4部分:

  1. 此选择器用来选择 per_periph_clk 的时钟源,可以选择 PLL2, PLL2_PFD2, PLL2_PFD0 和 PLL2_PFD2/2 。寄存器 CCM_BMCMR 的 PER_PERIPH_CLK_SEL 位决定了选择哪一个,默认选择 PLL2_PFD2,因此 per_periph_clk = PLL2_PFD2=396Mhz。
  2. 此选择器用来选择 perph_clk 的时钟源,由寄存器 CCM_CBCDR 的 PERIPH_CLK_SEL 与 PLL_bypass_en2 组成的或来选择。当 CCM_CBCDR 的 PERIPH_CLK_SEL 位为0时 periph_clk = per_periph_clk = 396MHz
  3. 通过CCM_CBCDR 的 AHB_PODF 位来设置 AHB_CLK 的分频值,可以设置 1~8 分频值,如果想要 AHB_CLK_ROOT=132MHz的话就应该设置3分频:396/3=132Mhz。图中虽然写的是默认 4 分频,但是 I.MX6U 的内部 boot rom 将其改为了 3 分频!
  4. 通过 CCM_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 的时钟频率,其时钟结构图如下图所示:

从图中可以看到 PERCLK_CLK_ROOT 时钟由两种来源:

  1. OSC,24MHz晶振。
  2. IPG_CLK_ROOT,有寄存器 CCM_CSCMR1 的 PERCLK_PODF 位来决定,如果为0的话 PERCLK_CLK_ROOT 的时钟源就是 IPG_CLK_ROOT= 66MHz。

可以通过结存起 CCM_CSCMR1 的 PERCLK_PODF 位来设置分频,如果要设置 PERCLK_CLK_ROOT 为 66MHz的话就要设置1分频。

在上面用到的三个寄存器 CCM_CBCDR,CCM_CBCMR,CCM_CSCMR1,我们依次来看一下这些寄存器,CCM_CBCDR 的结构如16.1.6.4 所示:

 

寄存器 CCM_CBCDR中各个位的含义如下:

  • PERIPH_CLK_SEL:peripheral 主时钟的选择,如果为0的话选择PLL2,如果为1的话选择 periph_clk2_clk,修改此位会引起一次与 MMDC 的握手,所以修改完成以后要等待握手完成,握手完成信号由寄存器 CCM_CDHIPR 中的指示位表示。
  • AXI_PODF:axi时钟分频,可设置 0~7 ,分别对应 1~8 分频。修改此位会引起一次与EMI的握手,所有修改完成后等待握手完成,握手完成信号由寄存器 CCM_CDHIPR 中的指示位表示。
  • AHB_PODF:axi时钟分频,可设置 0~7 ,分别对应 1~8 分频。修改此位会引起一次与EMI的握手,所有修改完成后等待握手完成,握手完成信号由寄存器 CCM_CDHIPR 中的指示位表示。
  • IPG_PODF:ipg时钟分频,可设置0~3,分别对应1~4 分频。
  • AXI_ALT_CLK_SEL:axi_alt 时钟选择,位0的的话选择 PLL2_PFD2,如果为1的话选择 PLL2_PFD1。
  • AXI_CLK_SEL:axi时钟源选择,为0的话选择 periph_clk,为的话选择  axi_alt 时钟。
  • FABRIC_MMDC_PODF:fabric/mmdc 时钟的分频设置,可以设置0~7,分别对应 1~8 分频。
  • PERIPH2_CLK2_PODF:periph2_clk2 的时钟分频,可以设置0~7,分别对应 1~8 分频。

接下来看一下 CCM_CMCMR 寄存器的结构,如下图所示:

  • 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,寄存器结构如图 16.1.6.6 所示

此寄存器主要用于外设时钟源的选择,比如QSPI1, ACLK, GPMI, BCH, USDHC2, HSDHC1,SAI3,SAI2, SAI1 等外设。我们重点看一下下面两个位:

  • PERCLK_CLK_SEL:perclk 时钟源选择,位0的话选择 ipg_,为1的话选择 osc clk。
  • PERCLK_CLK_PODF:perclk 的时钟分频,可设置 0~7 ,分别对应 1~8 分频

4. 握手

在修改如下时钟选择器或者分频器的时候会引起与 MMDC 的握手发生

  • mmdc_podf
  • perph_clk_sel
  • periph2_clk_sel
  • arm_podf
  • ahb_podf

发生握手信号以后需要等待握手完成,寄存器 CCM_CDHIPR 中保存着握手信号是否完成,如果相应位为1的话就表示握手没有完成,如果为0的话就表示握手完成,很简单,这里就不在详细结局寄存器 CCM_CDHIPR 的各个位了。

另外再修改 arm_podf 和 ahb_podf 的时候需要先关闭器时钟输出,等待修改完成以后再打开,否则的话可能会出现在修改完成后没有时钟输出的问题。本教程需要修改寄存器 CCM_CBCDR的 AHB_PODF 位来设置 SHB_ROOT_CLK 的时钟,所以在修改完成之前必选先关闭 AHB_ROOT_CLK 的输出。但是笔者没有找到相应的寄存器,因此目前没法关闭,那也就没法设置 AHB_PODF 了。不过 AHB_PODF 内部 boot rom 设置为了 3 分频,如果 pre_periph_clk 的时钟源选择 PLL2_PFD2 的话, AHB_ROOT_CLK 也是 396MHz/3=132MHz。

5. AHB, IPG, PERCLK 根时钟修改源码

AHB_CLK_ROOT, IPG_CLK_ROOT,, PERCLK_CLK_ROOT, 根时钟修改源码如下

	/* AHB_CLK_ROOT 配置 */CCM->CBCMR &= ~(3 << 18);				/* PER_PERIPH_CLK_SEL位清零 */CCM->CBCMR |= (1 << 18);				/* PER_PERIPH_CLK_SEL=01, per_periph_clk=PLL2_PFD2=396Mhz */CCM->CBCDR &= ~(1 << 25);				/* PER_PERIPH_CLK_SEL位清零, 选择PLL2 pll2_main_clk *///手册指出修改此位需要等待握手成功// PER_PERIPH_CLK_SELwhile((CCM->CDHIPR & (1 << 5)));		/* PERIPH_CLK_SEL_BUSY 指示握手是否完成 */CCM->CBCDR &= ~(7 << 10);				/* AHB PODF位清零 */CCM->CBCDR |= (2 << 10);				/* AHB PODF=010, 3分频,AHB_CLK_ROOT=periph_clk/3=396/3=132MHz *///手册指出修改此位需要等待握手成功//AHB_PODF_BUSYwhile((CCM->CDHIPR & (1 << 1)));		/* AHB_PODF_BUSY 指示握手是否完成 *//* IPG_CLK_ROOT 配置 *//* 修改IPG_PODF前,关闭IPG_CLK_ROOT 输出*/CCM->CBCDR &= ~(3 << 8);				/* IPG_PODF清零 */CCM->CBCDR |= (1 << 8);					/* IPG_PODF=1, 2分频, IPG_CLK_ROOT=AHB_CLK_ROOT/2=132/2=66MHz *//* 修改IPG_PODF后,开启IPG_CLK_ROOT 输出*//* PERCLK_CLK_ROOT 配置 */CCM->CSCMR1 &= ~(1 << 6);				/* PERCLK_CLK_SEL清零, PERCLK_ROOT选择IPG_CLK_ROOT */CCM->CSCMR1 &= ~(0x3f);					/* PERCLK_PODF清零 */CCM->CSCMR1 |= (0x0);					/* PERCLK_PODF=0, 1分频,PERCLK_ROOT=IPG_CLK_ROOT/1=66MHz */

6. 编译源码烧录SD卡验证

编译源码烧录SD卡验证,看LED灯是否闪烁,蜂鸣器按键按下后是否鸣叫。我本地验证的结果是,LED灯闪烁正常,蜂鸣器按键控制正常。

7. 总结

需要注意的点是,在I.MX6U参考手册中指出修改时钟 Colock 的 PODF 分频时会引起时钟和MMDC重新握手,用户需要再程序中检查 CCM->CDHIPR 寄存器的 Busy 位来确定是否已经握手完成,Busy=1表示正在握手,Busy=0表示握手完成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/324436.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

轮式机器人简介

迄今为止,轮子一般是移动机器人学和人造交通车辆中最流行的运动机构。它可达到很高的效率, 如图所示, 而且用比较简单的机械就可实现它的制作。 另外,在轮式机器人设计中,平衡通常不是一个研究问题。 因为在所有时间里,轮式机器人一般都被设计成在任何时间里所有轮子均与地接…

idea上如何新建git分支

当前项目在dev分支&#xff0c;如果想在新分支上开发代码&#xff0c;如何新建一个分支呢&#xff1f;5秒搞定~ 1、工具类选择git&#xff0c;点击New Branch 或者右下角点击git分支&#xff0c;再点击New Branch 2、在弹出的Create New Branch弹窗中&#xff0c;输入你的新分支…

VMware 不能拍摄快照

问题&#xff1a; 拍摄快照后&#xff0c;会出现这个弹窗&#xff0c;然后虚拟机就直接自动退出了&#xff0c;还会弹出一个框&#xff1a; 解决方法&#xff1a; 我用的是 window11 和 VMware16.0.0 这是因为VM16与window11&#xff0c;二者之间版本不兼容问题&#xff0c;可…

Python 全栈系列243 S2S flask_celery

说明 按现有的几个架构部件&#xff0c;构建数据流。 S Redis Stream。这个可以作为缓冲队列和简单任务队列&#xff0c;速度非常快&#xff0c;至少是万条/秒的速度。 Q RabbitMQ。这个作为任务队列&#xff0c;消息也主要是元数据。读速比较慢&#xff0c;但有一些特性&a…

Linux(openEuler、CentOS8)常用的IP修改方式(文本配置工具nmtui+配置文件+nmcli命令)

----本实验环境为openEuler系统<以server方式安装>&#xff08;CentOS类似&#xff0c;可参考本文&#xff09;---- 一、知识点 &#xff08;一&#xff09;文本配置工具nmtui(openEuler已预装) nmtui&#xff08;NetworkManager Text User Interface&#xff09;是一…

【LeetCode算法】389. 找不同

提示&#xff1a;此文章仅作为本人记录日常学习使用&#xff0c;若有存在错误或者不严谨得地方欢迎指正。 文章目录 一、题目二、思路三、解决方案 一、题目 给定两个字符串 s 和 t &#xff0c;它们只包含小写字母。字符串 t 由字符串 s 随机重排&#xff0c;然后在随机位置添…

Linux第三节--常见的指令介绍集合(持续更新中)

点赞关注不迷路&#xff01;&#xff0c;本节涉及初识Linux第三节&#xff0c;主要为常见的几条指令介绍。 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1f44d;&#x1f3fb; 收藏 ✨ 加关注&#x1f440; 期待与你共同进步! Linux下基本指令 1. man指令 Linu…

【网络原理】HTTPS | 对称加密 | 非对称加密 | 中间人攻击 | 证书 | 公钥 | 私钥

文章目录 HTTPSHTTPS的工作过程1.对称加密&#xff0c;加密业务数据2.非对称加密&#xff0c;加密对称密钥中间人攻击 3.使用证书&#xff0c;校验服务器的公钥 HTTPS 在http的基础上引入了一个加密层 1.对称加密&#xff0c;加密和解谜使用同一个密钥 2.非对称加密。有两个…

linux性能监控之top

说完了atop和htop&#xff0c;我们在来说说Linux自带的top&#xff0c;我们先看看命令效果&#xff1a; 可以看到是一个实时的系统监控工具&#xff0c;提供了一个动态的、交互式的实时视图&#xff0c;显示系统的整体性能信息以及正在运行的进程的相关信息。 我们先来解析下命…

【解决问题】电脑耳机可以听到对方声音,对方听不到自己声音

背景&#xff1a; 项目线上开会&#xff0c;自己说话对方一直听不到&#xff0c;但是我可以听到对方的声音 问题排查&#xff1a; 针对这个问题&#xff0c;尝试重新启动电脑&#xff0c;各种查看声音设置&#xff0c;都没有解决 最后看声卡驱动&#xff0c;想更新声卡驱动…

学习网络需要认识的各种设备

网桥&#xff08;bridge&#xff09; 网桥工作在数据链路层&#xff0c;可以把多个局域网连接起来&#xff0c;组成一个更大的局域网 以太网中&#xff0c;数据链路层地址就是mac地址&#xff0c;网桥与集线器的区别就是&#xff0c;网桥会过滤mac&#xff0c;只有目的mac地址…

Ardupilot Rpanion iperf网络性能测试

Ardupilot Rpanion iperf网络性能测试 1. 源由2. 分析3. 安装4. 测试4.1 第一次测试4.1.1 iperf测试参数A4.1.1.1 测试链路14.1.1.2 测试链路24.1.1.3 测试链路3 4.1.2 iperf测试参数B - 测试链路34.1.2.1 测试数据4.1.2.2 数据简单分析4.1.2.3 数据深入分析4.1.2.4 模拟测试网…

【八】centos7.6安装chrome和chromedriver并启动selenium

学习来源&#xff1a; 安装chrome和chrome driver -----https://blog.csdn.net/zdlcome/article/details/133813441 安装Python11 -----https://blog.csdn.net/weixin_43741408/article/details/130251102 chromedriver下载地址 -----https://googlechromelabs.github.io/chrom…

# 从浅入深 学习 SpringCloud 微服务架构(八)Sentinel(1)

从浅入深 学习 SpringCloud 微服务架构&#xff08;八&#xff09;Sentinel&#xff08;1&#xff09; 一、sentinel&#xff1a;概述 1、前言 – 服务熔断 Hystrix 的替换方案。 1&#xff09;2018年底 Netflix 官方宣布 Hystrix 已经足够稳定&#xff0c;不再积极开发 Hys…

用标准的GNU/Linux命令替换Alpine上的精简版命令

Alpine Linux 是一个基于 musl libc 和 busybox 的轻量级Linux发行版&#xff0c;busybox 实现了很多常用类Unix命令的精简版&#xff0c;特点是体积很小&#xff0c;舍弃了很多不常用参数&#xff0c;我们简单对比一下标准Linux自带的 date 命令 和 Alpine下默认的 date 命令便…

初期Linux

一&#xff0c;系统分为 1.1window系统 个人 &#xff1a;win7&#xff0c;win8&#xff0c;Win10&#xff0c;Win11服务器版&#xff1a;window server 2003&#xff0c;window server 2008 1.2Linux系统 centos7redhatubantukali 1.3什么是Linux&#xff1f; Linux是基…

连通“数据”,让制造变“聪明”

说起数据智能&#xff0c;你第一时间想到的是什么呢&#xff1f;是科技感十足的智慧城市&#xff1f;还是炫酷的人工智能景象&#xff1f; 数据作为企业的战略资产越来越受到重视&#xff0c;从最初的数据协助业务协同&#xff0c;转化为数据驱动业务&#xff0c;数据驱动运营…

ORACLE ODAX9-2的一个误告警Affects: /SYS/MB的分析处理

在运维的多套ORACLE ODAX9-2版本&#xff0c;都遇到了一个计算节点的告警&#xff1a;Description: The service Processor poweron selftest has deteced a problem. Probabity;:100, UulD:cd1ebbdf-f099-61de-ca44-ef646defe034, Resource:/SYS/MB,&#xff1b;此告警从描述上…

静态分析-RIPS-源码解析记录-01

token流扫描重构部分&#xff0c;这一部分主要利用php的token解析api解析出来的token流&#xff0c;对其中的特定token进行删除、替换、对于特定的语法结构进行重构&#xff0c;保持php语法结构上的一致性 解析主要在lib/scanner.php中通过Tokenizer这个类来实现,也就是在main…

怎么把手机ip地址变成了外省

在日常使用中&#xff0c;有时我们可能因为某些原因需要快速切换手机的IP地址&#xff0c;特别是当需要从一个省份切换到另一个省份的IP时。这种需求可能来源于网络访问限制、地理位置相关服务的使用、或者网络安全等方面的考虑。那么&#xff0c;怎么把手机IP地址变成外省呢&a…