嵌入式硬件——IMX6ULL时钟配置

一、时钟系统初始化准备

  • 关闭可能影响配置的模块(如Cache、MMU),避免时钟切换时内核不稳定;
  • 明确配置目标(如内核主频528MHz、AHB=132MHz、IPG=66MHz)。

读取并修改SCTLR寄存器(CP15协处理器):

  • 通过MRC指令读取CP15的SCTLR寄存器(系统控制寄存器);
  • 清零V位(bit13,允许异常向量表重定位)、I位(bit12,关闭I Cache)、C位(bit2,关闭D Cache)等,确保配置过程中无干扰。

确认外设时钟使能准备:

  • 后续需通过CCM_CCGR0~CCM_CCGR6寄存器启用外设时钟,初始可先全局使能(如enable_clocks函数,设置所有CCGR寄存器为0xFFFFFFFF)。

二、配置核心PLL(重点为ARM_PLL、PLL2、PLL3)

  • 配置ARM_PLL(PLL1)以设定内核主频;
  • 确认PLL2(528MHz)、PLL3(480MHz)的固定倍频(无需修改,仅需后续配置其PFD)。

操作步骤(以"内核主频528MHz"为例)

切换内核临时时钟源(避免PLL配置时内核停摆):

  • 配置CCM_CCSR寄存器(时钟控制状态寄存器):
    • CCM->CCSR &= ~(1 << 8):设置STEP_SEL位,使step_clk时钟源为24MHz晶振;
    • CCM->CCSR |= (1 << 2):设置PLL1_SW_CLK_SEL位,将内核时钟切换到step_clk(临时24MHz)。

配置ARM_PLL(PLL1)为1056MHz:

  • 操作CCM_ANALOG_PLL_ARM寄存器(PLL1配置寄存器):
    • 清零BYPASS位(bit16),禁用PLL旁路;
    • 设置DIV_SELECT位(bit12~bit0):根据公式Fout = Fin × (DIV_SELECT / 2.0),代入Fout=1056MHzFin=24MHz,计算得DIV_SELECT=88
    • 置位ENABLE位(bit13),使能PLL1输出。

设置内核分频(得到目标主频):

  • 配置CCM_CACRR寄存器(ARM时钟分频寄存器):
    • CCM->CACRR |= (1 << 0):设置ARM_PODF位为2分频(1056MHz / 2 = 528MHz)。

切换回PLL1主时钟:

  • CCM->CCSR &= ~(1 << 2):将PLL1_SW_CLK_SEL位清零,内核时钟切换回pll1_main_clk(528MHz)。

三、配置PLL2与PLL3的PFD(相位分数分频器)

  • 为外设提供多样化的根时钟源(如PLL2_PFD2供AHB根时钟),需按NXP推荐频率配置8路PFD(PLL2 4路+PLL3 4路)。

关键公式与配置步骤

PFD频率计算:

  • PLL2_PFDn:Fout = 528MHz × 18 / PFDn_FRACPFDn_FRAC范围12~35);
  • PLL3_PFDn:Fout = 480MHz × 18 / PFDn_FRACPFDn_FRAC范围12~35)。

按NXP推荐值配置PFD:

PFD模块 推荐频率 计算得PFDn_FRAC 操作寄存器
PLL2_PFD0 352MHz 27(528×18/27=352) CCM_ANALOG->PFD_528
PLL2_PFD1 594MHz 16(528×18/16=594) CCM_ANALOG->PFD_528
PLL2_PFD2 396MHz 24(528×18/24=396) CCM_ANALOG->PFD_528
PLL2_PFD3 297MHz 32(528×18/32=297) CCM_ANALOG->PFD_528
PLL3_PFD0 720MHz 12(480×18/12=720) CCM_ANALOG->PFD_480
PLL3_PFD1 540MHz 16(480×18/16=540) CCM_ANALOG->PFD_480
PLL3_PFD2 508.2MHz 17(480×18/17≈508) CCM_ANALOG->PFD_480
PLL3_PFD3 454.7MHz 19(480×18/19≈455) CCM_ANALOG->PFD_480

寄存器操作细节:

  • 先清零PFDn_FRAC位(如CCM_ANALOG->PFD_528 &= ~(0x3F << 0)),避免残留值;
  • 清零PFDn_CLKGATE位(如CCM_ANALOG->PFD_528 &= ~(1 << 7)),使能PFD输出。

四、配置AHB/IPG/PERCLK根时钟

  • 为外设提供标准时钟(AHB=132MHz、IPG=66MHz、PERCLK=66MHz),需从PFD选择输入时钟并分频。

配置步骤(以"PLL2_PFD2=396MHz为输入"为例)

配置AHB_CLK_ROOT(132MHz):

  • 选择输入时钟:配置CCM_CBCMR寄存器的PRE_PERIPH_CLK_SEL位(bit19~18),选择PLL2_PFD2为输入;
  • 分频设置:配置CCM_CBCDR寄存器的AHB_PODF位(bit12~10),设置为3分频(396MHz / 3 = 132MHz)。

配置IPG_CLK_ROOT(66MHz):

  • 输入时钟为AHB_CLK_ROOT,配置CCM_CBCDRIPG_PODF位(bit9~8),设置为2分频(132MHz / 2 = 66MHz)。

配置PERCLK_CLK_ROOT(66MHz):

  • 输入时钟为IPG_CLK_ROOT,配置CCM_CSCMR1PERCLK_PODF位(bit6~0),设置为1分频(66MHz / 1 = 66MHz)。

五、使能外设时钟

  • 为具体外设(如GPIO、UART、PWM)启用时钟,避免未使用外设耗电。

操作方式

全局使能(调试阶段便捷使用):

  • 通过enable_clocks函数,设置CCM_CCGR0~CCM_CCGR60xFFFFFFFF,启用所有外设时钟。

