外部参考晶振固定 24MHz ,所有 PLL 都基于这个 24MHz 倍频;CCM 模块管理全部时钟选择、分频、门控;内核主频来自 PLL1(ARM_PLL)
锁相环总表:
| PLL 名称 | 别名 | 参考源 | 特性 | 用途 |
|---|---|---|---|---|
| PLL1 | ARM_PLL | 24MHz | 可编程倍频 | Cortex-A7 内核主频(CPU 核心时钟) |
| PLL2 | 528_PLL | 24MHz | 固定 22 倍 → 528MHz,不可改 | 系统总线、DDR、NAND/NOR;自带 4 路 PFD 分频输出(PFD0~PFD3) |
| PLL3 | USB1_PLL | 24MHz | 固定 20 倍 → 480MHz | USB1 PHY |
| PLL4 | AUDIO_PLL | 24MHz | 可编程 | SAI/I2S 音频外设 |
| PLL5 | VIDEO_PLL | 24MHz | 可编程 | RGB LCD 显示 |
| PLL6 | ENET_PLL | 24MHz | 固定倍频输出 500MHz | 以太网 ETH,生成 125MHz 等网络时钟 |
| PLL7 | USB2_PLL | 24MHz | 固定 20 倍 →480MHz | USB2 PHY |
PLL2 的 PFD(PLL Fractional Divider,小数分频):528MHz 输入分出 4 路常用时钟:PFD0=352M、PFD1=594M、PFD2=396M、PFD3=297M,是 AHB/IPG 外设总线的常用时钟源。
裸机配置 PLL1 标准流程(必须按顺序,防止死机)
-
先切临时时钟源:把内核时钟临时切到 24MHz 外部晶振,不能直接改正在使用的 PLL
-
配置
CCM_ANALOG_PLL_ARM:设置倍频 N,使能 PLL -
等待 PLL 锁定(读锁定标志位)
-
把内核时钟切回 PLL1 输出
-
配置 AHB、IPG、PERCLK 总线分频
-
打开外设时钟门控 CCGR
//1. CPU先切到24M晶振
CCM->CCSR &= ~(1 << 8);
CCM->CCSR |= (1 << 2);unsigned int temp = CCM_ANALOG->PLL_ARM;
temp &= ~(0x3f << 0);
temp |= (88 << 0);
temp &= ~(0x3 << 14);
temp |= (0x1 << 13);
CCM_ANALOG->PLL_ARM = temp;// 等待PLL锁定!
while( !(CCM_ANALOG->PLL_ARM & (1U << 31)) );//设置ARM后分频,得到528M
CCM->CACRR &= ~(0x7 << 0);
CCM->CACRR |= (0X1 << 0);//切回PLL1给CPU
CCM->CCSR &= ~(1 << 2);
配置完成PLL1后继续对系统主要锁相环PLL2、PLL3及其下位分频器进行配置。
temp = CCM_ANALOG->PFD_528;
temp &= ~(0x3f << 0);
temp |= (27 << 0); //PLL2_PFD0 = 352MHz
temp &= ~(0x3f << 8);
temp |= (16 << 8); //PLL2_PFD1 = 594MHz
temp &= ~(0x3f << 16);
temp |= (24 << 16); //PLL2_PFD2 = 396MHz
temp &= ~(0x3f << 24);
temp |= (32 << 24); //PLL2_PFD3 = 297MHz
CCM_ANALOG->PFD_528 = temp; //设置PLL2的下位分频器PLL2_PFD0-PFD3
temp = CCM_ANALOG->PFD_480;
temp &= ~(0x3f << 0);
temp |= (12 << 0); //PLL3_PFD0 =720MHz
temp &= ~(0x3f << 8);
temp |= (16 << 8); //PLL3_PFD1 = 540MHz
temp &= ~(0x3f << 16);
temp |= (17 << 16); //PLL3_PFD2 = 508.23MHz
temp &= ~(0x3f << 24);
temp |= (19 << 24); //PLL3_PFD3 = 454.7MHz
CCM_ANALOG->PFD_480 = temp;
完成时钟源的锁相环配置后,对外设总线的时钟选择和分频进行配置
// 【PRE_PERIPH_CLK = PLL2_PFD2 = 396MHz】
CCM->CBCMR &= ~(3 << 18);
CCM->CBCMR |= (2 << 18);
CCM->CBCDR &= ~(3 << 8); //IPG 2分频
CCM->CBCDR |= (1 << 8);
CCM->CBCDR &= ~(7<< 10); //AHB 3分频
CCM->CBCDR |= (2 << 10);
CCM->CBCDR &= ~(1 << 25); //PERIPH_CLK来源PRE_PERIPH_CLK
while(CCM->CDHIPR & (1<<5)); //等待时钟切换完成
CCM->CSCMR1 &= ~(1 << 6); //PERCLK源选择IPGCLK
CCM->CSCMR1 &= ~(7 << 0); //PERCLK 1分频
enable_ccm(); //开启所有时钟的门控开关