1. PLL、Prescaler、PFD 的作用
结合 i.MX6ULL 时钟系统架构,三者是时钟树的核心组成单元,功能如下:
-
PLL(Phase Locked Loop,锁相环):频率合成核心模块,作用是对输入的低频基准时钟(外部 24MHz 晶振)进行倍频,输出高频时钟,为 CPU 内核、高速总线和外设提供高频基准源。i.MX6ULL 集成 7 路独立 PLL,例如 PLL1 专门为 ARM 内核提供高频时钟,PLL2(System PLL)固定输出 528MHz 作为系统主时钟源。
-
Prescaler(预分频器):整数分频模块,作用是将 PLL 或 PFD 输出的高频时钟,按整数比例降低频率,以匹配不同总线、外设的工作频率要求。例如 ARM_PODF、AHB_PODF、IPG_PODF 均为预分频器,分别对内核、AHB 总线、IPG 总线时钟进行分频。
-
PFD(Programmable Fractional Divider,可编程分数分频器):分数分频模块,在 PLL 输出的固定频率基础上,通过分数分频得到更多灵活的中间频率,解决整数分频无法覆盖的频率需求。i.MX6ULL 的 PLL2 和 PLL3 各集成 4 路 PFD,可输出 352MHz、396MHz 等多种频率,为 AHB、IPG、各类外设提供多样化的时钟源。
2. SOC 时钟配置的核心工作
基于 i.MX6ULL 裸机开发,完整的 SOC 时钟配置工作包含以下环节:
-
时钟源基础配置 确认外部 24MHz 主晶振与 32.768kHz RTC 晶振正常工作,以 24MHz OSC 作为系统主时钟源;可关闭未使用的 PLL 以降低功耗。
-
PLL 倍频配置
-
配置 PLL1(ARM PLL):先将 ARM 内核临时切换到 24MHz 低速 step 时钟,再配置 PLL1 倍频系数(如倍频到 1056MHz),锁定稳定后切回 PLL1 作为内核时钟源。
-
确认 PLL2(528MHz 固定)、PLL3(480MHz 固定)正常输出,作为系统外设的基准 PLL。
-
-
PFD 分数分频配置 配置 PLL2 和 PLL3 的共 8 路 PFD,根据外设需求设置分频系数,生成 396MHz、352MHz、297MHz 等中间频率时钟,供给总线和外设。
-
核心根时钟配置 配置三大系统根时钟:
-
ARM_CLK_ROOT:选择 PLL1 输出,配置 ARM_PODF 分频得到最终 CPU 主频(如 528MHz/792MHz)。
-
AHB_CLK_ROOT:选择 PLL2 的 PFD 作为时钟源,配置 AHB_PODF 分频得到 132MHz AHB 总线时钟。
-
IPG_CLK_ROOT:由 AHB 时钟经 IPG_PODF 二分频得到 66MHz,作为外设总线基准时钟。
-
-
外设时钟使能与分频 为 UART、GPIO、EPIT、GPT、LCD 等外设选择对应时钟源、配置分频系数,并开启对应外设的时钟门控。
-
时钟稳定性验证 通过读取 CCM 寄存器确认时钟切换状态,或通过定时器翻转、串口波特率校验等方式,验证各时钟频率符合设计值。
3. GIC 优先级数量
-
GIC v2 架构理论值 :通用中断控制器 GIC v2 的优先级寄存器为 8 位,理论上最多支持256 个优先级,优先级数值越小,优先级越高。
-
i.MX6ULL 实际支持 :i.MX6ULL 搭载的 Cortex-A7 内核集成 GIC v2,硬件仅实现了优先级寄存器的高 5 位(bit7~bit3),低 3 位无效,因此实际支持32 个优先级(2^5=32)。可通过 GICC_BPR 寄存器配置优先级分组,划分抢占优先级与子优先级的位宽。
4. 时钟配置代码与流程解析
4.1 时钟树核心路径梳理
以 i.MX6ULL 最常用的 528MHz 主频、132MHz AHB、66MHz IPG 配置为例,时钟流向如下:
-
ARM 时钟路径:24MHz OSC → PLL1(44 倍频→1056MHz) → ARM_PODF(2 分频) → ARM_CLK_ROOT(528MHz)
-
PFD 时钟路径:24MHz OSC → PLL2(22 倍频→528MHz 固定) → PFD2(分数分频→396MHz)
-
AHB 根时钟路径:PLL2_PFD2 → PERIPH 时钟选择器 → AHB_PODF(3 分频) → AHB_CLK_ROOT(132MHz)
-
IPG 根时钟路径:AHB_CLK_ROOT → IPG_PODF(2 分频) → IPG_CLK_ROOT(66MHz)
4.2 完整时钟配置代码
/**
* @brief 启能所有时钟
* @note 该函数将CCM(时钟控制器模块)的所有时钟使能寄存器设置为全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;
/**
* @brief 初始化系统时钟
* @details 该函数用于配置系统时钟,包括设置PLL_ARM时钟源和分频系数
*/
void clock_init(void){
unsigned int t = 0; // 定义临时变量t,用于寄存器操作
// 关闭ARM PLL
CCM->CCSR &= ~(1 << 8); // 清除CCSR寄存器的第8位,关闭ARM PLL
// 选择PLL作为时钟源
CCM->CCSR |= (1 << 2);
// 设置CCSR寄存器的第2位,选择PLL作为时钟源
// 读取PLL_ARM寄存器的当前值
t = CCM_ANALOG->PLL_ARM;
// 清除PLL_ARM的分频系数位(14-15位)
t &= ~(3 << 14);
// 设置PLL_ARM的预分频位(13位)
t |= (1 << 13);
t &= ~(0x7F << 0);
t |= (88 << 0);
CCM_ANALOG->PLL_ARM = t;
CCM.CACRR |= (1 << 0); // 设置CCM的CACRR寄存器的第0位,将PLL_ARM的输出作为系统时钟源
CCM->CCSR &= ~(1 << 2);
t = CCM_ANALOG->PFD_528;
t &= ~((0x3F << 0) | (0x3F << 8) | (0x3F << 16) | (0x3F << 24)); // 清除PFD_528的输出分频系数位(0-5,8-13,16-21,24-29位)
t &= ~((1 << 7) | (1 << 15) | (1 << 23) | (1 << 31)); // 清除PFD_528的锁标志位(7,15,23,31位)
t |= ((27 << 0) | (16 << 8) | (24 << 16) | (32 << 24));
// 设置PFD_528的输出分频系数(0-27,8-16,16-24,24-32) = 528 * 18 / 频率
CCM_ANALOG->PFD_528 = t; // 将PFD_528的输出分频系数位(0-5,8-13,16-21,24-29位)设置为27、16、24、32
t = CCM_ANALOG->PFD_480; // 读取PFD_480的当前值
t &= ~((0x3F << 0) | (0x3F << 8) | (0x3F << 16) | (0x3F << 24)); // 清除PFD_480的输出分频系数位(0-5,8-13,16-21,24-29位)
t &= ~((1 << 7) | (1 << 15) | (1 << 23) | (1 << 31)); // 清除PFD_480的锁标志位(7,15,23,31位)
t |= ((12 << 0) | (16 << 8) | (17<< 16) | (19 << 24));
// 设置PFD_480的输出分频系数(0-12,8-16,16-17,24-19) = 480 * 18 / 频率
CCM_ANALOG->PFD_480 = t; // 将PFD_480的输出分频系数位(0-5,8-13,16-21,24-29位)设置为12、16、17、19
t = CCM->CBCMR;
t &= (3 << 18);
t |= (1 << 18);
CCM->CBCMR = t;
t = CCM->CBCMR;
t &= ~(1 << 25);
t &= ~((7 << 10) | (3 << 8);
t |= ((2 << 10) | (1 << 8));
CCM->CBCDR = t;
t = CCM->CSCMR1
t &= ~(1 << 6);
t &= ~(0x3F << 0);
CCM.CSCMR1 = t;
enable_clocks();
}
4.3 配置过程关键说明
-
PLL 配置安全原则:修改 ARM 内核的 PLL 前,必须先将内核时钟切换到稳定的低速临时时钟(step_clk),避免 PLL 调整过程中频率跳变导致内核跑飞。
-
PFD 分频计算 :PLL2 的 PFD 输出频率公式为
Fout = 528MHz × 18 / FRAC,FRAC 取值范围 12\++35,可生成 271.5MHz\++792MHz 区间的任意分数频率。 -
根时钟分频规则:PODF 分频器的寄存器值 N 对应分频系数为 N+1,例如寄存器写 1 对应 2 分频,写 2 对应 3 分频。
-
时钟握手等待:切换总线时钟后,需要等待 CDHIPR 寄存器对应位清零,表示时钟切换完成,再执行后续操作,避免总线时序错误。