ARM---I.MX6ULL时钟系统详解、时钟树、系统时钟配置等

一. 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_ARMDIV_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_PODF | 000 :一分频 001 :二分频 010 :三分频 011 :四分频 100 :五分频 101 :六分频 110 :七分频 111 :八分频 |

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

|--------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|
| BYPASS_CLK_SRC | 0:选择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 配置内核时钟示例代码

cpp 复制代码
    /配置 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 示例代码

cpp 复制代码
    /配置 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_SEL | 0 :PLL2 (pll2_main_clk) 1 :derive clock from periph_clk2_clk clock source |

第三步:

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

2.3.2 配置PERCLK_CLK_ROOTIPG_CLK_ROOT

注意这里要使用**寄存器CBCDRIPG_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 示例代码

cpp 复制代码
    /配置三个根时钟
    /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配置与使能时钟完整代码

示例代码:

cpp 复制代码
#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();
}
相关推荐
染予2 小时前
上位机时间戳精度不够,时间无法对比怎么解决
单片机·嵌入式硬件
現実君2 小时前
关于MCU下位替换FPGA的经验与方案
单片机·嵌入式硬件·fpga开发
m0_547486662 小时前
《单片机原理及应用》全套PPT课件2026版
单片机·嵌入式硬件
十月的皮皮2 小时前
STM32从零到量产开发:四路继电器工业控制模块开发原理小灶 · 合集
stm32·单片机·嵌入式硬件·stm32cubemx·hal库
小羊先生car3 小时前
F429-HAL 库驱动框架(2026/7/22)
单片机·嵌入式硬件
小羊先生car3 小时前
F429-SysTick(2026/7/22)
stm32·单片机·嵌入式硬件
智购科技无人售货机工厂3 小时前
自动售货机硬件选型避坑:单片机 / 树莓派 / ESP32 怎么选?~YH
人工智能·单片机·嵌入式硬件·r语言·swift·perl·symfony
hongmai6668884 小时前
ESP32-C61-WROOM-1-N8R2:Wi-Fi 6与RISC-V融合的中坚力量
人工智能·单片机·嵌入式硬件·物联网·智能家居·risc-v
炸膛坦客13 小时前
单片机/C/C++八股:(二十六)IIC 专题(I²C)---- 上集
c语言·c++·单片机