ARM---I.MX6ULL时钟系统详解、时钟树、系统时钟配置等
2026/7/23 23:17:35 网站建设 项目流程

一. I.MX6ULL时钟系统详解

I.MX6ULL 的系统主频为 528MHz,有些型号可以跑到 696MHz,但是默认情况下内部 boot r om会将 I.MX6ULL 的主频设置为 396MHz。在使用 I.MX6ULL 的时候肯定是要发挥它的最大性能,那么主频肯定要设置到 528MHz(其它型号可以设置更高,比如 696MHz),其它的外设时钟也要设置到 NXP 推荐的值,如下表所示。

1.1 系统时钟的来源

从图中可以看出 I.MX6ULL 开发板的系统时钟来源于两部分:32.768KHz 和 2 4MHz 的晶振,其中32.768KHz 晶振是 I.MX6ULL 的 RTC 时钟源(实时时钟),24MHz 晶振是 I.MX6ULL 内核和其它外设的时钟源,也是重点

1.2 七路 PLL 时钟源

I.MX6ULL 的外设有很多,不同的外设时钟源不同,NXP 将这些外设的时钟源进行了分组, 一共有 7 组,这 7 组时钟源都是从24MHz 晶振 PLL而来的,因此也叫做 7 组 PLL

PLL:锁相环(Phase-Locked Loop)全称:相位锁定环路,模拟高频发生电路

功能:外部只有低速晶振(i.MX6ULL 为 24MHz),PLL 可以把 24MHz 成倍放大到几百 MHz,供给 CPU、DDR、高速外设。 普通分频器只能降频,只有 PLL 能升频。

这七个PLL如下表所示:

ARM PLL

PLL 1

作用:给 Cortex-A7 CPU 内核提供主频时钟

该锁相环从 24 MHz 的参考时钟中合成出具有低抖动的时钟。

此锁相环的时钟输出频率范围在650 MHz 至 1.3 GHz之间。

输出频率由 7 位寄存器字段CCM_ANALOG_PLL_ARM[DIV_SELECT]来选择,地址:0x020C8000

PLL 输出频率 = Fref * DIV_SEL / 2

System PLL

(528 PLL)

PLL 2

固定倍频,不可软件修改,输出恒定 528MHz,固定22倍频

PFD 典型输出:

PFD0 = 352 MHz

PFD1 = 594 MHz

PFD2 = 400(396) MHz

PFD3 = 297 MHz

作用:SoC 绝大多数总线、内存、通用外设时钟所使用,通常 528_PLL 和这 4 路 PFD 是 I.MX6U 内部系统总线的 时钟源,比如内处理逻辑单元、DDR 接口、NAND/NOR 接口等等

USB1 PLL

(480 PLL)

PLL 3

固定倍频,不可软件修改,输出恒定 480 MHz,固定倍频20倍频

PFD 典型输出:

PFD0 = 720 MHz

PFD1 = 540 MHz

PFD2 = 508 MHz

PFD3 = 454.7 MHz

作用:此路 PLL 主要用于 USBPHY,但是其和四路 PFD 同样也可以作为其他外设的根时钟源

PLL 4

Audio PLL

主供给音频使用

音频接口:SPDIF, SAI1 - SAI3

输出范围:650MHz ~ 1.3GHz

输出频率可通过编程 CCM_ANALOG_PLL_AUDIO、CCM_ANALOG_PLL_VIDEO 和 CCM_ANALOG_MISC2 寄存器组中的字段来设定,其依据以下公式计算得出:

PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM)

PLL 5

Video PLL

主供给视频外设,和图像处理有关的外设

eg:RGB LCD接口

输出范围:650MHz ~ 1.3GHz

输出频率可通过编程 CCM_ANALOG_PLL_AUDIO、CCM_ANALOG_PLL_VIDEO 和 CCM_ANALOG_MISC2 寄存器组中的字段来设定,其依据以下公式计算得出:

PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM)

PLL 6

Ethernet PLL

此路 PLL 固定为 20+5/6 倍频,因此 ENET_PLL=24MHz * (20+5/6) = 500MHz。

作用:用于生成网络所需的时钟

PLL 7

USB2 PLL

用来调试

1.3 CCM clock tree 时钟树简介

在图中一共有三部分:CLOCK_SWITCHERCLOCK ROOT GENERATORSYSTEM CLOCKS。其中左边的 CLOCK_SWITCHER 就是上一小节讲解的那 7 路 PLL 和 8 路 PFD,右边的 SYSTEM CLOCKS 就是芯片外设,中间的 CLOCK ROOT GENERATOR 是 最复杂的!这一部分就像“月老”一样, 给左边的 CLOCK_SWITCHER 和右边的 SYSTEM C LOCKS 进行牵线搭桥。外设时钟源是有多路可以选择的,CLOCK ROOT GENERATOR 就负 责从 7 路 PLL 和 8 路 PFD 中选择合适的时钟源给外设使用

1.4 有关时钟配置的器件

1.4.1 PLL

锁相环:phased locked loop
作用:倍频
倍频因子:N
输出:24*N

1.4.2 Prescaler

预分频器:Prescaler
作用:分频
分频因子:M
输出:24/M

1.4.3 PFD

相位分数分频器:phased fraction divder
作用:可以倍频也可以降频
倍频,分频因子:N M
输出:24 * N / M
N /M >1:倍频
N / M<1:降频

二. 系统时钟配置

2.1 内核时钟配置

使用到的寄存器:

CCM:Clock Controller Module,时钟控制器模块的各种寄存器

CCM_ANALOG系列寄存器

2.1.1 ARM内核时钟树

ARM内核时钟树如下图:

1、内核时钟源来自于 PLL1此时 PLL1 为 996MHz。

2、通过寄存器CCM_CACRRARM_PODF位对PLL1进行分频,可选择 1/2/4等分频,假如选择 2 分频,那么经过分频以后的时钟频率是 996/2=498MHz,也就是IMX6ULL主频

3、设置内核主频为 528MHz,那么 PLL1 可以设置为 1056MHz,寄存器CCM_CACRRARM_PODF位设置为 2 分频即可。同理,如果要将主频设 置为 696MHz,那么 PLL1 就可以设置为 696MHz,CCM_CACRRARM_PODF设置为 1 分 频即可。接下来详细的看一下CCM_CACRRCCM_ANALOG_PLL_ARMn这两个寄存器

4、寄存器CCM_CACRR(CCM ARM Clock Root Register) (内核根时钟寄存器)结构如下:

ARM_PODF000 :一分频
001 :二分频
010 :三分频
011 :四分频
100 :五分频
101 :六分频
110 :七分频
111 :八分频

5、寄存器CCM_ANALOG_PLL_ARMn(ARM 锁相环控制寄存器)

BYPASS_CLK_SRC0:选择24MHz晶振作为时钟源
ENABLE

1:使能

0:禁止

DIV_SELECT

此位设置 PLL1 的输出频率,

可设置范围为:54~108,可得出PLL1的范围:648 - 1296MHz

公式:PLL1 CLK = Fin * div_seclec/2.0,Fin=24MHz

如果 PLL1 要输出 1056MHz 的话,div_select 就要设置为 88

2.1.2 PLL1 时钟开关

配置内核前,boot rom默认配置主频为396MHz,在修改内核时钟频率的时候需要先将内核时钟源改为其他的时钟源,因为时钟频率突然的升高可能会导致内核工作状态死机等异常状态

修改过程如下图所示:

1、pll1_sw_clk也就是 PLL1 的最终输出频率

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

3、再下面也是一个选择器,选择step_clk的时钟源,由寄存器CCM_CCSRSTEP_SEL位来决定step_clk是选择osc_clk还是secondary_clk。一般选择osc_clk,也就是24MHz的晶振

