提前了解:
本文仅对IMX6ULL时钟做一个简单介绍,其他相应的芯片时钟也可以对照该文章进行参考使用,但是具体的芯片使用还需要认真查看相应的芯片手册,根据时钟树来寻找对应寄存器设置。对于时钟的应用就是几个字:先倍频,再分频
一、IMX6ULL时钟体系介绍
1.1 晶体振荡电路
时钟信号不是凭空产生的,芯片首先需有一个频率较低的源时钟信号。imx6ull包含两个偏压放大器(biased amplifier),当外部连接合适的晶振和负载电容时,能够分别产生24MHZ和32KHZ的时钟信号。
下面是开发板的时钟引脚连接原理图:
IIMX6ULL的时钟源有两个:24M外部晶振和32.768K晶振,其中32.768K晶振用于内部RTC模块使用。24M外部晶振用于内核和各种外设使用,是时钟树的根源。
当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的输出时钟信号为芯片的时钟体系提供基础的源时钟信号,是本篇讨论的重点。
除此之外,芯片本身也可以直接接收时钟信号作为源时钟信号,这需要芯片外部提供一个稳定的时钟信号源。这种方式较不常用,本文不再进行描述。
1.2 锁相环电路(PLL)
XTALOSC24M的时钟信号只有24MHZ,远远不能满足实际需求,在芯片中需要进行稳定和倍频操作,这主要是由锁相环电路完成的。在生成7路PLL和8路PFD后,系统产生了足够的时钟源。
锁相环(PLL)由鉴相器PD、低通滤波器LPF和压控振荡器VCO组成。鉴相器(PD)用来鉴别两个输入时钟信号之间的相位差,并输出误差电压,经过低通滤波(LPF)后,形成压控振荡器(VCO)的控制。压控振荡器的输出经过分频(DIV)后反馈到鉴相器与基准信号进行比较,最终,VCO的输出就会稳定下来。下图是锁相环工作原理示意图:
1.2.1 7个PLL介绍
imx6ull包含7个锁相环电路,它们的输入时钟信号称为源时钟信号,可通过寄存器选择,通常为XTALOSC24M产生的24MHZ时钟信号。它们的输出经过进一步选择和分频,形成不同的根时钟信号,分发到各个模块使用。这些锁相环电路及它们的分频器输出如下图所示:
下面分别介绍这些PLL的功能。
PLL1:
被称为ARM_PLL,用来驱动ARM核心工作。它能够倍频达到1.3GHZ,注意这个频率超过了芯片能够工作的最大频率1GHZ。
PLL2:
被称为SYS_PLL或者528_PLL。它的倍频参数固定在x22,在使用XTALOSC24M产生的24MHZ时钟作为参考时钟时,产生528MHZ的输出。除了这个主输出,SYS_PLL还包含四个分频器,主输出和分频器的输出可用来作为根时钟。SYS_PLL的这些输出时钟信号的频率并不需要是确定或者精确的值,可在运行时动态进行改变。通常,它们用来驱动芯片内部的系统总线,内部处理逻辑,DDR接口以及NAND/NOR等等。
PLL3:
被称为USB1_PLL,用来驱动第一个USB物理层实体USBPHY1。它的倍频参数固定在x20,在使用24MHZ参考时钟时产生480MHZ的输出。除了主输出之外,USB1_PLL同样包含四个分频器,它们的输出用来作为需要固定频率的根时钟,比如UART和其它的串行接口,音频接口等。
PLL4:
被称为AUDIO_PLL,能够进行倍频和分频操作,产生低抖动、高精度标准音频时钟信号。AUIDIO_PLL的输出频率范围从650MHZ到1300MHZ,时钟的频率分辨率要好于1HZ。该输出时钟信号主要用来驱动串行音频接口或者作为外部音频解码器的参考时钟。另外,AUDIO_PLL的分频器,可对VCO的输出时钟信号进行/1、/2或/4分频。
PLL5:
被称为VIDEO_PLL。它同样具有倍频和分频功能,能够产生低抖动、高精度标准视频时钟信号。VIDEO_PLL的输出频率范围从650MHZ到1300MHZ,时钟的频率分辨率要好于1HZ。该输出时钟主要作为显示和视频接口的时钟信号。另外,VIDEO_PLL的分频器,可对VCO的输出时钟信号进行/1、/2、/4或/8分频。
PLL6:
被称为ENET_PLL。它的倍频参数固定为x20+(5/6),在使用24MHZ参考时钟时产生500MHZ的输出。它主要用来生成:(1)50MHZ或25MHZ时钟,用于外部以太网接口;(2)125MHZ时钟,用于精简的千兆以太网接口;(3)100MHZ时钟,用于通用功能。
PLL7:
被称为USB2_PLL,专门用于驱动第二个USB物理层实体USBPHY2。它的倍频参数固定为x20,输出480MHZ的时钟信号。
1.2.2 锁相环电路的三种模式
上述锁相环电路都有自己专门的控制和状态寄存器,它们可独立配置为以下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无输出信号。
上图来自芯片手册:Figure 10-3. Primary Clock Generation
其中,两个锁相环电路SYS_PLL和USB1_PLL,分别带有四个分相器(PFD)对其产生的PLL输出信号进行分频(每个分相器可独立设置分频参数),用来产生额外的频率输出。由于分相器完全由数字器件组成且不包含反馈回路,我们只需要改变逻辑组合就能改变分频参数的值,不影响锁相环电路的锁定状态,因此分相器能够比锁相环更快的改变输出频率。除此之外,分相器的值还能在运行时改变,不需要在改变前后关闭和开启时钟的输出。
注意,对于那些包含分相器的锁相环电路,每个分相器有自己独立的时钟屏蔽控制位。当相连的锁相环电路加电启动或者重新锁定时,分相器自动进入屏蔽状态,需要手动对每个PFD进行一次屏蔽和开启操作。
1.3 根时钟信号电路
在生成7路PLL和8路PFD后,系统产生了足够的时钟源,但是如何供给外设使用呢,这就需要CLOCK ROOT GENERATOR牵线搭桥。其作用就是根据实际需要,选择合适的时钟源,并对其进行分频,倍频,切换等工作,从而让外设拥有合适的时钟源
如前所述,锁相环电路的输出时钟信号并不能直接供其它模块使用。在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和模块各自的寄存器设置,这里不再展开叙述。本章第二个编程示例计算锁相环电路输出时钟和这些总线的根时钟的频率并打印出来,有兴趣的同学也可以参照示例代码和imx6ull手册计算其它的时钟信号的频率。
二、 寄存器介绍
imx6ull时钟相关的寄存器主要分布在CCM和ANALOG_DIG这两个模块,它们均连接在AIPS-1总线上,它们的地址范围如下所示:
ANALOG_DIG模块主要负责晶体振荡电路和锁相环电路的相关设置。
它的寄存器分为两类:
CCM_ANALOG_PLL_xxx寄存器:
设置对应PLL的参数和工作状态。
CCM_ANALOG_MISCx (x = 0-2)寄存器:
进行其它一些杂项的设置或状态显示,包括晶体振荡电路的控制参数。这些寄存器数量较多,这里不一一列出。
另外需要注意,ANALOG_DIG与电源管理模块(PMU)共用这些CCM_ANALOG_MISCx寄存器,它们在PMU中被称为PMU_MISCx (x = 0-2)。由于晶体振荡电路在系统启动时已初始化完毕,输出频率固定的时钟信号,在芯片运行期间通常不需要修改设置,这里不再进行说明。
而CCM模块控制根时钟信号的产生和分发,大部分寄存器用来对PLL及PFD产生的时钟信号进行分发和分频控制,如下表所示:
以及下面的表,注意红框部分的寄存器CCM_CCGRx(x = 0-6),它们用来控制各个时钟信号在不同功耗模式下是否被屏蔽:
2.1 锁相环电路寄存器
如前所述,imx6ull共包含7个锁相环电路,除ENET_PLL(PLL6)之外,其它的锁相环电路控制和状态寄存器的结构都很类似。以ARM_PLL为例,它的寄存器结构如下所示:
其中,控制位BYPASS、ENABLE和POWERDOWN用来控制PLL的工作模式(bypass模式、输出禁止模式和断电模式);BYPASS_CLK_SRC选择输入时钟源,DIV_SELECT设置频率放大倍数。正常工作时,需要设置BYPASS和POWRDOWN为0,ENABLE为1。当LOCK值为1时,锁相环电路输出稳定的时钟信号。
稳定工作时,ARM_PLL的输出频率为 Fref * DIV_SELECT/2,其它PLL的设置方法和输出频率计算公式与ARM_PLL类似,但略有差别。例如,锁相环电路USB1_PLL、USB2_PLL和SYS_PLL虽然都有自己的DIV_SELECT,它们应当被设为固定的值。
需要特别说明的是,锁相环电路AUDIO_PLL和VIDEO_PLL还增加了额外的分频参数NUM和DENOM。以AUDIO_PLL为例,它的相应寄存器如下所示:
(1)CCM_ANALOG_PLL_AUDIO_NUM
(2)CCM_ANALOG_PLL_AUDIO_DENOM
它们的输出频率为Fref * (DIV_SELECT + NUM/DENOM)。除此之外,AUIDIO_PLL和VIDEO_PLL还可以在时钟切换电路(switcher)中设置额外的分频参数为/1、/2、/4、/8或/16,这些值分布在寄存器CCM_ANALOG_PLL_AUDIO、CCM_ANALOG_PLL_VIDEO和CCM_ANALOG_MISC2中。
除此之外,SYS_PLL和USB1_PLL还各自配有四个分相器,它们分别对SYS_PLL和USB1_PLL的输出时钟信号进行分频,分频参数分别在CCM_ANALOG_PFD_480n和CCM_ANALOG_PFD_528n中设置。这两个寄存器的结构完全一样,如下图所示:
每个PFD的输出频率为Fvco*18/PFD_FRAC,其中Fvco是相应PLL的输出频率,而PFD_FRAC的数值取值范围为12到35。
2.2 根时钟控制寄存器
上述锁相环电路以及它们的bypass时钟信号、PFD输出信号,经过时钟切换电路(switcher)和根时钟生成电路(root generator)处理后形成各种根时钟信号。其中,时钟切换电路寄存器CCM_CCSR选择时钟信号pll1_sw_clk和pll3_sw_clk的来源,如下图所示:
根时钟生成电路的寄存器也包含在CCM模块中,比如ARM根时钟信号由pll1_sw_clk分频得来,相应的分频寄存器CCM_CACRR如下图所示:
ARM的时钟信号频率为pll1_sw_clk/(ARM_PODF + 1)。
而之前提到的总线根时钟信号由寄存器CCM_CBCDR进行选择和分频,如下图所示:
其中各个字段的作用可参见根时钟信号电路一节中的原理图,具体设置步骤可参见后面的编程示例。其它根时钟的寄存器与其类似,详细的控制方式要参见imx6ull手册中CCM模块的寄存器描述,这里不再一一列举。
2.3 模块时钟屏蔽寄存器(CCM Low Power Control Register)
2.3.1 IMX6ULL的三种工作方式
为了降低功耗,imx6ull可以工作在以下三种模式:
RUN模式:CCM_CLPCR[LPM]的值为0,CPU正常工作,各个模块的时钟信号可以在寄存器CCGRx中开启和关闭。
WAIT模式:CCM_CLPCR[LPM]的值为1,当CPU执行WFI指令时,开始进入WAIT模式。在此模式下,CPU时钟被关闭,依据寄存器CCGRx中的设置,相应模块的时钟信号也会被关闭。
STOP模式:CCM_CLPCR[LPM]的值为2。STOP模式同样重复上述WAIT模式的操作,并且禁用所有的PLL。如果设置了CCM_CLPCR[SBYOS],该模式还将激活cosc_pwrdown信号,关闭晶体振荡电路的电源。
对于每个时钟信号,imx6ull提供了在不同工作模式下是否屏蔽这些时钟信号的控制方法,这些控制位集中放在寄存器CCGRx(x = 0-6)中,每个CCGRx寄存器结构如下图所示:
(注意这个寄存器默认值为11,即时钟信号在RUN和WAIT模式总是开启,在STOP模式中被屏蔽,所以在霞姐章节的笔记中,尚未有队时钟使能进行操作的代码)
每两位为一个单位,控制一个时钟信号。比如,在寄存器CCGR0中,CG15控制时钟信号gpio2_clocks,CG14控制时钟信号uart2_clock等等。这两位值的含义如下所示:
CGx (x=0-15) | 时钟信号活动状态描述 |
00 | 时钟信号在三个模式中均被屏蔽。 |
01 | 时钟信号仅在RUN模式开启,在其它模式中被屏蔽。 |
10 | 保留 |
11 | 时钟信号在RUN和WAIT模式开启,在STOP模式中被屏蔽。 |
当用户某个模块驱动时,应当根据该模块是否需要在低功耗模式下工作来设置寄存器CCGRx中相应的值,以达到降低功耗的目的。另外,在正常工作模式中,用户也可以在模块空闲时将CCGRx中相应的值设为0,动态调节模块的功耗。
三、个人理解
IMX6ULL的时钟源有两个:24M外部晶振和32.768K晶振,其中32.768K晶振用于内部RTC模块使用。24M外部晶振用于内核和各种外设使用,是时钟树的根源。
但是只有一个24M频率的时钟不足以供各种外设只用,因此,在24MHz的基础上,倍频分离出7路PLL时钟源
(图片来自芯片手册10.3.1章节)
在生成7路PLL和8路PFD后,系统产生了足够的时钟源,但是如何供给外设使用呢,这就需要CLOCK ROOT GENERATOR牵线搭桥。其作用就是根据实际需要,选择合适的时钟源,并对其进行分频,倍频,切换等工作,从而让外设拥有合适的时钟源。
注意根据上面的图,将时钟树分成了三个部分,就是上面用红色框框出来的部分,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 中选择合适的时钟源给外设使用。
4.1 Switcher Clock Generation 对应上图的Clock switcher部分
四、参考文章