
1. PLL、Prescaler、PFD 的作用结合 i.MX6ULL 时钟系统架构三者是时钟树的核心组成单元功能如下PLLPhase Locked Loop锁相环频率合成核心模块作用是对输入的低频基准时钟外部 24MHz 晶振进行倍频输出高频时钟为 CPU 内核、高速总线和外设提供高频基准源。i.MX6ULL 集成 7 路独立 PLL例如 PLL1 专门为 ARM 内核提供高频时钟PLL2System PLL固定输出 528MHz 作为系统主时钟源。Prescaler预分频器整数分频模块作用是将 PLL 或 PFD 输出的高频时钟按整数比例降低频率以匹配不同总线、外设的工作频率要求。例如 ARM_PODF、AHB_PODF、IPG_PODF 均为预分频器分别对内核、AHB 总线、IPG 总线时钟进行分频。PFDProgrammable 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 倍频配置配置 PLL1ARM PLL先将 ARM 内核临时切换到 24MHz 低速 step 时钟再配置 PLL1 倍频系数如倍频到 1056MHz锁定稳定后切回 PLL1 作为内核时钟源。确认 PLL2528MHz 固定、PLL3480MHz 固定正常输出作为系统外设的基准 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^532。可通过 GICC_BPR 寄存器配置优先级分组划分抢占优先级与子优先级的位宽。4. 时钟配置代码与流程解析4.1 时钟树核心路径梳理以 i.MX6ULL 最常用的 528MHz 主频、132MHz AHB、66MHz IPG 配置为例时钟流向如下ARM 时钟路径24MHz OSC → PLL144 倍频→1056MHz → ARM_PODF2 分频 → ARM_CLK_ROOT528MHzPFD 时钟路径24MHz OSC → PLL222 倍频→528MHz 固定 → PFD2分数分频→396MHzAHB 根时钟路径PLL2_PFD2 → PERIPH 时钟选择器 → AHB_PODF3 分频 → AHB_CLK_ROOT132MHzIPG 根时钟路径AHB_CLK_ROOT → IPG_PODF2 分频 → IPG_CLK_ROOT66MHz4.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 / FRACFRAC 取值范围 12\35可生成 271.5MHz\792MHz 区间的任意分数频率。根时钟分频规则PODF 分频器的寄存器值 N 对应分频系数为 N1例如寄存器写 1 对应 2 分频写 2 对应 3 分频。时钟握手等待切换总线时钟后需要等待 CDHIPR 寄存器对应位清零表示时钟切换完成再执行后续操作避免总线时序错误。