全部博文(92)
分类: 嵌入式
2010-06-15 09:25:01
s3c2440时钟文档
S3C2440 CPU默认的工作主频为12MHz或16.9344MHz,这里使用最多的是12M。使用PLL电路可以产生更高的主频供CPU及外围器件使用。
S3C2440有两个PLL:MPLL和UPLL,UPLL专用与USB设备。MPLL用于CPU及其他外围器件。
通过MPLL会产生三个部分的时钟频率:FCLK、HCLK、PLCK。FCLK用于CPU核,HCLK用于AHB总线的设备(比如SDRAM),PCLK用于APB总线的设备(比如UART)。从时钟结构图中可以查看到使用不同时钟频率的硬件。
下面介绍MPLL的启动流程:
1、上电几毫秒后,晶振输出稳定,FCLK=晶振频率,nRESET信号恢复高电平后,CPU开始执行指令。
2、我们可以在程序开头启动MPLL,在设置MPLL的几个寄存器后,需要等待一段时间(Lock Time),MPLL的输出才稳定。在这段时间(Lock Time)内,FCLK停振,CPU停止工作。Lock Time的长短由寄存器LOCKTIME设定。
3、Lock Time之后,MPLL输出正常,CPU工作在新的FCLK下。
设置S3c2440的时钟频率就是设置MPLL的几个寄存器:
1、LOCKTIME:设为0x00ffffff
前面说过,MPLL启动后需要等待一段时间(Lock Time),使得其输出稳定。位[23:12]用于UPLL,位[11:0]用于MPLL。使用确省值0x00ffffff即可。
2、CLKDIVN:用来设置FCLK:HCLK:PCLK的比例关系,默认为1:1:1
这里值设为0x05,即FCLK:HCLK:PCLK=1:4:8
3、MPLLCON:设为(0x7f << 12)|(0x02 << 4)|(0x01),即0x7f0021
对于MPLLCON寄存器,[19:12]为MDIV,[9:4]为PDIV,[1:0]为SDIV。有如下计算公式:
MPLL(FCLK) = (m * Fin)/(p * 2^s)
其中: m = MDIV + 8, p = PDIV + 2
Fin 即默认输入的时钟频率12MHz。MPLLCON设为0x7f0021,可以计算出FCLK=400MHz,再由CLKDIVN的设置可知:HCLK=100MHz,PCLK=50MHz。
到这里我们应该彻底弄清楚了程序中经常出现的几个CLK:
Fin,MPLL,UPLL,FCLK,HCLK,PCLK.
Fin指CPU外围接的晶振本身的频率,通常为12MHz。
MPLL和UPLL分别指的是用于供整机系统的PLL和专用于USB的UPLL。
FCLK = MPLL = (m * Fin)/(p + 2^s);
HCLK,PCLK受CLKDIVN寄存器的影响,即当FCLK确定后,CLKDIVN决定了HCLK和PCLK
在ADS中配置时钟:
Main 中输入要设置的内核时钟(FCLK)和分频比(1:4:8)
int
{
SetSysFclk(FCLK_400M);
ChangeClockDivider(2, 1);
…..
}
2440lib.c文件中定义时钟设置函数:
void SetSysFclk(int val)
{
rMPLLCON = val;
}
void ChangeClockDivider(int hdivn,int pdivn)
{
// hdivn,pdivn FCLK:HCLK:PCLK
// 0,0 1:1:1
// 0,1 1:1:2
// 1,0 1:2:2
// 1,1 1:2:4
// 2,0 1:4:4
// 2,1 1:4:8
// 3,0 1:3:3
// 3,1 1:3:6
rCLKDIVN = (hdivn<<1) | pdivn;
if (hdivn == 2)
rCAMDIVN = (rCAMDIVN & ~(3<<8)) | (1<<9);
if (hdivn == 3)
rCAMDIVN = (rCAMDIVN & ~(3<<8)) | (1<<8);
}
其实简化了写就是这样的:
void clock_init(void)
{
rLOCKTIME = 0xFFFFFF;
rCLKDIVN = 0x5;
rMPLLCON = 0x7f0021;
}
U-boot中设置时钟:
board/TX2440/TX2440.c中的board_init函数
/* S3C2440: Mpll,Upll = (2*m * Fin) / (p * 2^s)
* m = M (the value for divider M)+ 8, p = P (the value for divider P) + 2
*/
#define S3C2440_MPLL_400MHZ ((0x7f<<12)|(0x02<<4)|(0x01))
#define S3C2440_UPLL_48MHZ ((0x38<<12)|(0x02<<4)|(0x02))
#define S3C2440_CLKDIV 0x05 /* FCLK:HCLK:PCLK = 1:4:8 */
int board_init (void)
{
S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
………
/* FCLK:HCLK:PCLK = 1:4:8 */
clk_power->CLKDIVN = S3C2440_CLKDIV;
/* 如果HDIVN不为0,CPU总线模式从Fast Bus Mode 变为Asynchronous Bus Mode */
__asm__( "mrc p15, 0, r1, c1, c0, 0\n" /* read ctrl register */
"orr r1, r1, #0xc0000000\n" /* Asynchronous */
"mcr p15, 0, r1, c1, c0, 0\n" /* write ctrl register */
:::"r1"
);
/* to reduce PLL lock time, adjust the LOCKTIME register */
clk_power->LOCKTIME = 0xFFFFFF;
/* configure MPLL =FCLK=400MHZ*/
clk_power->MPLLCON = S3C2440_MPLL_400MHZ;
/* some delay between MPLL and UPLL */
delay (4000);
/* configure UPLL48MHZ FOR USB*/
clk_power->UPLLCON = S3C2440_UPLL_48MHZ;
/* some delay between MPLL and UPLL */
delay (8000);
…….
return 0;
}