当前位置: 首页 > article >正文

I.MX6U 裸机开发12.主频修改和PLL配置

I.MX6U 裸机开发12.主频修改和PLL配置

  • 一、系统主频配置
    • 1. 分频系数
    • 2. PLL1
      • pll1_sw_clk
    • 3. step_clk 临时时钟
    • 4. 修改PLL1
    • 5. 设置分频
  • 二、系统主频配置代码实现
    • 1. 创建工程
    • 2. 实现初始化时钟函数
      • (1)切换时钟源
      • (2)设置PLL1
    • 3. main 文件
    • 4. 超频
  • 三、PLL配置
  • 四、其它外设时钟源配置
    • 1. AHB_CLK_ROOT
      • AHB_CLK_ROOT介绍
      • AHB_CLK_ROOT 的时钟树
      • AHB_CLK_ROOT的初始化方法
        • 设置 CBCMR[PRE_PERIPH_CLK_SEL]
        • 设置 CCM_CBCDR[PERIPH_CLK_SEL]
        • 设置 CBCDR[AHB_PODF]
    • 2. IPG_CLK_ROOT
      • 时钟树
      • CCM_CBCDR[IPG_PODF]
    • 3. PERCLK_CLK_ROOT 初始化
      • CCM_CSCMR1[PERCLK_CLK_SEL]:

在这里插入图片描述

一、系统主频配置

前面章节运行时,系统运行在默认主频396MHz下。下面将主频改为528MHz。

首先要配置的是PLL1,即ARM PLL,如下图所示:
在这里插入图片描述

1. 分频系数

CACRR 寄存器用于设置 ARM 内核时钟的分频系数。该寄存器的值决定了从 PLL 输出的时钟频率如何被分频以生成 ARM 内核时钟。
ARM_PODFCACRR 寄存器中的一个字段,用于指定 ARM 内核时钟的分频系数。通过设置 ARM_PODF,可以控制 ARM 内核时钟的频率。
ARM_PODF 字段位于 CACRR 寄存器的 [2:0] 位,字段值如下:

ARM_PODF 字段值

  • 000 : 除以 1
  • 001 : 除以 2
  • 010 : 除以 3
  • 011 : 除以 4
  • 100 : 除以 5
  • 101 : 除以 6
  • 110 : 除以 7
  • 111 : 除以 8

假设 PLL 输出频率为 1056 MHz,通过设置 ARM_PODF 字段,可以将 ARM 内核时钟分频到所需的频率。例如:

  • ARM_PODF = 0:ARM 内核时钟 = 1056 MHz / (0 + 1) = 1056 MHz
  • ARM_PODF = 1:ARM 内核时钟 = 1056 MHz / (1 + 1) = 528 MHz
  • ARM_PODF = 2:ARM 内核时钟 = 1056 MHz / (2 + 1) = 352 MHz

假设使用的是696M的主频,ARM_PODF选择2分频,则PLL值是 696*2=1392M,通过《IMX6ULL参考手册》 P644,可以看到 PLL1 的范围是 650MHz - 1.3GHz:
在这里插入图片描述
这样的设置会超出限制,选择就不能选择2分频,只能除以1。

要设置ARM内核主频是528MHz,可以设置CACRR[ARM_PODF]为2分频, PLL1=1056MHz。

2. PLL1

如《IMX6ULL参考手册》 P648页图所示:
在这里插入图片描述

pll1_sw_clk

pll1_sw_clk 是I.MX6U处理器中的一个时钟信号选择器,用于选择PLL1的输出时钟源。 它有两个时钟源可选:

  • pll1_main_clk: PLL1 的主时钟输出
  • pll1_step_clk: PLL1的旁路时钟输出

pll1_sw_clk 通过寄存器 CCSR[plt_sw_clk_sel]寄存器控制,字段值如下:

  • 0:选择 pll1_main_clk 作为时钟源
  • 1:选择 pll1_step_clk 作为时钟源

P665

3. step_clk 临时时钟

在修改PLL1的时候,需要给I.MX6U 一个临时的时钟,即step_clk。
step_clk前面有一个时钟信号选择器,使用 CCRS[step_sel]控制,字段值如下:

  • 0 : 选择 osc_clk 作为步进时钟源
  • 1 : 选择 pll2_main_clk 作为步进时钟源

我们使用值0,即osc_clk,时钟修改成功后,可以修改PLL1。

4. 修改PLL1

计算公式 :
在这里插入图片描述
如文档所示,由CCM_ANALOG_PLL_ARM[DIV_SELECT]设置PLL1频率。

DIV_SELECT 字段值位于 CCM_ANALOG_PLL_ARM 寄存器的 [6:0] 位,
该字段的值决定了 PLL 的倍频系数,具体的频率计算公式为:

PLL 输出频率 = 输入时钟频率 × DIV_SELECT / 分频 \text{PLL 输出频率} = \text{输入时钟频率} \times \text{DIV\_SELECT} / 分频 PLL 输出频率=输入时钟频率×DIV_SELECT/分频

