【Linux 裸机篇(六)】I.MX6U 主频和时钟配置

news2024/12/23 0:09:48

目录

  • 一、时钟系统详解
    • 1. 系统时钟来源
    • 2. 7路 PLL 时钟源
      • 2.1 ARM_PLL (PLL1)
      • 2.2 528_PLL (PLL2)
      • 2.3 USB1_PLL (PLL3)
      • 2.4 USB2_PLL (PLL7)
      • 2.5 ENET_PLL (PLL6)
      • 2.6 VIDEO_PLL (PLL5)
      • 2.7 AUDIO_PLL (PLL4)
    • 3. 时钟树简介
    • 4. 内核时钟设置
    • 5. PFD 时钟设置
    • 6. AHB、 IPG 和 PERCLK 根时钟设置
  • 二、程序编写

一、时钟系统详解

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


1. 系统时钟来源

I.MX6U-ALPHA 开发板的系统时钟来源于两部分: 32.768KHz 和 24MHz 的晶振,其中32.768KHz 晶振是 I.MX6U 的 RTC 时钟源, 24MHz 晶振是 I.MX6U 内核和其它外设的时钟源

在这里插入图片描述


2. 7路 PLL 时钟源

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

在这里插入图片描述

2.1 ARM_PLL (PLL1)

此路 PLL 是供 ARM 内核使用的, ARM 内核时钟就是由此 PLL 生成的,此 PLL 通过编程的方式最高可倍频到 1.3GHz。

2.2 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 接口等等。

2.3 USB1_PLL (PLL3)

此路 PLL 主要用于 USBPHY,此 PLL 也有四路 PFD,为:PLL3_PFD0~PLL3_PFD3, USB1_PLL 是固定的 20 倍频,因此 USB1_PLL=24MHz *20=480MHz。USB1_PLL虽然主要用于USB1PHY,但是其和四路PFD同样也可以作为其他外设的根时钟源。

2.4 USB2_PLL (PLL7)

(PLL7,没有写错!就是 PLL7,虽然序号标为 4,但是实际是 PLL7),看名字就知道此路PLL是给USB2PHY 使用的。同样的,此路PLL固定为20倍频,因此也是480MHz。

2.5 ENET_PLL (PLL6)

此路 PLL 固定为 20+5/6 倍频,因此 ENET_PLL=24MHz * (20+5/6) = 500MHz。此路 PLL 用于生成网络所需的时钟,可以在此 PLL 的基础上生成 25/50/100/125MHz 的网络时钟。

2.6 VIDEO_PLL (PLL5)

此路 PLL 用于显示相关的外设,比如 LCD,此路 PLL 的倍频可以调整, PLL 的输出范围在 650MHz~1300MHz。此路 PLL 在最终输出的时候还可以进行分频,可选 1/2/4/8/16 分频。

2.7 AUDIO_PLL (PLL4)

此路 PLL 用于音频相关的外设,此路 PLL 的倍频可以调整, PLL 的输出范围同样也是 650MHz~1300MHz,此路 PLL 在最终输出的时候也可以进行分频,可选 1/2/4 分频。


3. 时钟树简介

I.MX6U 的所有外设时钟源都是从这 7 路 PLL 和有些 PLL 的 PFD 而来的。图中一共有三部分: 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 的时钟图如图所示:
在这里插入图片描述
图中分为三部分:
  ①:此部分是时钟源选择器, 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。


4. 内核时钟设置

先从主频开始,我们将 I.MX6U 的主频设置为 528MHz,根据时钟树可以看到 ARM 内核时钟如图所示:

在这里插入图片描述
  ①:内核时钟源来自于 PLL1,假如此时 PLL1 为
  ②:通过寄存器 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 就可以设置为 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。


5. 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=52818/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。


6. 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。图中虽然写的是默认 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。


二、程序编写

