I.MX6ULL主频和时钟配置实验

系列文章目录

I.MX6ULL主频和时钟配置实验


I.MX6ULL主频和时钟配置实验

  • 系列文章目录
  • 一、前言
  • 二、I.MX6U 时钟系统详解
  • 三、硬件原理
  • 四、 7 路 PLL 时钟源
  • 五、时钟树简介
  • 六、内核时钟设置
  • 七、PFD 时钟设置
  • 八、AHB、IPG 和 PERCLK 根时钟设置
  • 九、实验程序编写
  • 十、编译下载
    • 10.1编写 Makefile 和链接脚本
    • 10.2编译下载


一、前言

在之前实验中我们都没有涉及到 I.MX6U 的时钟和主频配置操作,全部使用的默认配置,默认配置下 I.MX6U 工作频率为 396MHz。但是 I.MX6U 系列标准的工作频率为528MHz,有些型号甚至可以工作到 696MHz。
本节学习 I.MX6U 的时钟系统,学习如何配置 I.MX6U 的系统时钟和其他的外设时钟,使其工作频率为 528MHz,其他的外设时钟源都工作在 NXP 推荐的频率。


二、I.MX6U 时钟系统详解

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)”这两章有详细的讲解。


三、硬件原理

打开 I.MX6U-ALPHA 开发板原理图,开发板时钟原理图如图所示:
在这里插入图片描述
从图可以看出 I.MX6U-ALPHA 开发板的系统时钟来源于两部分:32.768KHz 和
24MHz 的晶振,其中 32.768KHz 晶振是 I.MX6U 的 RTC 时钟源,24MHz 晶振是 I.MX6U 内核和其它外设的时钟源。在6U的T16和T17这两个IO上接了一个24MHz的晶振。


四、 7 路 PLL 时钟源

为了方便生成时钟,6从24MHz晶振生出来7路PLL。这7路PLL中有的又生出来PFD。

I.MX6U 的外设有很多,不同的外设时钟源不同,NXP 将这些外设的时钟源进行了分组,
一共有 7 组,这 7 组时钟源都是从 24MHz 晶振 PLL 而来的,因此也叫做 7 组 PLL,这 7 组 PLL结构如图所示:
在这里插入图片描述
PLL详解如图所示:

在这里插入图片描述

图展示了 7 个 PLL 的关系,我们依次来看一下这 7 个 PLL 都是什么做什么的:
①、 ARM_PLL(PLL1),此路 PLL 是供 ARM 内核使用的,ARM 内核时钟就是由此 PLL
生成的,此 PLL 通过编程的方式最高可倍频到 1.3GHz。
②、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同样也可以作为其他外设的根时钟源。
④、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。此路 PLL 用于生成网络所需的时钟,可以在此 PLL 的基础上生成 25/50/100/125MHz
的网络时钟。
⑥、VIDEO_PLL(PLL5),此路 PLL 用于显示相关的外设,比如 LCD,此路 PLL 的倍频可以
调整,PLL 的输出范围在 650MHz~1300MHz。此路 PLL 在最终输出的时候还可以进行分频,
可选 1/2/4/8/16 分频。
⑦、AUDIO_PLL(PLL4),此路 PLL 用于音频相关的外设,此路 PLL 的倍频可以调整,PLL
的输出范围同样也是 650MHz~1300MHz,此路 PLL 在最终输出的时候也可以进行分频,可选
1/2/4 分频。


五、时钟树简介

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 的时钟图如图所示:

在这里插入图片描述
在图中我们分为了 3 部分,这三部分如下:
①、此部分是时钟源选择器,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。
上面我们以外设 ESAI 为例讲解了如何根据图来设置外设的时钟频率,其他的外设基本类似的,大家可以自行分析一下其他的外设。关于外设时钟配置相关内容全部都在《I.MX6ULL 参考手册》的第 18 章。

官方参考手册第18章外设时钟源推荐值:
在这里插入图片描述


六、内核时钟设置