我们使用的freq=24,由: 1056 = 24 ∗ D I V _ S E L E C T / 2 1056=24*DIV\_SELECT/2 1056=24DIV_SELECT/2 得出: DIV_SELECT = 88。

5. 设置分频

在切换回PLL1之前,设置CACRR[ARM_PODF]=1,即二分频。

二、系统主频配置代码实现

1. 创建工程

复制上次实验工程 , 修改项目名称。

2. 实现初始化时钟函数

(1)切换时钟源

首先要判断当前的时钟源是 pll1_main_clock 不是 pll1_step时钟,则切换时钟源:

    // 如果PLL1_SW_CLK_SEL 当前是 step_clk
    if (((CCM->CCSR >> 2) & 0x1)== 0) {
        CCM->CCSR &= ~(1 << 8); // step_sel=osc_clk(24MHz)
        CCM->CCSR |= (1 << 2);  // 设置pll1_main_clk=step_clk=24MHz
    }

(2)设置PLL1

    // 设置PLL1=1056MHz
    CCM_ANALOG->PLL_ARM = (1 << 13) | ((88 << 0) & 0x7f); // 528*2=1056MHz, 1056*2/24=88
    // 设置二分频 arm_clk=1056/2=528MHz
    CCM->CACRR = 1;
    // 将pll1_sw_clk切换为pll1_main_clk,即1056MHz
    CCM->CCSR &= ~(1 << 2);

3. main 文件

#include "inc/main.h"
#include "bsp_clk.h"
#include "bsp_delay.h"
#include "led.h"
#include "beep.h"
#include "key.h"

int main(void)
{
   imx6u_clkinit();    /* 初始化系统时钟 */
   clk_enable();   /* 使能外设时钟 */
   led_init();     /* 初始化LED */
   beep_init();    /* 初始化蜂鸣器 */

   while(1) {
       led_on();
       delay(1000);
       led_off();
       delay(1000);
   }
   return 0;
}

烧录程序运行,可以与之前的LED闪烁比较感受下运行速度变化的差异。

4. 超频

修改 imx6u_clkinit(void) 函数如下:


// 设置PLL1=696MHz
CCM_ANALOG->PLL_ARM = (1 << 13) | ((58 << 0) & 0x7f); // 24MHz * 58 = 696MHz
// 设置一分频 arm_clk=696/1=696MHz
CCM->CACRR = 0;
// 将pll1_sw_clk切换为pll1_main_clk,即696MHz
CCM->CCSR &= ~(1 << 2);

这样将会以696MHz主频运行。

三、PLL配置

由于 PLL2 固定为528MHz, PLL3固定为480MHz,按要求配置即可。
PLL2和PLL3 各有4路PFD, 这些PFD需要初始化。

  1. 初始化 PLL2_PFD0~PFD3
  2. 初始化 PLL3_PFD0~PFD3

以PLL2的为例,在《IMX6ULL参考手册》P736,介绍 CCM_ANALOG_PFD_528n寄存器,以PFD0_FRAC为例:

PFD0频率,计算公式:
P L L 2 P F D 0 = 480 ∗ 18 / P F D 0 _ F R A C PLL2_PFD0 = 480*18/PFD0\_FRAC PLL2PFD0=48018/PFD0_FRAC
如PLL2_PFD0=352M,则PLL2_PFD0 = 352M=528*18/PFD0_FRAC,计算得 PFD0_FRAC设置为27。
其它几路设置也类似 ,得到代码如下:



static void imx6u_clk_pll2_pfd_init(void){
    // 配置PLL2的PFD0~PFD3
    uint32_t reg = 0;
    reg = CCM_ANALOG->PFD_528;
    reg &= ~(0x3F3F3F3F); // 清除原来的设置

    // PLL2 PFD3=297MHz, 528*18/297MHz=32
    reg |= 32 << 24;
    // PLL2 PFD2=396MHz, 528*18/396=24
    reg |= 24 << 16;
    // PLL2 PFD1=594MHz, 528*18/594=16
    reg |= 16 << 8;
    // PLL2 PFD0=352MHz, 528*18/352=27
    reg |= 27 << 0;
    // 设置PLL2_PFD0~3
    CCM_ANALOG->PFD_528 = reg;
}

static void imx6u_clk_pll3_pfd_init(void){
    // 配置PLL3的PFD0~PFD3
    uint32_t reg = 0;
    reg = CCM_ANALOG->PFD_480;
    reg &= ~(0x3F3F3F3F); // 清除原来的设置

    // PLL3 PFD3=454.7MHz, 480*18/454.7=19
    reg |= 19 << 24;
    // PLL3 PFD2=508.2MHz, 480*18/508.2=17
    reg |= 17 << 16;
    // PLL3 PFD1=540MHz, 480*18/540=16
    reg |= 16 << 8;
    // PLL3 PFD0=720Hz, 480*18/720=12
    reg |= 12 << 0;
    // 设置PLL3_PFD0~3
    CCM_ANALOG->PFD_480 = reg;
}

