I.MX6ULL 时钟配置

时钟来源和生成

/images/linux/clock_1.png
包括以下三个时钟来源:

  1. 外部晶振,高速晶振频率24Mhz,低速晶振频率32.768KHz
  2. 低压差分信号 (LVDS) I/O 端口,用于从外部获取时钟信号
  3. 锁相环(PLL),主时钟包含七个 PLL。其中两个 PLL 分别配备四个相位小数分频器 (PFD),以生成额外的频率。

七个PLL包括:

  • PLL1(ARM_PLL),ARM内核时钟,最高可倍频至1.3GHz(但MCU最高仅支持到1.0GHz)
  • PLL2(SYS_PLL/528_PLL),固定倍频22倍,从外部高速晶振的24MHz倍频产生528MHz,自带四个PFD。通常528_PLL和4路PFD是MX6U内部系统总线的时钟源,如逻辑单元、DDR、NAND/NOR设备等
  • PLL3(USB1_PLL),USB PHY的第一个实例(USBPHY1,也称为 OTG PHY)一起使用。此 PLL 驱动四个 PFD(PLL3_PFD0…PLL3_PFD3)并以固定乘数 20 运行。这导致 VCO 频率为 480 MHz,振荡器为 24 MHz。主 PLL 输出及其 PFD 输出用作许多需要恒定频率的时钟根的输入,例如 UART 和其他串行接口、音频接口等
  • PLL4(Audio_PLL),用于生成具有标准音频频率的低抖动和高精度音频时钟。其频率范围为 650 MHz 至 1300 MHz,频率分辨率优于 1 Hz。该时钟主要用作串行音频接口的时钟和外部音频编解码器的参考时钟。
  • PLL5(Video_PLL),用于生成具有标准视频频率的低抖动和高精度视频时钟。PLL 振荡器频率范围为 650 MHz 至 1300 MHz,频率分辨率优于 1 Hz。该时钟主要用作显示和视频接口的时钟。
  • PLL6(ENET_PLL),固定(20+5/6)倍频,输出500MHz,用于生成以太网
  • PLL7(USB2_PLL),专门为 USB2 PHY(USBPHY2,也称为 OTG PHY)提供时钟,固定倍频 20,输出频率480MHz

CCM时钟树

时钟树(1)

时钟树(2)

具体参见手册第629页。

时钟配置

以ARM时钟配置为例:

ARM时钟

时钟从PLL1的996MHz开始,通过寄存器CCM_CACRR的ARM_PODF位进行分频,可选1/2/4/8分频,然后得到ARM时钟ARM_CLK_ROOT。灰色的/2分频并未实际效果。其中PLL1频率可通过寄存器CCM_ANALOG_PLL_ARMn设置。

CCM_CACRR寄存器

CCM_ANALOG_PLL_ARMn寄存器

修改PLL1时钟时要首先要切换内核时钟源。

PLL1时钟源

  1. PLL1最终输出时钟频率。
  2. 选择器,用于选择pll1的时钟源,由CCM_CCSR的PLL1_SW_CLK_SEL位决定。默认为pll1_main_clk,但如果要调整pll1_main_clk频率,则首先应将pll_sw_clk切换至step_clk,调整完成后再切换回来。
  3. 选择器,用于选择step_clk的时钟源,由CCM_CCSR的STEP_SEL位决定。默认为osc_clk,即外部高速晶振。

CCM_CCSR寄存器

至此,修改I.MX6U主频的步骤可以归纳为:

  1. 设置CCM_CCSR的STEP_SEL位,设置step_clk时钟源为外部24MHz高速晶振
  2. 设置CCM_CCSR的PLL1_SW_CLK_SEL位,设置pll_sw_clk来源为step_clk=24Mhz
  3. 设置CCM_ANALOG_PLL_ARMn,将pll1_main_clk设置为1056MHz
  4. 设置CCM_CCSR的PLL1_SW_CLK_SEL位,将pll1_sw_clk时钟源切换回pll1_main_clk
  5. 设置CCM_CACRR的ARM_PODF为2分频,完成分频设置