4、寄存器CCM_CCSR(CCM Clock Switcher register)---时钟切换寄存器


STEP_SEL

作用:选择step_clk的时钟源

0 :选择 osc_clk (24M)
1 :选择 secondary_clk

PLL1_SW_CLK_SEL

作用:选择pll1_sw_clk的时钟源

0:选择pll1_main_clk

1:选择step_clk

2.1.3 配置内核时钟示例代码

/配置 ARM 时钟 CCM->CCSR &= ~(1 << 8); /选择 step_clk = osc_clk = 24MHz CCM->CCSR |= (1 << 2); /选择 pll1_sw_clk = step_clk = 24MHz t = CCM_ANALOG->PLL_ARM; t &= ~(3 << 14); /选择24MHz做为时钟源 t |= (1 << 13); /使能时钟 t &= ~(0x7F << 0); /先将低七位清零 t |= (88 << 0); /DIV_SELECT = 88 CCM_ANALOG->PLL_ARM = t; CCM->CACRR |= (1 << 0); /设置PLL1输出二分频 CCM->CCSR &= ~(1 << 2); /选择 pll1_sw_clk = pll1_main_clk

2.2 配置PLL2与PLL3的8个PFD

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

这两个要通过寄存器CCM_ANALOG_PFD_528与CCM_ANALOG_PFD_480来设置

2.2.1寄存器CCM_ANALOG_PFD_528

其余位同理:PLL2_PFD1~PLL2_PFD3 设置类似

PFD0_FRAC

PLL2_PFD0 的分频数,

PLL2_PFD0 的计算公式为528*18/PFD0_FRAC

范围:此位可设置的范围为12~35

如果 PLL2_PFD0 的频率要设置为 352MHz 的话PFD0_FRAC=528* 18/352=27

如果 PLL2_PFD0=352 MHz 的话,PFD0_FRAC=27

如果 PLL2_PFD1=594MHz 的话,PFD1_FRAC=16

如果 PLL2_P FD2=396MHz 的话,PFD2_FRAC=24

如果 PLL2_PFD3=297MHz 的话,PFD3_FRAC=32

PFD0_STABLE此位为只读位,可以通过读取此位判断 PLL2_PFD0 是否稳定
PFD0_CLKGATE

PLL2_PFD0 输出使能位,

为 1 的时候关闭 PLL2_PFD0 的输出,

为 0 的时候使能输出

2.2.2 寄存器CCM_ANALOG_PFD_480

从图可以看出,寄存器 CCM_ANALOG_PFD_480n 和 CCM_ANALOG_PFD_528n 的结构是一模一样的,只是一个是 PLL2 的,一个是 PLL3 的。寄存器位的含义也是一样的,只是频率计算公式不同,

比如 PLL3_PFDX=480*18/PFDX_FRAC(X=0~3)

如果 PLL3_PFD0=720 MHz 的话,PFD0_FRAC=12;

如果 PLL3_PFD1=540MHz 的话,PFD1_FRAC=16;

如果 PLL3_P FD2=508.2MHz 的话,PFD2_FRAC=17;

如果 PLL3_PFD3=454.7MHz 的话,PFD3_FRAC=19

2.2.3 示例代码

/配置 PLL2 的四路PFD:PFD0 PFD1 PFD2 PFD3 t = CCM_ANALOG->PFD_528; /配置PLL2的四路PFD输出指定频率时钟并且使能时钟 t &= ~((0x3F << 0) | (0x3F << 8) | (0x3F << 16) | (0x3F << 24)); t &= ~((1 << 7) | (1 << 15) | (1 << 23) | (1 << 31)); /启用分数分频器 t |= ((27 << 0) | (16 << 8) | (24 << 16) | (32 << 24)); CCM_ANALOG->PFD_528 = t; /配置 PLL3 的四路PFD:PFD0 PFD1 PFD2 PFD3 t = CCM_ANALOG->PFD_480; /配置PLL3的四路PFD输出指定频率时钟并且使能时钟 t &= ~((0x3F << 0) | (0x3F << 8) | (0x3F << 16) | (0x3F << 24)); t &= ~((1 << 7) | (1 << 15) | (1 << 23) | (1 << 31)); /启用分数分频器 t |= ((12 << 0) | (16 << 8) | (17 << 16) | (19 << 24)); CCM_ANALOG->PFD_480 = t;