设置相应的时钟频率,先从主频开始,我们将 I.MX6U 的主频设置为 528MHz,根据时钟树可以看到ARM 内核时钟如图所示:
在这里插入图片描述在图中各部分如下:
①、内核时钟源来自于 PLL1,假如此时 PLL1 为 996MHz。
②、通过寄存器 CCM_CACRR 的 ARM_PODF 位对 PLL1 进行分频,可选择 1/2/4/8 分频,
假如我们选择 2 分频,那么经过分频以后的时钟频率是 996/2=498MHz。
③、大家不要被此处的 2 分频给骗了,此处没有进行 2 分频(我就被这个 2 分频骗了好久,
主频一直配置不正确!)。
④、经过第②步 2 分频以后的 498MHz 就是 ARM 的内核时钟,也就是 I.MX6U 的主频。
经过上面几步的分析可知,假如我们要设置内核主频为 528MHz,那么 PLL1 可以设置为
1056MHz,寄存器 CCM_CACRR 的 ARM_PODF 位设置为 2 分频即可。同理,如果要将主频设
置为 696MHz,那么 PLL1 就可以设置为 696MHz,CCM_CACRR 的 ARM_PODF 设置为 1 分
频即可。现在问题很清晰了,寄存器 CCM_CACRR 的 ARM_PODF 位很好设置,PLL1 的频率
可以通过寄存器 CCM_ANALOG_PLL_ARMn 来设置。接下来详细的看一下 CCM_CACRR 和
CCM_ANALOG_PLL_ARMn 这两个寄存器,CCM_CACRR 寄存器结构如图所示:
在这里插入图片描述
寄存器 CCM_CACRR 只有 ARM_PODF 位,可以设置为 0~7,分别对应 1~8 分频。如果要
设置为2分频的话CCM_CACRR就要设置为1。再来看一下寄存器CCM_ANALOG_PLL_ARMn,
此寄存器结构如图所示:
在这里插入图片描述
在寄存器 CCM_ANALOG_PLL_ARMn 中重要的位如下:
ENABLE: 时钟输出使能位,此位设置为 1 使能 PLL1 输出,如果设置为 0 的话就关闭 PLL1
输出。
DIV_SELECT: 此位设置 PLL1 的输出频率,可设置范围为:54~108,PLL1 CLK = Fin *
div_seclec/2.0,Fin=24MHz。如果 PLL1 要输出 1056MHz 的话,div_select 就要设置为 88。
在修改 PLL1 时钟频率的时候我们需要先将内核时钟源改为其他的时钟源,PLL1 可选择的时钟源如图所示:
在这里插入图片描述
①、pll1_sw_clk 也就是 PLL1 的最终输出频率。
②、此处是一个选择器,选择 pll1_sw_clk 的时钟源,由寄存器 CCM_CCSR 的
PLL1_SW_CLK_SEL 位决定 pll1_sw_clk 是选择 pll1_main_clk 还是 step_clk。正常情况下应该
选择 pll1_main_clk,但是如果要对 pll1_main_clk(PLL1)的频率进行调整的话,比如我们要设置
PLL1=1056MHz,此时就要先将 pll1_sw_clk 切换到 step_clk 上。等 pll1_main_clk 调整完成以后
再切换回来。
③、此处也是一个选择器,选择 step_clk 的时钟源,由寄存器 CCM_CCSR 的 STEP_SEL 位
来决定 step_clk 是选择 osc_clk 还是 secondary_clk。一般选择 osc_clk,也就是 24MHz 的晶振。
这里我们就用到了一个寄存器 CCM_CCSR,此寄存器结构如图所示:
在这里插入图片描述寄存器 CCM_CCSR 我们只用到了 STEP_SEL、PLL1_SW_CLK_SEL 这两个位,一个是用来选择 step_clk 时钟源的,一个是用来选择 pll1_sw_clk 时钟源的。到这里,修改 I.MX6U 主频的步骤就很清晰了,修改步骤如下:
①、 设置寄存器 CCSR 的 STEP_SEL 位,设置 step_clk 的时钟源为 24M 的晶振。
②、设置寄存器 CCSR 的 PLL1_SW_CLK_SEL 位,设置 pll1_sw_clk 的时钟源为step_clk=24MHz,通过这一步我们就将 I.MX6U 的主频先设置为 24MHz,直接来自于外部的
24M 晶振。
③、设置寄存器 CCM_ANALOG_PLL_ARMn,将 pll1_main_clk(PLL1)设置为 1056MHz。
④、设置寄存器 CCSR 的 PLL1_SW_CLK_SEL 位,重新将 pll1_sw_clk 的时钟源切换回
pll1_main_clk,切换回来以后的 pll1_sw_clk 就等于 1056MHz。
⑤、最后设置寄存器 CCM_CACRR 的 ARM_PODF 为 2 分频,I.MX6U 的内核主频就为
1056/2=528MHz。


