当前位置: 首页 > news >正文

时钟(6.25-26)

       IMX有着一套复杂的时钟系统。时钟指的是系统运行时的频率,我们通常所讲的主频,其实指的就是内核运行程序时的速度问题。IMX考虑到不同的外设需要的时钟频率是不一样的,给所有外设提供同样的时钟对于低速设备来说是一种浪费(功耗更大)。所以imx6ull把主频分成不同频率时钟以提供给不同的外设使用。这个概念被称之为时钟树,这是因为无论哪种Soc通常都是由一个Soc外部的晶体振荡器提供最基本的频率,之后通过Soc内部复杂的电路进行分离的。形式上很像一棵树的样子,所以被称为时钟树。

        1、在开始介绍IMX的时钟之前,我们必须先搞清除: PLL、 PFD和divider

PLL(Phase Locked Loop)锁相环,倍频电路。 通过PLL就可以把一个低频升到较高的一个频率。fo = fi * a

divider分频器。把一个高频降低成一个低频。fo = fi / b

PFD: Phase Fractional Dividers,相位分数分频器,我们可以理解为将 PLL 输出再乘以一个分数(分数可以大于 1,也可以小于 1),然后再做为输出。fo = fi * a / b

        先看PLL,打开手册第十章 Clock and Power Management第350页,图中展示了 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 分出了 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。此PLL其实相当于是USB1 PLL的旁路输出,一般是用于检测的。

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、I.MX6U 的所有外设时钟源都是从这 7 路 PLL 和有些 PLL 的PFD 而来的,这些外设究竟是如何选择 PLL 或者 PFD 的?时钟树

这个图从左往右分为三个部分: CLOCK_SWITCHER、 CLOCK ROOT GENERATOR 和SYSTEM CLOCKS。其中左边的 CLOCK_SWITCHER 就是我们上一小节讲解的那 7 路 PLL 和8 路 PFD,右边的 SYSTEM CLOCKS 就是芯片外设,中间的 CLOCK ROOT GENERATOR  给左边的 CLOCK_SWITCHER 和右边的 SYSTEM CLOCKS进行牵线搭桥。外设时钟源是有多路可以选择的, CLOCK ROOT GENERATOR 就负责从 7 路PLL 和 8 路 PFD 中选择合适的时钟源给外设使用。

以Enhanced Serial Audio Interface (ESAI) 这个外设为例, ESAI 的时钟图如图:

图示我们分为了 3 部分,这三部分如下:

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

② 此部分是 ESAI 时钟的前级分频,分频值由寄存器 CCM_CS1CDR 的 ESAI_CLK_PRED来确定的,可设置 1~8 分频,假如现在 PLL4=650MHz,我们选择 PLL4 作为 ESAI 时钟,前级分频选择 2 分频,那么此时的时钟就是 650/2=325MHz。

③ 此 部分又 是一 个分 频器, 对② 中输出 的时钟 进一 步分频 ,分 频值 由寄存 器CCM_CS1CDR 的ESAI_CLK_PODF 来决定,可设置 1~8 分频。假如我们设置为 8 分频的话,经过此分频器以后的时钟就是 325/8=40.625MHz。因此最终进入到 ESAI 外设的时钟就是40.625MHz。

3、时钟设置

假如我们要设置内核主频为 528MHz,那么 PLL1 可以设置为1056MHz,寄存器 CCM_CACRR 的 ARM_PODF 位设置为 2 分频即可。同理,如果要将主频设置为696MHz,那么 PLL1 就可以设置为 696MHz, CCM_CACRR 的 ARM_PODF 设置为 1 分频即可。那么这里有两个问题: PLL1如何设置为1056? CCM_CACRR寄存器怎么设置?

        1、PLL1的设置, PLL1又称ARM_PLL,这个PLL的设置是通过寄存器CCM_ANALOG_PLL_ARMn来设置的(第714页)下图。事实上其他的几个PLL和PFD都是通过CCM_ANALOG章节中介绍的几个寄存器来设置的(第710页)。寄存器 CCM_CACRR 只有 ARM_PODF 位,可以设置为 0~7,分别对应 1~8 分频。如果要设置为 2分频的话 CCM_CACRR 就要设置为 1。


在修改 PLL1 时钟频率的时候我们需要先将内核时钟源改为其他的时钟源,因为PLL1是给ARM内核提供时钟的,在切换时钟时ARM内核有可能会由于时钟不稳定导致停摆。幸好, PLL1 可选择的,我们可以先把PLL1切换到另外一个时钟源上,之后设置完528M之后再切换回来。 PLL1时钟源如图:手册第648页

① pll1_sw_clk 也就是 PLL1 的最终输出频率,也就是ARM内核实际使用的频率;