2.3 配置三个根时钟

这一节配置三个根时钟,分别是:

AHB_CLK_ROOTPERCLK_CLK_ROOTIPG_CLK_ROOT

由时钟树得知,很多外设如:EPIT、I2C、ADC、WDOG等,时钟都来自这三个根时钟,故要对这三个根时钟进行配置

IMX6ULL外设根时钟可设置范围如图所示:

又图可知:AHB_CLK_ROOT最高可以设置132MHzIPG_CLK_ROOTPERCLK_CLK_ROOT最高可以设置66MHz。那就将 AHB_CLK_ ROOT、IPG_CLK_ROOT 和 PERCLK_CLK_ROOT 分别设置为 132MHz、66MHz、66MHz。

2.3.1 配置AHB_CLK_ROOT

配置步骤:

第一步:

此选择器用来选择 pre_periph_clk 的时钟源,可以选择PLL2、PLL2_PFD2、PLL2_PF D0 和 PLL2_PFD2/2寄存器 CCM_CBCMR 的 PRE_PERIPH_CLK_SEL位决定选择哪一个,默认选择 PLL2_PFD2,因此 pre_periph_clk=PLL2_PFD2=396MHz

寄存器 CCM_CBCMR

PRE_PERIPH_CLK_SEL(19 - 18)

作用:pre_periph 时钟源选择

00 :选择 PLL2 --- 528MHz

01 :选择 PLL2_PFD2 --- 396MHz

10 :选择 PLL2_PFD0 --- 352MHz

11 :选择 PLL2_PFD2/2 --- 396/2MHz

第二步:

寄存器 CCM_CBCDRPERIPH_CLK_SEL来选择

IPG_PODF(9 - 8)

IPG时钟分频

00 :一分频

01 :二分频
10 :三分频
11 :四分频

AHB_PODF

AHB 时钟分频

000:1分频
001 :2分频
010 :3分频------396 / 3 = 132MHz
011 :4分频
100 :5分频
101 :6分频
110 :7分频
111 :8分频

PERIPH_CLK_SEL0 :PLL2 (pll2_main_clk)
1 :derive clock from periph_clk2_clk clock source

第三步:

设置3分频即可,也是使用寄存器 CCM_CBCDR

2.3.2 配置PERCLK_CLK_ROOTIPG_CLK_ROOT

注意这里要使用寄存器CBCDR[IPG_PODF]来设置二分频,132/2=66,才能得到想要的频率

寄存器CCM_CSCMR1

PERCLK_PODF(低5位)

000000 divide by 1
000001 divide by 2
000010 divide by 3
000011 divide by 4
000100 divide by 5

000101 divide by 6
000110 divide by 7
111111 divide by 64

PERCLK_CLK_SEL(bit 6)

0 :选择 ipg clk

1 :选择 osc clk

2.3.3 示例代码

/配置三个根时钟 /AHB_CLK_ROOT t = CCM->CBCMR; t &= ~(3 << 18); t |= (1 << 18); /选择PFD2 CCM->CBCMR = t; t = CCM->CBCDR; t &= ~(1 << 25); /选择PLL2 t &= ~((7 << 10) | (3 << 8)); /三分频输出 t |= (2 << 10); t |= (1 << 8); /配置IPG_CLK_ROOT = 132/2 =66MHz CCM->CBCDR = t; /PERCLK_CLK_ROOT t = CCM->CSCMR1; t &= ~(1 << 6); /选择 IPG_CLK_ROOT,配置PERCLK_CLK_ROOT = IPG_CLK_ROOT t &= ~(0x3F << 0); /选择一分频,PERCLK_CLK_ROOT = IPG_CLK_ROOT = 66MHz CCM->CSCMR1 = t;

