S3C2440的时钟可以选用晶振(XTAL),也可以使用外部时钟(EXTCLK),由系统复位时,在复位信号上升沿对引脚OM3、OM2所测的状态来确定。由于我所用的开发板这两个引脚接地,故外部晶振作为主锁相环(MPLL)和usb锁相环(UPLL)的时钟源。
含有两个锁相环MPLL、UPLL产生系统所需要的不同频率的时钟
MPLL:
为CPU产生FCLK时钟
为AHB产生HCLK时钟
为APB产生PCLK时钟
UPLL:
为usb(Host and Device)产生UCLK(48M)
FCLK,HCLK和 PCLK
FCLK是提供给ARM920T 的时钟。
HCLK 是提供给用于 ARM920T,存储器控制器,中断控制器,LCD 控制器,DMA 和 USB 主机模块的 AHB
总线的时钟。
PCLK 是提供给用于外设如WDT,IIS,I2C,PWM 定时器,MMC/SD 接口,ADC,UART,GPIO,RTC 和
SPI的APB 总线的时钟。
下图为PLL(锁相环)方框图
设置FCLK要用到PLL控制寄存器MPLLCON
例如:如果外部晶振Fin为12MHZ,设置FCLK为400MHZ,
由公式Fout = 2 × m × Fin / ( p*2^s) 此处:m =MDIV+8, p=PDIV+2, s=SDIV
可知rMPLLCON=((92<<12)|(1<<4)|1) 其中(MDIV=92, PDIV=1,SDIV=1)。
下面的这个函数是配置FCLK HCLK PCLK的比例的函数,用到时钟分频寄存器CLKDIVN
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);
}
//**************************[ UPLL ]*******************************
void ChangeUPllValue(int mdiv,int pdiv,int sdiv) //配置UPLLCON寄存器
{
rUPLLCON = (mdiv<<12) | (pdiv<<4) | sdiv;
}
void CalcBusClk(void) //计算总线频率
{
U32 val;
U8 m, p, s;
val = rMPLLCON;
m = (val >> 12) & 0xff;
p = (val >> 4) & 0x3f;
s = val & 3;
//(m+8)*FIN*2 不要超出32位数!
FCLK = ((m+8)*(FIN/100)*2)/((p+2)*(1<<s))*100; //计算FCLK频率
val = rCLKDIVN;
m = (val >> 1) & 3; //HDIVN 的值
p = val & 1; //PDIVN 的值
val = rCAMDIVN;
s = val >> 8; //CAMDIVN[8:9],为HDIVN分频改变位
switch (m) //计算HCLK频率
{
case 0:
HCLK = FCLK;
break;
case 1:
HCLK = FCLK >> 1;
break;
case 2:
if(s & 2) //见CAMDIVN寄存器HCLK4_HALF
HCLK = FCLK >> 3;
else
HCLK = FCLK >> 2;
break;
case 3:
if(s & 1) //见CAMDIVN寄存器HCLK3_HALF
HCLK = FCLK / 6;
else
HCLK = FCLK / 3;
break;
}
if(p) //计算PCLK频率
PCLK = HCLK >> 1;
else
PCLK = HCLK;
val = rUPLLCON;
m = (val >> 12) & 0xff;
p = (val >> 4) & 0x3f;
s = val & 3;
UPLL = ((m+8)*FIN)/((p+2)*(1<<s));
UCLK = (rCLKDIVN&8)?(UPLL>>1):UPLL; //计算UCLK频率
}
下图为外部时钟为晶振时的上电复位顺序