七、PFD 时钟设置

设置好主频以后我们还需要设置好其他的 PLL 和 PFD 时钟,PLL1已经设置了,PLL2、PLL3 和 PLL7 固定为 528MHz、480MHz 和 480MHz,PLL4~PLL6 都是针对特殊外设的,用到的时候再设置。因此,接下来重点就是设置 PLL2 和 PLL3 的各自 4 路 PFD,NXP 推荐的这 8 路 PFD 频率如表所示(时钟树上的):
在这里插入图片描述先设置 PLL2 的 4 路 PFD 频率,用到寄存器是 CCM_ANALOG_PFD_528n,寄存器结构如图所示:
在这里插入图片描述
从图可以看出,寄存器 CCM_ANALOG_PFD_528n 其实分为四组,分别对应PFD0~PFD3,每组 8 个 bit,我们就以 PFD0 为例,看一下如何设置 PLL2_PFD0 的频率。PFD0对应的寄存器位如下:
PFD0_FRAC: PLL2_PFD0 的分频数,PLL2_PFD0 的计算公式为 52818/PFD0_FRAC,此
为 可 设 置 的 范 围 为 12~35 。 如 果 PLL2_PFD0 的 频 率 要 设 置 为 352MHz 的 话
PFD0_FRAC=528
18/352=27。
PFD0_STABLE: 此位为只读位,可以通过读取此位判断 PLL2_PFD0 是否稳定。
PFD0_CLKGATE: PLL2_PFD0 输出使能位,为 1 的时候关闭 PLL2_PFD0 的输出,为 0 的
时候使能输出。
如果我们要设置 PLL2_PFD0 的频率为 352MHz 的话就需要设置 PFD0_FRAC 为 27,
PFD0_CLKGATE 为 0 。 PLL2_PFD1~PLL2_PFD3 设置类似,频率计算公式都是
528*18/PFDX_FRAC(X=1~3) ,因此 PLL2_PFD1=594MHz 的话, PFD1_FRAC=16 ;
PLL2_PFD2=400MHz 的话 PFD2_FRAC 不能整除,因此取最近的整数值,即 PFD2_FRAC=24,
这样 PLL2_PFD2 实际为 396MHz;PLL2_PFD3=297MHz 的话,PFD3_FRAC=32。

接 下 来 设 置 PLL3_PFD0~PLL3_PFD3 这 4 路 PFD 的 频 率 , 使 用 到 的 寄 存 器 是
CCM_ANALOG_PFD_480n,此寄存器结构如图所示:
在这里插入图片描述
从图可以看出,寄存器 CCM_ANALOG_PFD_480n 和 CCM_ANALOG_PFD_528n
的结构是一模一样的,只是一个是 PLL2 的,一个是 PLL3 的。寄存器位的含义也是一样的,只
是 频 率 计 算 公 式 不 同 , 比 如 PLL3_PFDX=480*18/PFDX_FRAC(X=0~3) 。如果
PLL3_PFD0=720MHz 的话,PFD0_FRAC=12;如果 PLL3_PFD1=540MHz 的话,PFD1_FRAC=16;
如果 PLL3_PFD2=508.2MHz 的话,PFD2_FRAC=17;如果 PLL3_PFD3=454.7MHz 的话,
PFD3_FRAC=19。


八、AHB、IPG 和 PERCLK 根时钟设置