三. IMX6ULL配置与使能时钟完整代码

示例代码:

#include"MCIMX6Y2.h" #include"clock.h" //打开所有时钟门 void enable_clocks(void) { CCM->CCGR0 = 0xFFFFFFFF; CCM->CCGR1 = 0xFFFFFFFF; CCM->CCGR2 = 0xFFFFFFFF; CCM->CCGR3 = 0xFFFFFFFF; CCM->CCGR4 = 0xFFFFFFFF; CCM->CCGR5 = 0xFFFFFFFF; CCM->CCGR6 = 0xFFFFFFFF; } //初始化时钟 void clock_init(void) { unsigned int t; //配置 ARM 时钟 CCM->CCSR &= ~(1 << 8); //选择 step_clk = osc_clk = 24MHz CCM->CCSR |= (1 << 2); //选择 pll1_sw_clk = step_clk = 24MHz t = CCM_ANALOG->PLL_ARM; t &= ~(3 << 14); //选择24MHz做为时钟源 t |= (1 << 13); //使能时钟 t &= ~(0x7F << 0); //先将低七位清零 t |= (88 << 0); //DIV_SELECT = 88 CCM_ANALOG->PLL_ARM = t; CCM->CACRR |= (1 << 0); //设置PLL1输出二分频 CCM->CCSR &= ~(1 << 2); //选择 pll1_sw_clk = pll1_main_clk //配置 PLL2 的四路PFD:PFD0 PFD1 PFD2 PFD3 t = CCM_ANALOG->PFD_528; //配置PLL2的四路PFD输出指定频率时钟并且使能时钟 t &= ~((0x3F << 0) | (0x3F << 8) | (0x3F << 16) | (0x3F << 24)); t &= ~((1 << 7) | (1 << 15) | (1 << 23) | (1 << 31)); //启用分数分频器 t |= ((27 << 0) | (16 << 8) | (24 << 16) | (32 << 24)); CCM_ANALOG->PFD_528 = t; //配置 PLL3 的四路PFD:PFD0 PFD1 PFD2 PFD3 t = CCM_ANALOG->PFD_480; //配置PLL3的四路PFD输出指定频率时钟并且使能时钟 t &= ~((0x3F << 0) | (0x3F << 8) | (0x3F << 16) | (0x3F << 24)); t &= ~((1 << 7) | (1 << 15) | (1 << 23) | (1 << 31)); //启用分数分频器 t |= ((12 << 0) | (16 << 8) | (17 << 16) | (19 << 24)); CCM_ANALOG->PFD_480 = t; //配置三个根时钟 //AHB_CLK_ROOT t = CCM->CBCMR; t &= ~(3 << 18); t |= (1 << 18); //选择PFD2 CCM->CBCMR = t; t = CCM->CBCDR; t &= ~(1 << 25); //选择PLL2 t &= ~((7 << 10) | (3 << 8)); //三分频输出 t |= (2 << 10); t |= (1 << 8); //配置IPG_CLK_ROOT = 132/2 =66MHz CCM->CBCDR = t; //PERCLK_CLK_ROOT t = CCM->CSCMR1; t &= ~(1 << 6); //选择 IPG_CLK_ROOT,配置PERCLK_CLK_ROOT = IPG_CLK_ROOT t &= ~(0x3F << 0); //选择一分频,PERCLK_CLK_ROOT = IPG_CLK_ROOT = 66MHz CCM->CSCMR1 = t; //使能时钟 enable_clocks(); }

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询