四、其它外设时钟源配置

1. AHB_CLK_ROOT

AHB_CLK_ROOT介绍

AHB_CLK_ROOT是AHB总线的主时钟源。AHB总线用于连接处理器、内存和外设等模块,提供高性能的总线通信。AHB_CLK_ROOT的频率直接影响系统的性能和功耗。

通过《IMX6ULL参考手册》P643的表格:

在这里插入图片描述
可以看到AHB_CLK_ROOT的默认频率是6MHz,最大132MHz。

AHB_CLK_ROOT 的时钟树

在这里插入图片描述

AHB_CLK_ROOT的初始化方法

根据上面的时钟树,按下面顺序进行设置:

设置 CBCMR[PRE_PERIPH_CLK_SEL]

在这里插入图片描述
PRE_PERIPH_CLK_SEL 是预外设时钟多路复用器的选择器,字段值说明:

  • 00:从 PLL2 派生时钟
  • 01:从 PLL2 PFD2 派生时钟
  • 10:从 PLL2 PFD0 派生时钟
  • 11:从分频(/2)的 PLL2 PFD2 派生时钟
    这里设置为01:
    // PRE_PERIPH_CLK_SEL=1, 选择pll2_pfd2=396MHz
    CCM->CBCDR &= ~(3 << 18);
    CCM->CBCDR |= 1 << 18;
设置 CCM_CBCDR[PERIPH_CLK_SEL]

在这里插入图片描述
这里设置为0, PLL2(pll2_main_clk)。

设置 CBCDR[AHB_PODF]

在这里插入图片描述
在这里插入图片描述
这里设置为2,即3分频,得到 396/3=132MHz外设频率。

需要注意的是 CCM_CDHIPR 的 AHB_PODF_BUSY,需要在0的时候设置

2. IPG_CLK_ROOT

PERCLK_CLK_ROOT要设置为66MHz,IPG_CLK_ROOT也是66MHz,在配置PERCLK_CLK_ROOT时,可以顺便先配置好IPG_CLK_ROOT。

时钟树

在这里插入图片描述
从图中可以看出,从AHB_CLK_ROOT 的时钟信号,经过 CBCDR[IPG_PODF]二分频,可以给 IPG_CLK_ROOT 66MHz信号 。

CCM_CBCDR[IPG_PODF]

在这里插入图片描述
这里设置为1,二分频。
代码如下:

/**
 * @brief 初始化IPG时钟, 设置IPG_CLK_ROOT=66MHz
 */
static void imx6u_ipg_clk_init(void) {
    // 清0 IPG_PODF
    CCM->CBCDR &= ~(3 << 8);
    // 设置IPG_PODF=1, 二分频
    CCM->CBCDR |= 1 << 8;
}

这样 IPG_CLK_ROOT 就设置好了。

3. PERCLK_CLK_ROOT 初始化

CCM_CSCMR1[PERCLK_CLK_SEL]:

在这里插入图片描述
这里设置为0。
分频是 CCM->CSCMR1 bit0~5:

在这里插入图片描述
这里设置为 0,1分频。

代码如下:

/**
 * @brief 初始化PERCLK时钟,设置PERCLK_CLK_ROOT=66MHz
 */
static void imx6u_perclk_init(void) {
    // 清0 PERCLK_CLK_SEL
    CCM->CSCMR1 &= ~(1 << 6);
    // 分频
    CCM->CSCMR1 &= ~(7 << 0);
}


http://www.kler.cn/a/402122.html

相关文章:

  • 用PHP实现一个简单的http服务器
  • 学习记录:js算法(九十八):课程表 II
  • 【Python数据可视化分析实战】数据爬取—京东手机品牌信息数据爬取和数据分析与可视化
  • 等保二级需要哪些安全设备?
  • openfoam中通过precice耦合的流固耦合案例如何单独运行流体这样可以防止报错float exception
  • 如何利用virtualenv和python命令创建Python虚拟环境
  • AI赋能电商:开启智慧零售新纪元
  • 高阶数据结构——图
  • Go语言里简短声明语句词法域问题
  • 【Electron】Electron Forge如何支持Element plus?
  • 视频里的音频怎么提取出来成单独文件?音频提取照着这些方法做
  • 论文阅读:Mixture-of-Agents Enhances Large Language Model Capabilities
  • MATLAB和Python发射光谱
  • 【Linux】深入理解GCC/G++编译流程及库文件管理
  • C++中的std::tuple和std::pair
  • C++---类型转换
  • 5G CPE:为什么活动会场与商铺的网络成为最新选择
  • lua调用C语言函数,在函数中进行类型检查
  • CPU服务器是指什么?
  • 如何解决Ubuntu 20.04中Vim编辑器在按下Ctrl+S时暂停响应的问题