7 路 PLL 和 8 路 PFD 设置完成以后最后还需要设置 AHB_CLK_ROOT 和 IPG_CLK_ROOT
的时钟,I.MX6U 外设根时钟可设置范围如图所示:
在这里插入图片描述
图中给出了大多数外设的根时钟设置范围,AHB_CLK_ROOT 最高可以设置 132MHz,
IPG_CLK_ROOT 和PERCLK_CLK_ROOT 最高可以设置66MHz。那我们就将AHB_CLK_ROOT、
IPG_CLK_ROOT 和 PERCLK_CLK_ROOT 分 别 设 置 为 132MHz 、 66MHz 、 66MHz 。
AHB_CLK_ROOT 和 IPG_CLK_ROOT 的设计如图所示:
在这里插入图片描述图就是 AHB_CLK_ROOT 和 IPG_CLK_ROOT 的时钟图,图中分为了部分。
①、此选择器用来选择 pre_periph_clk 的时钟源,可以选择 PLL2、PLL2_PFD2、PLL2_PFD0
和 PLL2_PFD2/2。寄存器 CCM_CBCMR 的 PRE_PERIPH_CLK_SEL 位决定选择哪一个,默认
选择 PLL2_PFD2,因此 pre_periph_clk=PLL2_PFD2=396MHz。
②、此选择器用来选择 periph_clk 的时钟源,由寄存器 CCM_CBCDR 的 PERIPH_CLK_SEL
位与 PLL_bypass_en2 组成的或来选择。当 CCM_CBCDR 的 PERIPH_CLK_SEL 位为 0 的时候
periph_clk=pr_periph_clk=396MHz。
③、通过 CBCDR 的 AHB_PODF 位来设置 AHB_CLK_ROOT 的分频值,可以设置 1~8 分
频,如果想要 AHB_CLK_ROOT=132MHz 的话就应该设置为 3 分频:396/3=132MHz。图 16.1.6.2
中虽然写的是默认 4 分频,但是 I.MX6U 的内部 boot rom 将其改为了 3 分频!
④、通过 CBCDR 的 IPG_PODF 位来设置 IPG_CLK_ROOT 的分频值,可以设置 1~4 分频,
IPG_CLK_ROOT 时钟源是 AHB_CLK_ROOT,要想 IPG_CLK_ROOT=66MHz 的话就应该设置
2 分频:132/2=66MHz。
最后要设置的就是 PERCLK_CLK_ROOT 时钟频率,其时钟结构图如图所示:
在这里插入图片描述

从图中可看出 , PERCLK_CLK_ROOT 来 源 有 两 种 : OSC(24MHz) 和IPG_CLK_ROOT,由寄存器 CCM_CSCMR1 的 PERCLK_CLK_SEL 位来决定,如果为 0 的话PERCLK_CLK_ROOT 的时钟源就是 IPG_CLK_ROOT=66MHz 。可以通过寄存器CCM_CSCMR1 的 PERCLK_PODF 位来设置分频,如果要设置 PERCLK_CLK_ROOT 为 66MHz的话就要设置为 1 分频。
在上面的设置中用到了三个寄存器:CCM_CBCDR、CCM_CBCMR 和 CCM_CSCMR1,依次来看一下这些寄存器,CCM_CBCDR 寄存器结构如图所示:

在这里插入图片描述
寄存器 CCM_CBCDR 各个位的含义如下:
PERIPH_CLK2_PODF:periph2 时钟分频,可设置 0~7,分别对应 1~8 分频。
PERIPH2_CLK_SEL:选择 peripheral2 的主时钟,如果为 0 的话选择 PLL2,如果为 1 的
话选择 periph2_clk2_clk。修改此位会引起一次与 MMDC 的握手,所以修改完成以后要等待握
手完成,握手完成信号由寄存器 CCM_CDHIPR 中指定位表示。
PERIPH_CLK_SEL:peripheral 主时钟选择,如果为 0 的话选择 PLL2,如果为 1 的话选
择 periph_clk2_clock。修改此位会引起一次与 MMDC 的握手,所以修改完成以后要等待握手完
成,握手完成信号由寄存器 CCM_CDHIPR 中指定位表示。
AXI_PODF:axi 时钟分频,可设置 0~7,分别对应 1~8 分频。
AHB_PODF:ahb 时钟分频,可设置 0~7,分别对应 1~8 分频。修改此位会引起一次与
MMDC 的握手,所以修改完成以后要等待握手完成,握手完成信号由寄存器 CCM_CDHIPR 中
指定位表示。
IPG_PODF:ipg 时钟分频,可设置 0~3,分别对应 1~4 分频。
AXI_ALT_CLK_SEL:axi_alt 时钟选择,为 0 的话选择 PLL2_PFD2,如果为 1 的话选择
PLL3_PFD1。
AXI_CLK_SEL:axi 时钟源选择,为 0 的话选择 periph_clk,为 1 的话选择 axi_alt 时钟。
FABRIC_MMDC_PODF:fabric/mmdc 时钟分频设置,可设置 0~7,分别对应 1~8 分频。
PERIPH2_CLK2_PODF:periph2_clk2 的时钟分频,可设置 0~7,分别对应 1~8 分频。