1 #include "bsp_clk.h"
2 
3/***************************************************************
4 Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
5 文件名 : bsp_clk.c
6 作者 : 左忠凯
7 版本 : V1.0
8 描述 : 系统时钟驱动。
9 其他 : 无
10 论坛 : www.openedv.com
11 日志 : 初版 V1.0 2019/1/3 左忠凯创建
12
13 V2.0 2019/1/3 左忠凯修改
14 添加了函数 imx6u_clkinit(),完成 I.MX6U 的系统时钟初始化
15 ***************************************************************/
16
17 /*
18 * @description : 使能 I.MX6U 所有外设时钟
19 * @param : 无
20 * @return : 无
21 */
22 void clk_enable(void)
23 {
24 CCM->CCGR0 = 0XFFFFFFFF;
25 CCM->CCGR1 = 0XFFFFFFFF;
26 CCM->CCGR2 = 0XFFFFFFFF;
27 CCM->CCGR3 = 0XFFFFFFFF;
28 CCM->CCGR4 = 0XFFFFFFFF;
29 CCM->CCGR5 = 0XFFFFFFFF;
30 CCM->CCGR6 = 0XFFFFFFFF;
31 }
32
33 /*
34 * @description : 初始化系统时钟 528Mhz,并且设置 PLL2 和 PLL3 各个
35 PFD 时钟,所有的时钟频率均按照 I.MX6U 官方手册推荐的值.
36 * @param : 无
37 * @return : 无
38 */
39 void imx6u_clkinit(void)
40 {
41 unsigned int reg = 0;
42 /* 1、设置 ARM 内核时钟为 528MHz */
43 /* 1.1、判断当使用哪个时钟源启动的,正常情况下是由 pll1_sw_clk 驱动的,而
44 * pll1_sw_clk 有两个来源: pll1_main_clk 和 step_clk, 如果要
45 * 让 I.MX6ULL 跑到 528M, 那必须选择 pll1_main_clk 作为 pll1 的时钟
46 * 源。 如果我们要修改 pll1_main_clk 时钟的话就必须先将 pll1_sw_clk 从
47 * pll1_main_clk 切换到 step_clk,当修改完以后再将 pll1_sw_clk 切换
48 * 回 pll1_main_cl, step_clk 等于 24MHz。
49 */
50
51 if((((CCM->CCSR) >> 2) & 0x1 ) == 0) /* pll1_main_clk */
52 {
53 CCM->CCSR &= ~(1 << 8); /* 配置 step_clk 时钟源为 24MHz OSC */
54 CCM->CCSR |= (1 << 2); /* 配置 pll1_sw_clk 时钟源为 step_clk */
55 }
56
57 /* 1.2、设置 pll1_main_clk 为 1056MHz,也就是 528*2=1056MHZ,
58 * 因为 pll1_sw_clk 进 ARM 内核的时候会被二分频!
59 * 配置 CCM_ANLOG->PLL_ARM 寄存器
60 * bit13: 1 使能时钟输出
61 * bit[6:0]: 88, 由公式: Fout = Fin * div_select / 2.0,
62 * 1056=24*div_select/2.0, 得出: div_select=88。
63 */
64 CCM_ANALOG->PLL_ARM = (1 << 13) | ((88 << 0) & 0X7F);
65 CCM->CCSR &= ~(1 << 2);/* 将 pll_sw_clk 时钟切换回 pll1_main_clk */
66 CCM->CACRR = 1; /* ARM 内核时钟为 pll1_sw_clk/2=1056/2=528Mhz */
67
68 /* 2、设置 PLL2(SYS PLL)各个 PFD */
69 reg = CCM_ANALOG->PFD_528;
70 reg &= ~(0X3F3F3F3F); /* 清除原来的设置 */
71 reg |= 32<<24; /* PLL2_PFD3=528*18/32=297Mhz */
72 reg |= 24<<16; /* PLL2_PFD2=528*18/24=396Mhz */
73 reg |= 16<<8; /* PLL2_PFD1=528*18/16=594Mhz */
74 reg |= 27<<0; /* PLL2_PFD0=528*18/27=352Mhz */
75 CCM_ANALOG->PFD_528=reg; /* 设置 PLL2_PFD0~3 */
76
77 /* 3、设置 PLL3(USB1)各个 PFD */
78 reg = 0; /* 清零 */
79 reg = CCM_ANALOG->PFD_480;
80 reg &= ~(0X3F3F3F3F); /* 清除原来的设置 */
81 reg |= 19<<24; /* PLL3_PFD3=480*18/19=454.74Mhz */
82 reg |= 17<<16; /* PLL3_PFD2=480*18/17=508.24Mhz */
83 reg |= 16<<8; /* PLL3_PFD1=480*18/16=540Mhz */
84 reg |= 12<<0; /* PLL3_PFD0=480*18/12=720Mhz */
85 CCM_ANALOG->PFD_480=reg; /* 设置 PLL3_PFD0~3 */
86
87 /* 4、设置 AHB 时钟 最小 6Mhz, 最大 132Mhz */
88 CCM->CBCMR &= ~(3 << 18); /* 清除设置*/
89 CCM->CBCMR |= (1 << 18); /* pre_periph_clk=PLL2_PFD2=396MHz */
90 CCM->CBCDR &= ~(1 << 25); /* periph_clk=pre_periph_clk=396MHz */
91 while(CCM->CDHIPR & (1 << 5));/* 等待握手完成 */
92
93 /* 修改 AHB_PODF 位的时候需要先禁止 AHB_CLK_ROOT 的输出,但是
94 * 我没有找到关闭 AHB_CLK_ROOT 输出的的寄存器,所以就没法设置。
95 * 下面设置 AHB_PODF 的代码仅供学习参考不能直接拿来使用!!
96 * 内部 boot rom 将 AHB_PODF 设置为了 3 分频,即使我们不设置 AHB_PODF,
97 * AHB_ROOT_CLK 也依旧等于 396/3=132Mhz。
98 */
99 #if 0
100 /* 要先关闭 AHB_ROOT_CLK 输出,否则时钟设置会出错 */
101 CCM->CBCDR &= ~(7 << 10);/* CBCDR 的 AHB_PODF 清零 */
102 CCM->CBCDR |= 2 << 10; /* AHB_PODF 3 分频, AHB_CLK_ROOT=132MHz */
103 while(CCM->CDHIPR & (1 << 1));/* 等待握手完成 */
104 #endif
105
106 /* 5、设置 IPG_CLK_ROOT 最小 3Mhz,最大 66Mhz */
107 CCM->CBCDR &= ~(3 << 8); /* CBCDR 的 IPG_PODF 清零 */
108 CCM->CBCDR |= 1 << 8; /* IPG_PODF 2 分频, IPG_CLK_ROOT=66MHz */
109
110 /* 6、设置 PERCLK_CLK_ROOT 时钟 */
111 CCM->CSCMR1 &= ~(1 << 6); /* PERCLK_CLK_ROOT 时钟源为 IPG */
112 CCM->CSCMR1 &= ~(7 << 0); /* PERCLK_PODF 位清零,即 1 分频 */
113 }

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

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

