Linux学习笔记12---主频和时钟配置实验

news2024/9/20 22:33:59
        本章学习 I.MX6U 的时钟系统,学习如何配置 I.MX6U 的 系统时钟和其他的外设时钟,使其工作频率为 528MHz ,其他的外设时钟源都工作在 NXP 推荐的频率。

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

2、 系统时钟来源

打开 I.MX6U-ALPHA 开发板原理图,开发板时钟原理图如图 所示: 
        从图中可以看出 I.MX6U-ALPHA 开发板的系统时钟来源于两部分: 32.768KHz 和 24MHz 的晶振,其中 32.768KHz 晶振是 I.MX6U RTC 时钟源, 24MHz 晶振是 I.MX6U 内核 和其它外设的时钟源,也是我们重点要分析的

3、7 PLL 时钟源

        I.MX6U 的外设有很多,不同的外设时钟源不同, NXP 将这些外设的时钟源进行了分组,一共有 7 组,这 7 组时钟源都是从 24MHz 晶振 PLL 而来的,因此也叫做 7 PLL ,这 7 PLL 结构如图 所示:
        图中展示了 7 PLL 的关系,我们依次来看一下这 7 PLL 都是什么做什么的:
  • ①、 ARM_PLLPLL1),此路 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 分频。

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 个可选的时钟源:PLL4PLL5PLL3_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 章。

5、内核时钟设置

        I.MX6U 的时钟系统前面几节已经分析的差不多了,现在就可以开始设置相应的时钟频率 了。先从主频开始,我们将 I.MX6U 的主频设置为 528MHz ,根据 时钟树可以看到
ARM 内核时钟如图 所示:
在上图 中各部分如下:
  • ①、内核时钟源来自于 PLL1,假如此时 PLL1 996MHz
  • ②、通过寄存器 CCM_CACRR ARM_PODF 位对 PLL1 进行分频,可选择 1/2/4/8 分频,假如我们选择 2 分频,那么经过分频以后的时钟频率是 996/2=498MHz
  • ③、大家不要被此处的 2 分频给骗了,此处没有进行 2 分频
  • ④、经过第②步 2 分频以后的 498MHz 就是 ARM 的内核时钟,也就是 I.MX6U 的主频。 经过上面几步的分析可知,假如我们要设置内核主频为 528MHz,那么 PLL1 可以设置为 1056MHz,寄存器 CCM_CACRR ARM_PODF 位设置为 2 分频即可。同理,如果要将主频设 置为 696MHz,那么 PLL1 就可以设置为 696MHzCCM_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

6、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 的计算公式为 528*18/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

7、 AHBIPG 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 的时钟源,可以选择 PLL2PLL2_PFD2PLL2_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。图 中虽然写的是默认 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.MX6U 的时钟系统还是很复杂的,大家要结合 《I.MX6ULL 参考手册》中时钟相关的结构图来学习。本章我们也只是讲解了如何进行主频、 PLL、 PFD 和一些总线时钟的设置,关于具体的外设时钟设置我们在学习到的时候在详细的讲 解。

8、 实验程序编写

本试验在上一章试验“ 7_key ”的基础上完成,因为本试验是配置 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	: 初始化系统时钟,设置系统时钟为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分频 */
}

        文件 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 来初始化时钟,如下所示:
#include "bsp_clk.h"
#include "bsp_delay.h"
#include "bsp_led.h"
#include "bsp_beep.h"
#include "bsp_key.h"

/*
 * @description	: main函数
 * @param 		: 无
 * @return 		: 无
 */
int main(void)
{
	int i = 0;
	int keyvalue = 0;
	unsigned char led_state = OFF;
	unsigned char beep_state = OFF;
	
	imx6u_clkinit();	 /* 初始化系统时钟 */   //时钟初始化函数,时钟初始化函数最好放到最开始的地方调用。
	clk_enable();		/* 使能所有的时钟 			*/
	led_init();			/* 初始化led 			*/
	beep_init();		/* 初始化beep	 		*/
	key_init();			/* 初始化key 			*/
	
	while(1)			
	{	
		keyvalue = key_getvalue(); //查询按键状态
		if(keyvalue)
		{
			switch ((keyvalue))
			{
				case KEY0_VALUE:
					beep_state = !beep_state;
					beep_switch(beep_state);
					break;
			}
		}

		i++;
		if(i==50)
		{
			i = 0;
			led_state = !led_state;
			led_switch(LED0, led_state);
		}
		delay(10);	
	}

	return 0;
}