接下来看一下寄存器 CCM_CBCMR,寄存器结构如图所示:
在这里插入图片描述
寄存器 CCM_CBCMR 各个位的含义如下:
LCDIF1_PODF:lcdif1 的时钟分频,可设置 0~7,分别对应 1~8 分频。
PRE_PERIPH2_CLK_SEL:pre_periph2 时钟源选择,00 选择 PLL2,01 选择 PLL2_PFD2,
10 选择 PLL2_PFD0,11 选择 PLL4。
PERIPH2_CLK2_SEL:periph2_clk2 时钟源选择为 0 的时候选择 pll3_sw_clk,为 1 的时候
选择 OSC。
PRE_PERIPH_CLK_SEL:pre_periph 时钟源选择,00 选择 PLL2,01 选择 PLL2_PFD2,10 选
择 PLL2_PFD0,11 选择 PLL2_PFD2/2。
PERIPH_CLK2_SEL:peripheral_clk2 时钟源选择,00 选择 pll3_sw_clk,01 选择 osc_clk,
10 选择 pll2_bypass_clk。

最后看一下寄存器 CCM_CSCMR1,寄存器结构如图所示:
在这里插入图片描述
此寄存器主要用于外设时钟源的选择,比如 QSPI1、ACLK、GPMI、BCH 等外设,我们重点看一下下面两个位:
PERCLK_CK_SEL:perclk 时钟源选择,为 0 的话选择 ipg clk,为 1 的话选择 osc clk。
PERCLK_PODF:perclk 的时钟分频,可设置 0~7,分别对应 1~8 分频。
在修改如下时钟选择器或者分频器的时候会引起与 MMDC 的握手发生:
①、mmdc_podf
②、periph_clk_sel
③、periph2_clk_sel
④、arm_podf
⑤、ahb_podf
发生握手信号以后需要等待握手完成,寄存器 CCM_CDHIPR 中保存着握手信号是否完成,如果相应的位为 1 的话就表示握手没有完成,如果为 0 的话就表示握手完成,很简单,这里就不详细的列举寄存器 CCM_CDHIPR 中的各个位了。
另外在修改 arm_podf 和 ahb_podf 的时候需要先关闭其时钟输出,等修改完成以后再打开,否则的话可能会出现在修改完成以后没有时钟输出的问题。本节需要修改寄存器CCM_CBCDR 的AHB_PODF 位来设置 AHB_ROOT_CLK 的时钟,所以在修改之前必须先关闭AHB_ROOT_CLK 的输出。但是笔者没有找到相应的寄存器,因此目前没法关闭,那也就没法设置 AHB_PODF 了。不过 AHB_PODF 内部 boot rom 设置为了 3 分频,如果 pre_periph_clk 的时钟源选择 PLL2_PFD2 的话,AHB_ROOT_CLK 也是 396MHz/3=132MHz。

I.MX6U 的时钟系统还是很复杂的,大家要结合《I.MX6ULL 参考手册》中时钟相关的结构图来学习。本节也只是讲解了如何进行主频、PLL、PFD 和一些总线时钟的设置,关于具体的外设时钟设置,后面配置具体外设时候,具体书写。


九、实验程序编写

本试验在链接的试验的基础上完成,因为本试验是配置 I.MX6U 的系统时钟,因
此我们直接在文件“bsp_clk.c”上做修改,修改 bsp_clk.c 的内容如下:

#include "bsp_clk.h"
/*
* @description : 使能 I.MX6U 所有外设时钟
* @param : 无
* @return : 无
*/
void clk_enable(void)
{
CCM->CCGR0 = 0XFFFFFFFF;
CCM->CCGR1 = 0XFFFFFFFF;
CCM->CCGR2 = 0XFFFFFFFF;
CCM->CCGR3 = 0XFFFFFFFF;
CCM->CCGR4 = 0XFFFFFFFF;
CCM->CCGR5 = 0XFFFFFFFF;
CCM->CCGR6 = 0XFFFFFFFF;
}/*
* @description : 初始化系统时钟 528Mhz,并且设置 PLL2 和 PLL3 各个
PFD 时钟,所有的时钟频率均按照 I.MX6U 官方手册推荐的值.
* @param : 无
* @return : 无
*/
void imx6u_clkinit(void)
{
unsigned int reg = 0;
/* 1、设置 ARM 内核时钟为 528MHz */
/* 1.1、判断当使用哪个时钟源启动的,正常情况下是由 pll1_sw_clk 驱动的,而
* pll1_sw_clk 有两个来源:pll1_main_clk 和 step_clk,如果要
* 让 I.MX6ULL 跑到 528M,那必须选择 pll1_main_clk 作为 pll1 的时钟
* 源。如果我们要修改 pll1_main_clk 时钟的话就必须先将 pll1_sw_clk 从
* pll1_main_clk 切换到 step_clk,当修改完以后再将 pll1_sw_clk 切换
* 回 pll1_main_cl,step_clk 等于 24MHz。
*/if((((CCM->CCSR) >> 2) & 0x1 ) == 0) /* pll1_main_clk */{ CCM->CCSR &= ~(1 << 8); /* 配置 step_clk 时钟源为 24MHz OSC */ CCM->CCSR |= (1 << 2); /* 配置 pll1_sw_clk 时钟源为 step_clk */}/* 1.2、设置 pll1_main_clk 为 1056MHz,也就是 528*2=1056MHZ,
* 因为 pll1_sw_clk 进 ARM 内核的时候会被二分频!
* 配置 CCM_ANLOG->PLL_ARM 寄存器
* bit13: 1 使能时钟输出
* bit[6:0]: 88, 由公式:Fout = Fin * div_select / 2.0,
* 1056=24*div_select/2.0, 得出:div_select=88。 
*/
CCM_ANALOG->PLL_ARM = (1 << 13) | ((88 << 0) & 0X7F);
CCM->CCSR &= ~(1 << 2);/* 将 pll_sw_clk 时钟切换回 pll1_main_clk */
CCM->CACRR = 1; /* ARM 内核时钟为 pll1_sw_clk/2=1056/2=528Mhz *//* 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 */
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 */
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 */
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 分频 */
}

文件 bsp_clk.c 中一共有两个函数:clk_enable 和 imx6u_clkinit,其中函数 clk_enable 前面已经讲过了,就是使能 I.MX6U 的所有外设时钟。函数 imx6u_clkinit 才是本章的重点,imx6u_clkinit 先设置系统主频为 528MHz,然后根据 I.MX6U 时钟系统来设置 8 路 PFD,最后设置 AHB、IPG 和 PERCLK 的时钟频率。
在 bsp_clk.h 文件中添加函数 imx6u_clkinit 的声明,最后修改 main.c 文件,在 main 函数里
面调用 imx6u_clkinit 来初始化时钟,如下所示:

1 int main(void)
2 {
3 int i = 0;
4 int keyvalue = 0;
5 unsigned char led_state = OFF;
6 unsigned char beep_state = OFF;
7 
8 imx6u_clkinit(); /* 初始化系统时钟 */
9 clk_enable(); /* 使能所有的时钟 */
10 led_init(); /* 初始化 led */
11 beep_init(); /* 初始化 beep */
12 key_init(); /* 初始化 key */
13
14 /* 省略掉其它代码 */
15 }

上述代码的第 8 行就是时钟初始化函数,时钟初始化函数最好放到最开始的地方调用。


十、编译下载

10.1编写 Makefile 和链接脚本

本试验在链接的试验的基础上完成,而且本章试验没有添加任何新的文件,因此只需
要修改 Makefile 的变量 TARGET 为“clk”即可,如下所示:

TARGET ?= clk

链接脚本保持不变。

10.2编译下载

使用 Make 命令编译代码,编译成功以后使用软件 imxdownload 将编译完成的 clk.bin 文件
下载到 SD 卡中,命令如下:

chmod 777 imxdownload //给予 imxdownload 可执行权限,一次即可
./imxdownload clk.bin /dev/sdd //烧写到 SD 卡中,不能烧写到/dev/sda 或 sda1 设备里面!

烧写成功以后将 SD 卡插到开发板的 SD 卡槽中,然后复位开发板。本试验效果其实和试验本试验在链接的试验的基础上完成一样,但是 LED 灯的闪烁频率相比之前试验要快一点。因为试验之前实验的主频是 396MHz,而本试验的主频被配置成了 528MHz,因此代码执行速度会变快,所以延时函数的运行就会加快。


END
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/337682.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华为telnet的两种认证方式

华为telnet的两种认证方式 实验拓扑&#xff1a; 实验要求&#xff1a; 1.采用普通密码认证实现telnet 远程登录机房设备R3 2.采用AAA认证服务方式实现telnet 远程登录机房设备R3 实验步骤&#xff1a; 1.完成基本配置&#xff08;设备接口配置IP&#xff0c;此步骤略过&#…

戴尔向“数”而行,以“质”致远,做新质生产力的躬耕者

【全球存储观察 &#xff5c; 热点关注】 自1984年戴尔成立&#xff0c;一路走来&#xff0c;戴尔科技集团40年长期持续的技术创新&#xff0c;一直引领全球科技行业的技术趋势。 到如今&#xff0c;AIGC风行一时&#xff0c;在重塑千行百业的同时&#xff0c;也加速了科技行业…

Python自然语言处理(NLP)库之NLTK使用详解

概要 自然语言处理(NLP)是人工智能和计算机科学中的一个重要领域,涉及对人类语言的计算机理解和处理。Python的自然语言工具包(NLTK,Natural Language Toolkit)是一个功能强大的NLP库,提供了丰富的工具和数据集,帮助开发者进行各种NLP任务,如分词、词性标注、命名实体…

搭载昇腾310NPU的Orange Pi AIpro开箱体验以及深度学习样例测试

Orange Pi AIpro开箱体验以及样例测试 随着人工智能和物联网技术的快速发展&#xff0c;单板计算机&#xff08;Single Board Computer, SBC&#xff09;在创客和开发者社区中越来越受到欢迎。我最近入手了一款高性能的单板计算机——Orange Pi AIpro。 在入手此款AI开发板之…

C/C++中互斥量(锁)的实现原理探究

互斥量的实现原理探究 文章目录 互斥量的实现原理探究互斥量的概念何为原子性操作原理探究 互斥量的概念 ​ 互斥量&#xff08;mutex&#xff09;是一种同步原语&#xff0c;用于保护多个线程同时访问共享数据。互斥量提供独占的、非递归的所有权语义&#xff1a;一个线程从成…

动态路由协议实验——RIP