② pll1_sw_clk是可以选择的,由 寄 存 器 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 调整完成以后再切换回来。

③ 此处也是一个选择器,选择 step_clk 的时钟源,由寄存器 CCM_CCSR 的 STEP_SEL 位来决定 step_clk 是选择 osc_clk 还是 secondary_clk。一般选择 osc_clk,也就是 24MHz 的晶振。

参考一下CCM_CCSR寄存器:

总结一下:对于IMX6U的主频(ARM内核)的设置步骤如下:

1. 设置寄存器 CCSR 的 STEP_SEL 位,设置 step_clk 的时钟源为 24M 的晶振。

2. 设置寄存器 CCSR 的 PLL1_SW_CLK_SEL 位,设置 pll1_sw_clk 的时钟源为step_clk=24MHz,通过这一步我们就将 I.MX6U 的主频先设置为 24MHz,直接来自于外部的24M 晶振。

3. 设置寄存器 CCM_ANALOG_PLL_ARMn,将 pll1_main_clk(PLL1)设置为 1056MHz。

4. 设置寄存器 CCM_CACRR 的 ARM_PODF 为 2 分频, pll1_sw_clk就为1056/2=528MHz。

5. 设置寄存器 CCSR 的 PLL1_SW_CLK_SEL 位,重新将 pll1_sw_clk 的时钟源切换回pll1_main_clk,切换回来以后 I.MX6U 的内核主频就等于 528MHz。

设置好主频以后我们还需要设置好其他的 PLL 和 PFD 时钟。 PLL1刚才已经设置过了, PLL2、PLL3 和 PLL7 固定为 528MHz、 480MHz 和 480MHz, PLL4~PLL6 都是针对特殊外设的,用到的时候再设置。因此,接下来重点就是设置 PLL2 和 PLL3 的各自 4 路 PFD, NXP 推荐的这 8 路 PFD 频率如下表所示:

以PLL2_PFD0为例,手册第350页指出, PLL_PFDn都可以以PLL2作为时钟源,而PLL2又被称为528PLL(因为PLL2的时钟固定为528MHz)。那么想把528MHz转变为PLL2_PFD0的352MHz,那肯定需要设置一个系数,这个系数由寄存器CCM_ANALOG_PFD_528n来设置,来看一下这个寄存器:

这个寄存器被分成了四个部分,分别对应PFD0~PFD3,每个部分又有四个域: PFD0_FRAC: PLL2_PFD0的分频数, PLL2_PFD0 的计算公式为 528*18/PFD0_FRAC,此为 可 设 置 的 范 围 为 12~35 。 如 果PLL2_PFD0 的 频 率 要 设 置 为 352MHz 的 话PFD0_FRAC=528*18/27=352; PFD0_STABLE: 此位为只读位,可以通过读取此位判断 PLL2_PFD0 是否稳定; PFD0_CLKGATE: PLL2_PFD0 输出使能位,为 1的时候关闭 PLL2_PFD0 的输出,为 0 的时候使能输出。
很明显,设置PLL2_PFDn的频率值,都是按照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。那么PLL2的四个PFD设置就应该是分别设置四个部分的PFDn_FRAC,将PFDn_CLKGATE清零以使能时钟输出(提供给根时钟,外设才能正常使用)。至于PFDn_STABLE 手册上说是用于诊断的,驱动程序和应用程序永远都不要用它。