9、编写 Makefile 和链接脚本

因为本章是在试验“ 7_key ”上修改的,而且本章试验没有添加任何新的文件,因此只需要修改 Makefile 的变量 TARGET 为“ clk ”即可,如下所示:
TARGET ?= clk
链接脚本保持不变。

10、编译下载

使用 Make 命令编译代码,
编译成功以后使用软件 imxdownload2 将编译完成的 clk.bin 文件生成可执行的img文件,命令如下:
chmod 777 imxdownload //给予 imxdownload 可执行权限,一次即可
./imxdownload clk.bin 
        利用Win32DiskImager软件将load.img执行文件写入SD卡,SD卡插入开发板上即可正常运行。
        如果代码运行正常的话 LED0 会以大约 500ms 周期闪烁, 按下开发板上的 KEY0 按键,蜂鸣器打开,再按下 KEY0按键,蜂鸣器关闭。本试验效果其实和试 验“7_key”一样,但是 LED 灯的闪烁频率相比试验“7_key”要快一点。因为试验“7_key”的 主频是396MHz,而本试验的主频被配置成了 528MHz,因此代码执行速度会变快,所以延时函数的运行就会加快。

11、例程

【免费】Linux学习笔记12-主频和时钟配置实验程序资源-CSDN文库

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2工作队列

工作队列 逻辑图 <!-- SpringBoot 消息队列的起步依赖 --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId> </dependency>轮询分发 Round-robin 生产者 import com…

[数据集][目标检测]人脸口罩佩戴目标检测数据集VOC+YOLO格式8068张3类别

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

Fortran程序辅助构建(Python)

目的 Visual Studio用不明白&#xff0c;于是我找了一个Fortran解释器&#xff08;大概&#xff09;&#xff0c;接着了解到cmd也是可以直接运行Fortran的&#xff0c;于是VScode就又得1分。但是每次构建都得敲命令&#xff0c;后来我就写了一个脚本&#xff0c;专门解决这个痒…

【人工智能/机器学习/机器人】数学基础-学习笔记

函数 奇偶性&#xff1a; 偶函数&#xff1a; f ( − x ) f ( x ) f(-x)f(x) f(−x)f(x)   y轴对称 f ( x ) x 2 f(x)x^2 f(x)x2     f ( − x ) ( − x ) 2 x 2 f ( x ) f(-x)(-x)^2x^2f(x) f(−x)(−x)2x2f(x) 奇函数&#xff1a; f ( − x ) − f ( x ) f(-…

如何制作新生资料收集系统?

新学年伊始&#xff0c;学校需要高效收集学生信息和证件照。易查分提供了一个便捷的解决方案&#xff0c;通过创建一个集成信息和图片的收集系统&#xff0c;可以快速完成这项工作&#xff0c;并将信息导出为PDF&#xff0c;方便打印和存档。 制作步骤如下&#xff1a; 1. 准备…

Android Studio打开Modem模块出现:The project ‘***‘ is not a Gradle-based project

花了挺长时间处理该问题&#xff0c;特记录如下&#xff1a;1.背景&#xff1a; 在Android studio 下导入一个新增的modem模块&#xff0c;如MPSS.DE.3.1.1\modem_proc\AAA, 目的是看代码方便一些&#xff0c;可以自由搜索各种关键字。但导入该项目时出现了如下错误&#xff1a…

C++ 封装 DLL 供 Unity 调用

一&#xff1a;封装DLL 开发工具最好使用 Visual Studio 20XX 来制作&#xff0c;因为VS Code 需要配置很多东西&#xff0c;环境搭建过程比较复杂。 a、我安装的是 Visual Studio 2022&#xff0c;安装的时候&#xff0c;【工作负荷】记得勾选 【使用C的桌面开发】和【使用C的…

dubbo 服务消费原理分析之引用服务配置

文章目录 前言一、服务监听ContextRefreshedEvent1、AbstractApplicationContext.refresh2、AbstractApplicationContext.finishRefresh3、DubboDeployApplicationListener.onApplicationEvent4、DefaultModuleDeployer .referServices5、SimpleReferenceCache.get 二、引用服务…

SRT库介绍