其他的时钟配置方式大同小异。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
/*
* @description : 初始化系统时钟,设置系统时钟为792Mhz,并且设置PLL2和PLL3各个
PFD时钟,所有的时钟频率均按照I.MX6U官方手册推荐的值.
* @param : 无
* @return : 无
*/
void imx6u_clkinit(void)
{
unsigned int reg = 0;
/* 1、设置ARM内核时钟为792MHz */
/* 1.1、判断当前ARM内核是使用的那个时钟源启动的,正常情况下ARM内核是由pll1_sw_clk驱动的,而
* pll1_sw_clk有两个来源:pll1_main_clk和tep_clk。
* 如果我们要让ARM内核跑到792M的话那必须选择pll1_main_clk作为pll1的时钟源。
* 如果我们要修改pll1_main_clk时钟的话就必须先将pll1_sw_clk从pll1_main_clk切换到step_clk,
* 当修改完pll1_main_clk以后在将pll1_sw_clk切换回pll1_main_clk。而step_clk的时钟源可以选择
* 板子上的24MHz晶振。
*/

if((((CCM->CCSR) >> 2) & 0x1 ) == 0) /* 当前pll1_sw_clk使用的pll1_main_clk*/
{
CCM->CCSR &= ~(1 << 8); /* 配置step_clk时钟源为24MH OSC */
CCM->CCSR |= (1 << 2); /* 配置pll1_sw_clk时钟源为step_clk */
}

/* 1.2、设置pll1_main_clk为792MHz
* 因为pll1_sw_clk进ARM内核的时候会被二分频!
* 配置CCM_ANLOG->PLL_ARM寄存器
* bit13: 1 使能时钟输出
* bit[6:0]: 66, 由公式:Fout = Fin * div_select / 2.0,792=24*div_select/2.0,
* 得出:div_select= 66
*/
CCM_ANALOG->PLL_ARM = (1 << 13) | ((66 << 0) & 0X7F); /* 配置pll1_main_clk=792MHz */
CCM->CCSR &= ~(1 << 2); /* 将pll_sw_clk时钟重新切换回pll1_main_clk */
CCM->CACRR = 0; /* ARM内核时钟为pll1_sw_clk/1=792/1=792Mhz */

/* 2、设置PLL2(SYS PLL)各个PFD */
reg = CCM_ANALOG->PFD_528;
reg &= ~(0X3F3F3F3F); /* 清除原来的设置 */
reg |= 32<<24; /* PLL2_PFD3=528*18/32=297Mhz */
reg |= 24<<16; /* PLL2_PFD2=528*18/24=396Mhz(DDR使用的时钟,最大400Mhz) */
reg |= 16<<8; /* PLL2_PFD1=528*18/16=594Mhz */
reg |= 27<<0; /* PLL2_PFD0=528*18/27=352Mhz */
CCM_ANALOG->PFD_528=reg; /* 设置PLL2_PFD0~3 */

/* 3、设置PLL3(USB1)各个PFD */
reg = 0; /* 清零 */
reg = CCM_ANALOG->PFD_480;
reg &= ~(0X3F3F3F3F); /* 清除原来的设置 */
reg |= 19<<24; /* PLL3_PFD3=480*18/19=454.74Mhz */
reg |= 17<<16; /* PLL3_PFD2=480*18/17=508.24Mhz */
reg |= 16<<8; /* PLL3_PFD1=480*18/16=540Mhz */
reg |= 12<<0; /* PLL3_PFD0=480*18/12=720Mhz */
CCM_ANALOG->PFD_480=reg; /* 设置PLL3_PFD0~3 */

/* 4、设置AHB时钟 最小6Mhz, 最大132Mhz (boot rom自动设置好了可以不用设置)*/
CCM->CBCMR &= ~(3 << 18); /* 清除设置*/
CCM->CBCMR |= (1 << 18); /* pre_periph_clk=PLL2_PFD2=396MHz */
CCM->CBCDR &= ~(1 << 25); /* periph_clk=pre_periph_clk=396MHz */
while(CCM->CDHIPR & (1 << 5));/* 等待握手完成 */

/* 修改AHB_PODF位的时候需要先禁止AHB_CLK_ROOT的输出,但是
* 我没有找到关闭AHB_CLK_ROOT输出的的寄存器,所以就没法设置。
* 下面设置AHB_PODF的代码仅供学习参考不能直接拿来使用!!
* 内部boot rom将AHB_PODF设置为了3分频,即使我们不设置AHB_PODF,
* AHB_ROOT_CLK也依旧等于396/3=132Mhz。
*/
#if 0
/* 要先关闭AHB_ROOT_CLK输出,否则时钟设置会出错 */
CCM->CBCDR &= ~(7 << 10); /* CBCDR的AHB_PODF清零 */
CCM->CBCDR |= 2 << 10; /* AHB_PODF 3分频,AHB_CLK_ROOT=132MHz */
while(CCM->CDHIPR & (1 << 1));/
* 等待握手完成 */
#endif

/* 5、设置IPG_CLK_ROOT最小3Mhz,最大66Mhz (boot rom自动设置好了可以不用设置)*/
CCM->CBCDR &= ~(3 << 8); /* CBCDR的IPG_PODF清零 */
CCM->CBCDR |= 1 << 8; /* IPG_PODF 2分频,IPG_CLK_ROOT=66MHz */

/* 6、设置PERCLK_CLK_ROOT时钟 */
CCM->CSCMR1 &= ~(1 << 6); /* PERCLK_CLK_ROOT时钟源为IPG */
CCM->CSCMR1 &= ~(7 << 0); /* PERCLK_PODF位清零,即1分频 */
}

I.MX6ULL 时钟配置
http://akichen891.github.io/2025/03/03/时钟配置/
作者
Aki
发布于
2025年3月3日
更新于
2025年3月4日
许可协议