LV005-imx6ull的时钟系统
I.MX6U 的系统主频为 528MHz,有些型号可以跑到 696MHz,但是默认情况下内部 boot rom 会将 I.MX6U 的主频设置为 396MHz(前边学习启动方式的时候有提到过)。我们在使用 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. 时钟的产生
时钟信号不是凭空产生的,芯片首先需有一个频率较低的源时钟信号。imx6ull 包含两个偏压放大器( biased amplifier),当外部连接合适的晶振和负载电容时,能够分别产生 24MHZ 和 32KHZ 的时钟信号。 打开 I.MX6U-ALPHA 开发板原理图,开发板时钟原理图如图 :

可以看出 I.MX6U-ALPHA 开发板的系统时钟来源于两部分: 32.768KHz 和 24MHz 的晶振,其中 32.768KHz 晶振是 I.MX6U 的 RTC 时钟源, 24MHz 晶振是 I.MX6U 内核和其它外设的时钟源。
当 imx6ull 的时钟引脚 XTALI 和 XTALO 连上合适的晶振和电容时,模块 XTALOSC24M 会产生 24MHZ 的时钟信号。注意,输出频率到达 24MHZ 并不意味着模块 XTALOSC24M 已经稳定工作,仍然需要等待一段时间。一旦时钟信号稳定,可以通过设置寄存器来降低它的工作电流;但是注意,在关闭模块 XTALOSC24M 电源之前,相应的值应当被恢复,否则恢复供电时模块不能正常启动。
另外, imx6ull 还有一个内置的 24MHZ RC 振荡器,它以 RTC 时钟( 32KHZ)做基准产生时钟信号。尽管能源消耗显著低于模块 XTALOSC24M,但是它的精确度存在较大误差,实际应用中应当避免使用它。
当 imx6ull 的时钟引脚 RTC_XTALI 和 RTC_XTALO 连接 32KHZ 或 32.768KHZ 的晶振时,用模块 RTC_XTAL 产生 32KHZ 的 RTC 时钟信号。除此之外, imx6ull 还包含一个内部的 32KHZ 振荡器,当时钟系统探测到 RTC 振荡器丢失时钟信号时,会自动切换到内部的 32KHZ 振荡器。但是由于该内部振荡器精度不如模块 RTC_XTAL,不能作为替代品长时间使用。
RTC 时钟信号主要用来记录时间,而 XTALOSC24M 的输出时钟信号为芯片的时钟体系提供基础的源时钟信号。除此之外,芯片本身也可以直接接收时钟信号作为源时钟信号,这需要芯片外部提供一个稳定的时钟信号源。但这种方式较不常用。
2. 锁相环电路
XTALOSC24M 的时钟信号只有 24MHZ,远远不能满足实际需求,在芯片中需要进行稳定和倍频操作,这主要是由锁相环电路完成的。
锁相环( PLL)由鉴相器 PD、低通滤波器 LPF 和压控振荡器 VCO 组成。鉴相器( PD)用来鉴别两个输入时钟信号之间的相位差,并输出误差电压,经过低通滤波( LPF)后,形成压控振荡器( VCO)的控制。压控振荡器的输出经过分频( DIV)后反馈到鉴相器与基准信号进行比较,最终, VCO 的输出就会稳定下来。下图是锁相环工作原理示意图:
二、7 路 PLL 时钟源
1. 7 个时钟源的作用
imx6ull 包含 7 个锁相环电路,它们的输入时钟信号称为源时钟信号,可通过寄存器选择,通常为 XTALOSC24M 产生的 24MHZ 时钟信号。它们的输出经过进一步选择和分频,形成不同的根时钟信号,分发到各个模块使用。
I.MX6U 的外设有很多,不同的外设时钟源不同, NXP 将这些外设的时钟源进行了分组,一共有 7 组,这 7 组时钟源都是从 24MHz 晶振 PLL 而来的,这 7 组 PLL 结构如图(参考手册 10.3.1 Centralized components of clock management system):