相关文章

SQLite数据库简单小入门学习(一)

目录 一、认识数据库&#xff08;一&#xff09;数据库简介&#xff08;二&#xff09;数据库类型 二、SQLite数据库&#xff08;一&#xff09;SQLite简介&#xff08;二&#xff09;学习所需工具&#xff08;1&#xff09;scott.db&#xff08;2&#xff09;SQLiteSpy.exe &a…

【分布式理论】聊一下 ACID、BASE、CAP、FLP

分布式理论基础 今天我们来聊一下分布式相关基础理论基础&#xff0c;上一篇文章中&#xff0c;我描述了一下分布式系统的纲&#xff0c;但是想要入手学习分布式系统设计&#xff0c;其实需要先从基本理论开始。而知名的ACID、BASE、CAP、FLP都是相关的理论基础。 ACID ACID…

STM32平衡小车 TB6612电机驱动学习

TB6612FNG简介 单片机引脚的电流一般只有几十个毫安&#xff0c;无法驱动电机&#xff0c;因此一般是通过单片机控制电机驱动芯片进而控制电机。TB6612是比较常用的电机驱动芯片之一。 TB6612FNG可以同时控制两个电机&#xff0c;工作电流1.2A&#xff0c;最大电流3.2A。 VM电…

C++ [STL-简介]

本文已收录至《C语言和高级数据结构》专栏&#xff01; 作者&#xff1a;ARMCSKGT ​​​​​​​​ 文章目录 前言正文简介关于STL各种版本 STL组件容器迭代器配接器(适配器)算法仿函数空间配置器 STL的重要性学习STL的意义如何学习STL STL的缺陷 最后 前言 STL(standard tem…

Django+Vue的一个用户数据分析展示

文章目录 Git地址、项目所需文件总体效果展示一、项目环境所需二、Django代码解析2.1、执行文件2.2、注册app01 Git地址、项目所需文件 SQL数据文件和用户需求文件 提取码 1111 Git克隆地址 zip下载 其中第一个连接是数据文件&#xff0c;后两个连接选一个即可 总体效果展示 …

从idea向GitLab上传代码图文详解

这里写目录标题 一 新建一个idea工程二 点击左下角Version Control三 上传到GitLab四 给IDEA发链接五 回gitlab上校验六 去gitlab上把代码拖回来 在安装完gitlab插件&#xff0c;辛苦的配置完gitlab环境后&#xff0c;向gitlab中提交代码变成了首要任务 一 新建一个idea工程 二…

非常量引用只能绑定到左值

问题分析 代码情况&#xff1a; // ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 //#include <iostream> #include <vector> using namespace std; vector<int> fun1() {vector<int> ver1;for (int i…

HCIP之路---vlan实验