按需使能(量产阶段节能):

  • 每个CCM_CCGRx寄存器的每2位控制一个外设时钟,例如:
    • CCM_CCGR0bit31~30控制GPIO2时钟,设置为11(除停止模式外均使能);
    • 公式:CCM->CCGRx |= (0x03 << n)n为外设对应的位偏移)。

六、时钟配置验证

  • 确认时钟配置是否生效(如内核主频、根时钟频率)。

验证方法

软件验证:

  • 读取CCM_CACRRARM_PODF位,确认分频是否正确;
  • 读取CCM_ANALOG_PLL_ARMDIV_SELECT位,确认PLL1倍频是否正确;
  • 通过延时函数间接验证。

硬件验证:

  • 若开发板有示波器接口,可测量外设时钟引脚(如UART的PCLK),确认频率是否匹配配置值。

关键代码参考(基于clock.c

c 复制代码
// 1. 全局使能外设时钟
void enable_clocks(void) {
    CCM->CCGR0 = 0xFFFFFFFF;
    CCM->CCGR1 = 0xFFFFFFFF;
    CCM->CCGR2 = 0xFFFFFFFF;
    CCM->CCGR3 = 0xFFFFFFFF;
    CCM->CCGR4 = 0xFFFFFFFF;
    CCM->CCGR5 = 0xFFFFFFFF;
    CCM->CCGR6 = 0xFFFFFFFF;
}

// 2. 核心时钟配置(内核528MHz、AHB=132MHz、IPG=66MHz)
void init_clock(void) {
    unsigned int t;
    // 阶段2:切换内核临时时钟源(24MHz)
    CCM->CCSR &= ~(1 << 8);   // STEP_SEL=0,step_clk=24MHz
    CCM->CCSR |= (1 << 2);    // PLL1_SW_CLK_SEL=1,内核时钟=step_clk

    // 阶段2:配置ARM_PLL(PLL1=1056MHz)
    t = CCM_ANALOG->PLL_ARM;
    t &= ~(3 << 14);          // 清除BYPASS_CLK_SRC
    t |= (1 << 13);           // 使能PLL1
    t &= ~(0x7F << 0);        // 清除DIV_SELECT
    t |= (88 << 0);           // DIV_SELECT=88(1056MHz=24×88/2)
    CCM_ANALOG->PLL_ARM = t;
    CCM->CACRR |= (1 << 0);   // ARM_PODF=2分频(528MHz)

    // 阶段2:切换回PLL1主时钟
    CCM->CCSR &= ~(1 << 2);   // PLL1_SW_CLK_SEL=0,内核时钟=pll1_main_clk

    // 阶段3:配置PLL2_PFD(528MHz衍生)
    t = CCM_ANALOG->PFD_528;
    t &= ~((0x3F << 0) | (0x3F << 8) | (0x3F << 16) | (0x3F << 24));
    t &= ~((1 << 7) | (1 << 15) | (1 << 23) | (1 << 31));  // 使能PFD输出
    t |= (27 << 0) | (16 << 8) | (24 << 16) | (32 << 24);  // PFD0~PFD3配置
    CCM_ANALOG->PFD_528 = t;

    // 阶段3:配置PLL3_PFD(480MHz衍生)
    t = CCM_ANALOG->PFD_480;
    t &= ~((0x3F << 0) | (0x3F << 8) | (0x3F << 16) | (0x3F << 24));
    t &= ~((1 << 7) | (1 << 15) | (1 << 23) | (1 << 31));  // 使能PFD输出
    t |= (12 << 0) | (16 << 8) | (17 << 16) | (19 << 24);  // PFD0~PFD3配置
    CCM_ANALOG->PFD_480 = t;

    // 阶段4:配置AHB/IPG/PERCLK根时钟
    t = CCM->CBCMR;
    t &= ~(3 << 18);
    t |= (1 << 18);           // PRE_PERIPH_CLK_SEL=PLL2_PFD2
    CCM->CBCMR = t;

    t = CCM->CBCDR;
    t &= ~((7 << 10) | (3 << 8));
    t |= (2 << 10) | (1 << 8);  // AHB_PODF=3分频(132MHz)、IPG_PODF=2分频(66MHz)
    CCM->CBCDR = t;

    CCM->CSCMR1 &= ~(0X3F << 0);  // PERCLK_PODF=1分频(66MHz)

    // 阶段5:全局使能外设时钟
    enable_clocks();
}
相关推荐
小莞尔3 小时前
【51单片机】【protues仿真】基于51单片机秒表系统(LCD1602多功能、可保持30条记录)
c语言·stm32·单片机·嵌入式硬件·51单片机
Tolines4 小时前
PCIe外接卡标准尺寸
嵌入式硬件·硬件工程·设计规范
寅双木4 小时前
常见的九种二极管
笔记·嵌入式硬件·稳压二极管·tvs·肖特基二极管·发光二极管·齐纳击穿
Black doncky prince4 小时前
QR反激电源副边整流二极管电压波形分析
单片机·嵌入式硬件·硬件工程
currycheng64 小时前
开关电源测试及方法
单片机·嵌入式硬件·硬件架构·硬件工程
SundayBear5 小时前
基于MCU的文件系统
linux·服务器·单片机
DIY机器人工房11 小时前
关于解决 libwebsockets 库编译时遇到的问题的方法:
服务器·stm32·单片机·嵌入式硬件·tcp
GilgameshJSS12 小时前
STM32H743-ARM例程3-SYSTICK定时闪烁LED
arm开发·stm32·单片机·嵌入式硬件·学习
云山工作室13 小时前
基于单片机的按摩椅系统的设计(论文+源码)
stm32·单片机·嵌入式硬件·毕业设计·毕设