①、ARM_PLL(PLL1),此路 PLL 是供 ARM 内核使用的, ARM 内核时钟就是由此 PLL 生成的,此 PLL 通过编程的方式最高可倍频到 1.3GHz。注意 这个频率超过了芯片能够工作的最大频率 1GHZ。
②、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 接口等等。
③、 USB1_PLL(PLL3),此路 PLL 主要用于 USBPHY,此 PLL 也有四路 PFD,为:PLL3_PFD0~PLL3_PFD3, USB1_PLL 是固定的 20 倍频,因此 USB1_PLL = 24MHz *20 = 480MHz。USB1_PLL 虽然主要用于 USB1PHY,但是四路 PFD 同样也可以作为其他需要固定频率的根时钟,比如 UART 和其它的串行接口,音频接口等。
④、 USB2_PLL(PLL7,没有写错!就是 PLL7,虽然序号标为 4,但是实际是 PLL7),看名字就知道此路 PLL 是给 USB2PHY 使用的。同样的,此路 PLL 固定为 20 倍频,因此也是 480MHz。
⑤、 ENET_PLL(PLL6),此路 PLL 固定为 20+5/6 倍频,因此 ENET_PLL = 24MHz * (20+5/6)= 500MHz。它主要用来生成:50MHZ 或 25MHZ 时钟,用于外部以太网接口;125MHZ 时钟,用于精简的千兆以太网接口;100MHZ 时钟,用于通用功能。
⑥、 VIDEO_PLL(PLL5),它具有倍频和分频功能,能够产生低抖动、高精度标准视频时钟信号。此路 PLL 主要作为显示和视频接口的时钟信号,比如 LCD,此路 PLL 的倍频可以调整, PLL 的输出范围在 650MHz~1300MHz。时钟的频率分辨率要好于 1HZ。另外,VIDEO_PLL 的分频器,可对 VCO 的输出时钟信号进行/1、 /2、 /4 或 /8 分频。
⑦、 AUDIO_PLL(PLL4),此路 PLL 用于音频相关的外设,此路 PLL 的倍频可以调整,能够进行倍频和分频操作,产生低抖动、高精度标准音频时钟信号。PLL 的输出范围是 650MHz~1300MHz,时钟的频率分辨率要好于 1HZ。该输出时钟信号主要用来驱动串行音频接口或者作为外部音频解码器的参考时钟。另外, AUDIO_PLL 的分频器,可对 VCO 的输出时钟信号进行/1、 /2 或 /4 分频。
2. 锁相环电路模式
那 7 个锁相环电路都有自己专门的控制和状态寄存器,它们可独立配置为以下 3 个模式中的一种:
(1)Bypass 模式: PLL 输入的参考时钟直接传递到输出,由 BYPASS 位控制;
(2)输出禁止模式:无论 bypass 时钟还是 PLL 生成的时钟均被禁止,无输出时钟信号,由 ENABLE 位控制;
(3)断电模式: PLL 中大部分电路断电,无输出时钟信号,由 POWERDOWN 位控制。
以 ARM_PLL 为例,单独截取出来说明,见下图。 PLL 正常工作时,时钟信号通过路径 1 传输作为信号 ref_armpll_clk 输出;处于 Bypass 模式时,源时钟信号不经过 PLL 放大,由路径 2 直接输出;处于输出禁止模式时,时钟信号在 armpll_enable 处被屏蔽, ref_armpll_clk 无输出;处于断电模式时,ARM_PLL 大部分电路断电,电路不工作, ref_armpll_clk 无输出信号。

其中,两个锁相环电路 SYS_PLL 和 USB1_PLL:

分别带有四个分相器( PFD)对其产生的 PLL 输出信号进行分频(每个分相器可独立设置分频参数),用来产生额外的频率输出。由于分相器完全由数字器件组成且不包含反馈回路,我们只需要改变逻辑组合就能改变分频参数的值,不影响锁相环电路的锁定状态,因此分相器能够比锁相环更快的改变输出频率。除此之外,分相器的值还能在运行时改变,不需要在改变前后关闭和开启时钟的输出。
注意,对于那些包含分相器的锁相环电路,每个分相器有自己独立的时钟屏蔽控制位。当相连的锁相环电路加电启动或者重新锁定时,分相器自动进入屏蔽状态,需要手动对每个 PFD 进行一次屏蔽和开启操作。
3. 根时钟信号电路
锁相环电路的输出时钟信号并不能直接供其它模块使用。在 imx6ull 中,它们的输出时钟信号、 PFD 时钟信号以及对应的 bypass 时钟信号经过选择、分频后形成根时钟信号,才会分发到各个模块。这部分电路又细分为两部分,前半部分称为时钟切换电路( switcher),后半部分称为根时钟生成电路( root generator)。
时钟切换电路主要对 PLL1 和 PLL3 的输出进行选择,被选中的信号形成 pll1_sw_clk 和 pll3_sw_clk 信号。另外,它还对 PLL4 和 PLL5 进行额外的分频操作,形成 pll4_main_clk 和 pll5_main_clk 信号。如下图所示:

后续电路不直接使用上述 PLL 的输出,而是使用 switcher 形成的这些输出信号。例如,如果我们想改变 CPU 的工作频率,可以先修改 CCSR[pll1_sw_clk_sel]将 pll1_sw_clk 切换到 step_clk,然后修改 PLL1 的参数,等待其输出时钟信号稳定到新的频率上,再切换回 PLL1 的输出信号 pll1_main_clk。因为使用了无抖动的多路选择器( glitchless multiplexer),在切换过程中 CPU 仍正常运行。
根时钟生成电路对前面的这些信号和 PLL2 的输出信号进一步筛选和分频形成根时钟信号,它们直接或者间接驱动芯片中的模块来实现各自功能。这里仅以 总线相关的根时钟信号进行说明,如下图所示

其它的根时钟信号和模块对这些根时钟信号的使用参见 CCM 和模块各自的寄存器设置。
三、时钟树简介
在上一小节学习了 7 路 PLL, I.MX6U 的所有外设时钟源都是从这 7 路 PLL 和有些 PLL 的 PFD 而来的,这些外设究竟是如何选择 PLL 或者 PFD 的?这个就要看《IMX6ULL 参考手册》里面的时钟树了,在“Chapter 18 Clock Controller Module (CCM)”的 18.3 小节给出了 I.MX6U 详细的时钟树图,如图:

在图中一共有三部分: 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 中选择合适的时钟源给外设使用。具体操作肯定是设置相应的寄存器,我们以 ESAI 这个外设为例, ESAI 的时钟图如下图所示:

①、此部分是时钟源选择器, 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。