动态路由协议实验——RIP 什么是RIP ​ RIP(Routing Information Protocol,路由信息协议&#xff09;是一种内部网关协议&#xff08;IGP&#xff09;&#xff0c;是一种动态路由选择协议&#xff0c;用于自治系统&#xff08;AS&#xff09;内的路由信息的传递。RIP协议基于…

计算机组成原理·定点加减法与先行进位

重点理解一下加减法的电路实现&#xff0c;先行进位的原理&#xff0c;以及时间延迟分析。挑重点记录一下我的理解。 定点加减法的运算 运算原理 在计算机内&#xff0c;定点数都是以补码的形式进行运算的。两个数 x , y x,y x,y 的加减法满足下面的规则&#xff1a; { [ x …

深入理解 Go 语言中的字符串不可变性与底层实现

文章目录 前言1 字符串类型的数据结构组成2 为什么要这么设计数据结构&#xff1f;3 为什么说字符串类型不可修改&#xff1f;4 如何实现字符串的修改&#xff1f;5 为什么字符串修改的字面量用单引号&#xff1f;6 如何判断字符串的修改新建了一个字符串&#xff1f;7 字符串的…

【机器学习】智能选择的艺术:决策树在机器学习中的深度剖析

在机器学习的分类和回归问题中&#xff0c;决策树是一种广泛使用的算法。决策树模型因其直观性、易于理解和实现&#xff0c;以及处理分类和数值特征的能力而备受欢迎。本文将解释决策树算法的概念、原理、应用、优化方法以及未来的发展方向。 &#x1f680;时空传送门 &#x…

PieCloudDB Database Flink Connector:让数据流动起来

面对客户环境中长期运行的各种类型的传统数据库&#xff0c;如何优雅地设计数据迁移的方案&#xff0c;既能灵活地应对各种数据导入场景和多源异构数据库&#xff0c;又能满足客户对数据导入结果的准确性、一致性、实时性的要求&#xff0c;让客户平滑地迁移到 PieCloudDB 数据…

Linux|虚拟机|Windows 11 家庭版的Hyper虚拟机服务开启

前言&#xff1a; Windows11的版本是比较多的&#xff0c;但有的时候笔记本预装的可能是家庭版&#xff0c;而家庭版的Windows通常是不支持虚拟机的&#xff0c;也就是说Hyper服务根本就看不到 Windows的程序和功能大体如下&#xff1a; &#x1f197;&#xff0c;那么如何开…

【数据结构】P1 数据结构是什么、算法怎样度量

1.1 基本概念与术语 数据&#xff1a; 数据是信息的载体&#xff0c;是所有能被计算机识别以及处理的符号。数据元素&#xff1a; 数据元素是数据基本单位&#xff0c;由若干 数据项 组成&#xff0c;数据项是构成数据元素最小的单位。 e . g . e.g. e.g. 数据元素如一条学生记…

云动态摘要 2024-05-31

给您带来云厂商的最新动态&#xff0c;最新产品资讯和最新优惠更新。 最新优惠与活动 [1.5折起]年中盛惠--AI分会场 腾讯云 2024-05-30 人脸核身、语音识别、文字识别、数智人、腾讯混元等热门AI产品特惠&#xff0c;1.5折起 云服务器ECS试用产品续用 阿里云 2024-04-14 云…

HTML 转义字符(escape characters)及其对应的符号(symbols)

以下是常见的 HTML 转义字符及其对应的符号&#xff0c;这些可以用于在 HTML 或 JSX 中避免解析错误和特殊字符的冲突&#xff1a; 空格 ( ): 或 引号: 单引号&#xff08;&#xff09;&#xff1a;&apos;、&lsquo;、、&rsquo;双引号&#xff08;"&#x…

AI 网页解锁器,用于网页抓取一切 | 最快的验证码解决服务

想象一下&#xff0c;解锁互联网的全部潜力&#xff0c;数据自由流动&#xff0c;没有任何障碍阻挡你获取所需信息。在网络爬虫的世界里&#xff0c;这个梦想常常会遇到障碍&#xff1a;CAPTCHA和反机器人措施&#xff0c;这些措施旨在保护网站免受自动化访问的侵害。但如果有一…

前端传String字符串 后端使用enun枚举类出现错误

情况 前端 String 后端 enum 前端 后端 报错 2024-05-31T21:47:40.61808:00 WARN 21360 --- [nio-8080-exec-6] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to con…

[数据集][目标检测]红外车辆检测数据集VOC+YOLO格式13979张类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;13979 标注数量(xml文件个数)&#xff1a;13979 标注数量(txt文件个数)&#xff1a;13979 标…

C++程序命令行参数学习

argc是参数个数&#xff1b; argv[0]是程序名&#xff0c;argv[1]是第一个参数&#xff1b; 如果输入osgptr1 x &#xff0c;osgptr1是程序名&#xff0c;argc是2&#xff1b; 不算程序名&#xff0c;实际的参数个数是argc-1&#xff1b; #include <iostream>using …

STM32 入门教程(江科大教材)#笔记2

3-4按键控制LED /** LED.c**/ #include "stm32f10x.h" // Device headervoid LED_Init(void) {/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_I…

Python魔法之旅-魔法方法(08)

目录 一、概述 1、定义 2、作用 二、应用场景 1、构造和析构 2、操作符重载 3、字符串和表示 4、容器管理 5、可调用对象 6、上下文管理 7、属性访问和描述符 8、迭代器和生成器 9、数值类型 10、复制和序列化 11、自定义元类行为 12、自定义类行为 13、类型检…