同理, PLL3_PFDn的设置方法根PLL2_PFDn设置方法类似,不同之处在于PLL3又被称为480PLL,因为PLL2的频率固定为480MHz。因此计算公式也就变成480/PFDx_FRAC(x=1~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。

7 路 PLL 和 8 路 PFD 设置完成以后最后还需要设置 AHB_CLK_ROOT 和 IPG_CLK_ROOT的时钟, I.MX6U 外设根时钟可设置范围如下图(手册 第643页)所示:

7 路 PLL 和 8 路 PFD 设置完成以后最后还需要设置 AHB_CLK_ROOT 、 IPG_CLK_ROOT和PERCLK_CLK_ROOT的时钟, I.MX6U 外设根时钟可设置范围如下图所示(请查阅时钟树,对照分析这三个根时钟的作用):
我们之所以要设置AHB_CLK_ROOT 、 IPG_CLK_ROOT和PERCLK_CLK_ROOT的时钟,是因为我们之后的外设实验需要使用这三个时钟,从时钟树图中可以看出: IPG_CLK_ROOT和PERCLK_CLK_ROOT分别给ADC和I2C外设提供时钟,这两个外设是我们之后要学习的重点,而这两个根时钟又是由AHB_CLK_ROOT 提供时钟的。因此配置好这三个时钟是我们之后学习的基础保障。

这三个时钟的配置方法是多样的、灵活的。这里选择PLL2_PFD2(396MHz)作为输入时钟,我们来分析以下整个时钟配置流程:首先上图给出了大多数外设的根时钟设置范围, AHB_CLK_ROOT 最高可以设置 132MHz, IPG_CLK_ROOT 和 PERCLK_CLK_ROOT 最高可以设置 66MHz。那我们就将 AHB_CLK_ROOT、 IPG_CLK_ROOT 和 PERCLK_CLK_ROOT 分 别 设 置 为 132MHz 、 66MHz 、66MHz 。

从图示标记的红色箭头线开始, PLL2_PFD2(标记的是400MHz,实际是396MHz)。首先到达一个四通道选择器,由CBCMR寄存器PRE_PERIPH_CLK_SEL域决定输入通道,这肯定是我们需要设置的,之后道道一个2通道选择器,由CBCDR寄存器PERIPH_CLK_SEL决定,再到达一个4位分频器,分频值由CDCDR寄存器AHB_PODF决定。此时AHB_CLK_ROOT就已经被确定下来了,之后由来到一个2位分频器CBCDR的IPG_PODF决定,产生出IPG_CLK_ROOT,并且兵分两路,经由一个2通道选择器,由CSCMR1寄存器的PERCLK_PODF域决定,再经由一个6位分频器由CSCMR1的PERCLK_PODF域决定,最终产生PERCLK_CLK_ROOT。那么剩下的就是去查阅相关上述所涉及到的各个寄存器,将其配置好就可以了。

注意:在设置AHB_PODF 位的时候需要先禁止 AHB_CLK_ROOT 的输出,这是因为有的外设无法接受时钟的剧烈波动,但是手册没有找到关闭 AHB_CLK_ROOT 输出控制的寄存器,所以就没法设置。但是内部 boot rom 将 AHB_PODF 设置为了 3 分频,也就是说即使我们不设置 AHB_PODF, AHB_ROOT_CLK 也依旧等于 396/3=132Mhz。

下面开始编码,新建一个工程,修改clk.c中的初始化CCM函数:

首先是设置PLL1(ARM_PLL),按照之前的分析,逐步编写就可以了

分别设置PLL2的四个PFD和PLL3的四个PFD。

分别设置AHB_CLK的时钟源位PLL2_PFD2,将该频率3分频作为AHB_CLK_ROOT ;然后2分频最为IGP_CLK_ROOT,之后1分频作为PERCLK_CLK_ROOT。

至此时钟设置完毕,某些外设我们在需要的时候再来设置。

下载程序后看不出有太大的变化,对于PLL1来说,如果Led采用软件延时周期性闪烁的话,经过设置会闪烁得更快些。其他的频率是否正确只能在使用相关外设的时候才能验证。

http://www.dtcms.com/a/265037.html

相关文章:

  • pppoe宽带连接-系列命令调用
  • 使用Process Monitor定位benchstat工具执行过程
  • Almalinux_10.0下MySQL的多表操作与函数使用
  • 智慧城市的安全密码:商用密码如何守护万物互联?
  • 鸿蒙自定义相机的拍照页面
  • 荧光原位杂交(FISH)-实验操作-011
  • LeetCode[617]合并二叉树
  • 从SEO到GEO:AI时代的品牌大模型种草与数字营销重构
  • 【记录】基于 C++ 和 Winsock 的简单 TCP 通信实现
  • 健康医疗类Agent推荐有哪些
  • 下载公开的dahiti全球水位数据
  • 通过异步解决超时问题-使用 Spring 的 @Async 实现异步调用
  • Python毕业设计230—基于python+爬虫+vue的豆瓣影视数据可视化系统(源代码+数据库+15000字论文+开题+答辩ppt)
  • 构建灵活的监控系统:多表存储与动态告警规则设计实践
  • 智能防御原理和架构
  • dial tcp 10.1.68.88:3306: connect: cannot assign requested address
  • 中心化钱包安全方案
  • 跨平台开发的抉择:Flutter vs 原生安卓(Kotlin)的优劣对比与选型建议​​
  • Kotlin Data包含ByteArray类型
  • Dify 工作流全栈解析:从零构建你的 AI 应用流程引擎
  • 如何看待RWA赛道
  • 前端代码优化规范及实践指南
  • leetcode TOP 100 1. 两数之和
  • Centos系统及国产麒麟系统设置自己写的go服务的开机启动项完整教程
  • CentOS 6操作系统安装
  • win11, 两个窗口短时间多次切换时,原本的英文输入法会自动变更成中文输入法。有时候是中文输入法变更成英文输入法
  • 014_循环语句(for / for-each / while / do-while)
  • LeetCode 11.盛最多水的容器
  • Binder机制与实现原理解析
  • 达梦数据库一键安装脚本详解