文章目录 简介SRT协议介绍FFmpegSRS推拉流测试SRT库介绍apps示例程序srt-file-transmitsrt-live-transmitsrt-test-multiplexsrt-test-relaysrt-tunnel docs/buildsrtcoreexamples编译 安装错误处理 API说明初始化、回收创建配置套接字连接管理Socket Group属性设置传输数据统计…

CNC数控加工如何开启个性化制造新时代?

在现代制造业中&#xff0c;CNC 数控加工定做正以其独特的特点和显著的优势&#xff0c;成为满足各种复杂、高精度加工需求的首选方式。与时利和一起了解CNC 数控加工定做是如何开启个性化制造新时代! 一、CNC 数控加工定做的特点 1.高精度加工 CNC 数控加工依靠先进的计算机控…

Java并发编程实战 04 | 使用WaitNotify时要注意什么?

在 Java 中&#xff0c;wait()、notify() 和 notifyAll() 方法在多线程编程中主要用于线程间的协作和同步。理解这些方法的使用特点对于编写稳定的多线程程序至关重要。我们将从以下三个问题入手深入探讨它们的使用&#xff1a; 为什么必须在 synchronized 代码块中使用 wait(…

字体反爬(一)

网址 http://xxfb.mwr.cn/sq_djdh.html?v1.0 获取相关数据 解决 F12 先找接口吧&#xff0c; 搜索一下表格的数据 直接从表格中复制 复制过来乱码&#xff0c;基本锁定有字体反爬处理 先点进去看看 {"addvnm": "#GkcERlldm4_1725629424756otltag㯼㢴#Fon…

Linux 技巧汇编

10个重要的Linux ps命令实战 显示所有当前进程 根据用户过滤进程 通过cpu和内存使用来过滤进程 通过进程名和PID过滤 根据线程来过滤进程 树形显示进程 显示安全信息 格式化输出root用户&#xff08;真实的或有效的UID&#xff09;创建的进程 使用PS实时监控进程状态 …

泛型列表相关知识

集合 C#中集合是指在system.Collection下的类型&#xff0c;他们大多数是通过实现此命名空间下的接口来实现的。 C#集合是来维护一组对象的数据结构&#xff0c;与数组不同&#xff0c;集合包含更多的功能。如&#xff1a;自动添加元素到指定位置&#xff0c;排序等。 泛型集…

企业级WEB应用服务器---TOMACT

一、WEB技术介绍 1.1 Http和B/S结构 操作系统一般都有子进程系统&#xff0c;使用多进程就可以充分利用硬件资源&#xff0c;提高效率。在前面的学习中我们了解到进程中可以有多个线程&#xff0c;且每一个线程都可以被CPU调度执行&#xff0c;这样就可以让程序并行执行。一台…

深入浅出孪生神经网络,高效训练模型

大家好&#xff0c;在深度学习领域&#xff0c;神经网络几乎能处理各种任务&#xff0c;但通常需要依赖于海量数据来达到最佳效果。然而&#xff0c;对于像面部识别和签名验证这类任务&#xff0c;我们不可能总是有大量的数据可用。由此产生了一种新型的神经网络架构&#xff0…

【自考zt】【数据结构】【22.04】

一、单选 二、填空 三、解答 四、算法阅读 五、算法设计

【Flutter】解决第一次运行项目很慢(gradle需要下载依赖)

配置gradle默认下载路径 默认下C盘谁顶得住 配置环境变量 名称: GRADLE_USER_HOME 值: D:\Develop\gradle 自己创建一个 下边是重点 配置gradle远端下载地址 后边版本号自己换 https://mirrors.cloud.tencent.com/gradle/ https://mirrors.cloud.tencent.com/gradle/gradl…

Matlab 一维层状声子晶体振动传输特性

一维声子晶体的传递矩阵法是一种用于研究声波在一维周期性结构中传播的方法。这种方法基于‌波动方程和周期性边界条件&#xff0c;通过计算声波在不同介质中的传播特性&#xff0c;进而分析声子晶体的带隙结构。传递矩阵法可以有效地预测声波在一维声子晶体中的传播行为&#…

利用AI大语言模型和Langchain开发智能车算法训练知识库(上篇)

今天小李哥将介绍亚马逊云科技的Jupyter Notebook机器学习托管服务Amazon SageMaker上&#xff0c;通过AI大语言模型、向量知识库和LangChain Agent&#xff0c;创建用于AI 智能车模型训练的RAG问答知识库。整个项目的架构图如下&#xff1a; 本系列共分为上下两篇。在上篇内容…