TQ210——时钟系统
1、时钟域
一般来讲, MCU 的主时钟来源主要是外部晶振或外部时钟,比较常见的是 外 部晶振。一般情况,系统内所使用的时钟都是高频率的时钟,外部晶振一般达不到那么高的频率,所以一般使用锁相环电路(PLL)进行倍频,而TQ210 正是通过外接24MHz 的外部晶振,通过一定的倍频达到更高的频率。
S5PV210内部包含三个时钟域:
MSYS(mainsystem):主时钟域【Cortex-A8处理器、DRAM控制器(DMC0& DMC1)、3D、IROM& IRAM、INTC、SEPRI等。最高工作频率200MHz】
DSYS(displaysystem):显示时钟域【显示相关的模块,如FIMC、FIMD、JPEG、多媒体Ips。最高工作频率166MHz】
PSYS(peripheralsystem):外设时钟域【安全模块、IO外设和低功耗音频播放模块等。最高工作频率133MHz】
2、时钟域与PLL
S5PV210内部包含4个PLL。
Cortex-A8内核(ARMCLK)和MSYS时钟域(HCLK_MSYS、PCLK_MSYS)使用APLL;
DSYS和PSYS时钟域(HCLK_DSYS、HCLK_PSYS、PCLK_DSYS、PCLK_PSYS)、外设时钟(SPI、UART、Timer等)使用MPLL和EPLL;
VideoClock使用VPLL
上面是各时钟关系图和三星公司给出了一些经典的频率参数。
上图是S5PV210时钟发生器,三星公司给出了一些经典参数。
分析一:
目标时钟的值取决于三个因素:MUX、时钟源频率、Divider(分频器)
MUX为多路时钟分选器,使用MUX可以为一个时钟选择不同的时钟源
时钟源一般来自于上级时钟系统或PLL输出或直接来自于外部晶振时钟
源时钟可以经过MUX直接连接到目标时钟系统,也可以途经Divider分做分频后再输出到下一级时钟系统
分析二:
一般在bootloader的前部会有时钟初始化代码,该阶段会对系统主要时钟进行设置,包括ARMCLK、HCLK_PSYS、PCLK_PSYS等。
外设时钟配置的常规思路:
1、分析目标外设模块要使用的时钟
2、分析该时钟如何由源时钟经MUX、Divider而得到。
3、根据需要设置寄存器位完成时钟配置。
【时钟分频配置】:
ARMCLK = 1000MHz= MOUT_MSYS / (APLL_RATIO + 1),经过在第四和第五步的设置后,MOUT_MSYS会被设置为1000MHz,所以APLL_RATIO=0即可
SCLKA2M=200MHz=SCLKAPLL/ (A2M_RATIO + 1),由于SCLKAPLL=1000MHz,所以A2M_RATIO=4。
HCLK_MSYS=200MHz=ARMCLK/ (HCLK_MSYS_RATIO + 1),所以HCLK_MSYS_RATIO=4
PCLK_MSYS=100MHz=HCLK_MSYS/ (PCLK_MSYS_RATIO + 1),所以PCLK_MSYS_RATIO=1
HCLK_DSYS=166MHz=MOUT_DSYS/ (HCLK_DSYS_RATIO + 1), 经过在第四和第五步的设置后,MOUT_DSYS=667MHz,所以HCLK_DSYS_RATIO=3
PCLK_DSYS=83MHz=HCLK_DSYS/ (PCLK_DSYS_RATIO + 1),所以PCLK_DSYS_RATIO=1
HCLK_PSYS=133Mhz=MOUT_PSYS/ (HCLK_PSYS_RATIO + 1),经过在第四和第五步的设置后,MOUT_PSYS=667MHz所以HCLK_PSYS_RATIO=4
PCLK_PSYS=66Mhz=HCLK_PSYS/ (PCLK_PSYS_RATIO + 1),所以HCLK_PSYS_RATIO=1
3、时钟配置
(1)设置系统锁相环(PLL)的锁定值 // 参考 PLL_LOCK 寄存器
(2)设置PLL的PMS值,并使能PLL //参考 PLL_CON寄存器
(3)等待PLL锁定(即等待 PLL 输出稳定的频率) // 读取 PLL_CON 寄存器的 LOCKED 位来判断【设置PLL后,时钟从Fin提升到目标频率时,需要一定的时间,即锁定时间】
(4)设置系统时钟源:选择PLL,而不是外部晶振 // 参考 CLK_SRC0 寄存器
(5)设置其他模块的时钟源 // 参考 CLK_SRC1~CLK_SRC6寄存器
(6)设置系统时钟分频值 // 参考 CLK_DIV0寄存器
(7)设置其他模块的时钟分频值 // 参考 CLK_DIV1~CLK_DIC7
4、寄存器
(1)主要的MUX
最终的时钟源一般均来自于外部晶振直接输出(低频、低功耗),或PLL输出(高频、高性能)由相应的MUX开关来决定使用哪个。
PLL输出频率的计算公式如下:
对于APLL:
FOUT = MDIV X FIN / (PDIV × 2exp(SDIV-1))
对于MPLL、EPLL、VPLL:
FOUT = MDIV X FIN / (PDIV X2exp(SDIV))
(2)APLL配置
ALPP_CON0负责设置APLL,FINPLL=24MHz,经过APLL后,我们将输出FOUT=1000Mhz的时钟频率,FOUT的计算公式如下:FOUT=MDIV*FIN/(PDIV*2^(SDIV-1)) = 1000 MHz 由于FIN=24MHz,FOUT=1000MHz,我们可以这样取值:MDIV= 0x7d,PDIV=0x3,SDIV=1。这3个值并不是固定死的,只要能使FOUT=1000Mhz,任意搭配都是可以的。
(3)MPLL
MPLL_CON寄存器负责设置MPLL,经过MPLL后,我们将输出FOUT=667Mhz的时钟频率,FOUT的计算公式如下:FOUT=MDIV*FIN/(PDIV*2^SDIV) = 667 MHz 由于FIN=24MHz,FOUT=667MHz,我们可以这样取值:MDIV=0x29B,PDIV= 0xC,SDIV=1。这3个值并不是固定死的,只要能使FOUT=667Mhz,任意搭配都是可以的。
(4)分频器
从低位开始分析:
① MOUT_MSYS = FOUTapll = 1000MHz 而 ARMCLK 根据经典值为 1000,所以 APLL_RATIO = 0;
② SLKA2M = HCLK_MSYS = 200MHz , 而 SCLKAPLL = 1000 ,所 以A2M_RATIO = 4;
③ HCLK_MSYS = 200MHz,而 ARMCLK = 1000,所以 HCLK_MSYS_RATIO= 4;
④ MOUT_DSY 来自 SCLKmpll 即 FOUTmpll = 667MHz,而 HCLK_DSYS按照经典设置应为 166MHz 所以, HCLK_DSY_RATIO 约为 3;
⑤ 经 典 值 设 置 可 知 PCLK_DSYS =166MHz,HCLK_DSYS=83MHz,故 PCLK_DSYS_RATIO = 1;
⑥ MOUT_PSYS 与 MOUT_DSYS 的来源是一样的,故也是FOUTmpll = 667MHz,而 HCLK_PSYS = 133,故 HCLK_PSYS_RATIO = 4;
⑦ 由经 典 值 设 置 可 知 PCLK_PSYS =66MHz,HCLK_PSYS=133MHz,故 PCLK_PSYS_RATIO = 1;
(5)模块时钟门控
为了支持移动设备的低功耗需求,S5PV210的时钟模块提供了极精细的时钟开关控制,即ClockGating Control。
有两类ClockGating寄存器,CLK_GATE_IPx和CLK_GATE_BOLCK,这两者之间是逻辑与的关系,即对于一个具体模块,只有在两类门控寄存器内其时钟都被允许的情况下,该模块的时钟才能被最终开启。两类寄存器中只要有一处被禁止则最终的模块时钟是禁止的。
(6)设置各种时钟开关
5、时钟初始化
.global _start
_start:bl main /* 跳转到C函数去执行*/
halt:b halt
#ifndef CLOCK_H_
#define CLOCK_H_void clock_init();#endif
#include"clock.h"#defineAPLL_LOCK *((volatile u32*)0xE0100000)
#defineMPLL_LOCK *((volatile u32*)0xE0100008)
#defineEPLL_LOCK *((volatile u32*)0xE0100010)
#defineVPLL_LOCK *((volatile u32*)0xE0100020)#defineAPLL_CON0 *((volatile u32*)0xE0100100)
#define MPLL_CON *((volatile u32 *)0xE0100108)
#defineEPLL_CON0 *((volatile u32*)0xE0100110)
#defineEPLL_CON1 *((volatile u32*)0xE0100114)
#define VPLL_CON *((volatile u32 *)0xE0100120)#define CLK_SRC0 *((volatile u32*)0xE0100200)
#define CLK_SRC1 *((volatile u32*)0xE0100204)
#define CLK_SRC2 *((volatile u32*)0xE0100208)
#define CLK_SRC3 *((volatile u32*)0xE010020C)
#define CLK_SRC4 *((volatile u32*)0xE0100210)
#define CLK_SRC5 *((volatile u32*)0xE0100214)
#define CLK_SRC6 *((volatile u32*)0xE0100218)#define CLK_DIV0 *((volatile u32 *)0xE0100300)
#define CLK_DIV1 *((volatile u32 *)0xE0100304)
#define CLK_DIV2 *((volatile u32 *)0xE0100308)
#define CLK_DIV3 *((volatile u32 *)0xE010030C)
#define CLK_DIV4 *((volatile u32 *)0xE0100310)
#define CLK_DIV5 *((volatile u32 *)0xE0100314)
#define CLK_DIV6 *((volatile u32 *)0xE0100318)
#define CLK_DIV7 *((volatile u32 *)0xE010031C)/* 时钟初始化*/
void clock_init()
{/* 1.设置PLL锁定值*/APLL_LOCK = 0xFFFF;MPLL_LOCK = 0xFFFF;EPLL_LOCK = 0xFFFF;VPLL_LOCK = 0xFFFF;/* 2.设置PLL的PMS值(使用芯片手册推荐的值),并使能PLL*//* P M S EN */APLL_CON0 = (3 << 8) | (125 << 16) | (1 << 0) | (1 << 31); /*FOUT_APLL = 1000MHz */MPLL_CON = (12 << 8) | (667 << 16) | (1 << 0) | (1 << 31); /* FOUT_MPLL = 667MHz */EPLL_CON0 = (3 << 8) | (48 << 16) | (2 << 0) | (1 << 31); /* FOUT_EPLL = 96MHz */VPLL_CON = (6 << 8) | (108 << 16) | (3 << 0) | (1 << 31); /*FOUT_VPLL = 54MHz *//* 3.等待PLL锁定*/while (!(APLL_CON0 & (1 <<29)));while (!(MPLL_CON & (1 << 29)));while (!(EPLL_CON0 & (1 <<29)));while (!(VPLL_CON & (1 << 29)));/*** 4.设置系统时钟源,选择PLL为时钟输出*//* MOUT_MSYS = SCLKAPLL = FOUT_APLL =1000MHz** MOUT_DSYS = SCLKMPLL = FOUT_MPLL =667MHz** MOUT_PSYS = SCLKMPLL = FOUT_MPLL =667MHz** ONENAND = HCLK_PSYS*/CLK_SRC0 = (1 << 0) | (1 <<4) | (1 << 8) | (1 << 12);/* 4.设置其他模块的时钟源*//* 6.设置系统时钟分频值*/CLK_DIV0 = (0 << 0) | /* APLL_RATIO = 0, freq(ARMCLK) = MOUT_MSYS /(APLL_RATIO + 1) = 1000MHz */(4 << 4) | /*A2M_RATIO = 4, freq(A2M) = SCLKAPLL / (A2M_RATIO + 1) = 200MHz */(4 << 8) | /*HCLK_MSYS_RATIO = 4, freq(HCLK_MSYS) = ARMCLK / (HCLK_MSYS_RATIO + 1) = 200MHz*/(1 << 12) | /* PCLK_MSYS_RATIO = 1, freq(PCLK_MSYS) =HCLK_MSYS / (PCLK_MSYS_RATIO + 1) = 100MHz */(3 << 16) | /*HCLK_DSYS_RATIO = 3, freq(HCLK_DSYS) = MOUT_DSYS / (HCLK_DSYS_RATIO + 1) =166MHz */(1 << 20) | /*PCLK_DSYS_RATIO = 1, freq(PCLK_DSYS) = HCLK_DSYS / (PCLK_DSYS_RATIO + 1) =83MHz */(4 << 24) | /* HCLK_PSYS_RATIO = 4, freq(HCLK_PSYS) =MOUT_PSYS / (HCLK_PSYS_RATIO + 1) = 133MHz */(1 << 28); /* PCLK_PSYS_RATIO = 1, freq(PCLK_PSYS) =HCLK_PSYS / (PCLK_PSYS_RATIO + 1) = 66MHz *//* 7.设置其他模块的时钟分频值*/
}
#include"clock.h"#define GPC0CON *((volatile unsigned int *)0xE0200060)
#define GPC0DAT *((volatile unsigned int *)0xE0200064)void delay(volatile unsigned int t)
{volatile unsigned int t2 = 0xFFFF;while (t--)for (; t2; t2--);
}int main()
{int toggle = 0;GPC0CON &= ~(0xFF << 12);GPC0CON |= 0x11 << 12; // 配置GPC0_3和GPC0_4为输出clock_init(); // 时钟初始化while (1){GPC0DAT &= ~(0x3 << 3); // 熄灭LED1和LED2if (toggle)GPC0DAT |= 1 << 3; // 点亮LED1elseGPC0DAT |= 1 << 4; // 点亮LED2toggle = !toggle;delay(0x50000);}return 0;
}