1、pc2/4/5/6同一网段&#xff0c;pc1/3与2/4/5/6不在同一网段 设置1/3 --- 192.168.1.0/24 2/4/5/6 --- 192.168.2.0/24 sw1上配置 [SW1-GigabitEthernet0/0/3]dis this # interface GigabitEthernet0/0/3 port link-type access port default vlan 2 # return [SW1-Giga…

C++类的模拟实现

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;C &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 本博客主要内容讲解了简单模拟实现string类 C类的模拟实现 文章目录 C类的…

Progress ThemeBuilder crack

Progress ThemeBuilder crack 自定义输入将覆盖自定义日期输入和下拉列表。 Fluent主题中的图表不应用系列颜色。 撤消重做操作会导致重复以前编辑过的变量。 拆分器折叠的拆分条模板错误。 ThemeBuilder是一个多功能工具&#xff0c;可以帮助您创建视觉样式&#xff0c;并将其…

数据分析入门之:如何快速安装使用Jupyter Notebook?

人生苦短&#xff0c;我用python 今天来给大家介绍一下关于Jupyter Notebook的用法 关于它的组成部分就先不在这里详细解说啦~ 毕竟我可太懂你们啦~ 文章太长就会吃灰的~ python 安装包资料:点击此处跳转文末名片获取 一、什么是Jupyter Notebook&#xff1f; 1. 简介 Jupy…

Atom 1.13版本带来的哪些改变?

Atom是GitHub基于Electron的开源文本编辑器&#xff0c;它的1.13版本 为用户和开发人员增加了许多新的特性和改进&#xff0c;包括一个基准工具&#xff0c;一个“重新打开项目”菜单选项和API&#xff0c;以及一个自定义按钮解析器&#xff0c;它可以把Chrome键盘事件映射为At…

PTA L1-092 进化论 (10 分)

在“一年一度喜剧大赛”上有一部作品《进化论》&#xff0c;讲的是动物园两只猩猩进化的故事。猩猩吕严说自己已经进化了 9 年了&#xff0c;因为“三年又三年”。猩猩土豆指出“三年又三年是六年呐”…… 本题给定两个数字&#xff0c;以及用这两个数字计算的结果&#xff0c;…

【c语言】函数的基本概念 | 函数堆栈调用原理

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ…

【通知】CSDN学院:<华为流程体系课程> 正式上线啦!

目录 前言 适用人群 你将收获 课程介绍 前言 经过两个月的准备和短视频测试&#xff0c;这门介绍华为流程体系的课程就正式上线了。 虽然由于公开的原因&#xff0c;华为的发展受到了一定程度的影响&#xff0c;但是丝毫不妨碍企业、以及一些个人对学习华为的热情。 原因…

Java内存模型详解

Java内存模型 Java内存模型(Java Memory Model)是Java虚拟机规范定义的&#xff0c;用于屏蔽因不同程序/硬件/操作系统上内存访问的差异&#xff0c;确保程序运行与设计一致&#xff0c;Java内存模型定义了Java虚拟机在计算机内存中的工作方式&#xff0c;确定了在共享内存系统…

通过SSH实现Linux与Windows之间的文件互传

目录 一 序言 二 准备工作 三 Windows端操作命令&#xff0c;实现文件互传 四 Linux端操作命令&#xff0c;实现文件互传 五 总结 一 序言 Linux和Linux以及Windows和Windows之间的文件共享互传&#xff0c;大家应该接触的都比较多&#xff0c;无非就是两种方式&#xff…

【C++类和对象】类和对象(上) {初识面向对象,类的引入,类的定义,类的访问限定符,封装,类的作用域,类的实例化,类对象模型,this指针}

一、面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题。 C是基于面向对象的&#xff0c;关注的是对象&#xff0c;将一件事情拆分成不同的对象&#xff0c;靠对象之间的交互完成。…

1.2和1.3、GCC

1.2和1.3、GCC 1.2和1.3、GCC1.2.1、什么是GCC1.2.2、编程语言的发展1.2.3、GCC工作流程1.2.4、gcc和g的区别1.2.5、GCC常用参数选项实际操作①接下来进行预处理操作&#xff08;test.c为需要预处理的源代码&#xff0c;test.i为要生成的目标代码&#xff09;②汇编操作&#x…

iOS--SDWebImage源码

文章目录 前言它提供了UIImageView的一个分类&#xff0c;支持从网路上下载且缓存图片&#xff0c;并设置图片到对应的UIImageView控件或者UIButton控件。 SDWebImage简介官方图解主序列图&#xff08;Main Sequence Disagram&#xff09;顶层API图&#xff08;Top Level API D…