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 寄存器对应位清零,表示时钟切换完成,再执行后续操作,避免总线时序错误。