时钟概念:
★时钟脉冲:一个按一定电压幅度,一定时间间隔连续发出的脉冲信号;
★时钟频率:在单位时间(如:1秒)内产生的时钟秒冲数;
作用:
时钟信号是时序逻辑的基础
时钟的产生-晶振
晶振:晶体振荡器,是用石英晶体精密切割做成。
时钟产生-PLL
PLL:(锁相环)合成器=外部晶体+PLL电路。
S3C2440的主时钟晶振来自外部晶振(XTIPLL),或者是外部时钟(EXTCLK)。时钟生成器包含了一个振荡器(振荡放大器),其连接外部晶振,可以产生需要的高频,通过引脚OM[3:2]来决定时钟源时Crystal还是EXTCLK.
S3C2440有两个PLL:(1)MPLL和(2)UPLL,
UPLL专用于USB设备。
MPLL 用于CPU及其他外围器件。
通过MPLL会产生三个部分的时钟频率:
FCLK:用于CPU核;
HCLK:用于AHB(常用于高速外设)总线的设备,比如:SDRAM;
PCLK:用于APB(常用于低速外设)总线的设备,比如:UART.
时钟启动流程:
1.上电几毫秒后,外部晶振输出稳定,FCLK=外部晶振频率(12MHZ),nRESET
信号恢复高电平后,CPU开始执行命令。
2.在设置MPLL的几个寄存器后,需要等待一段时间(Lock Time),MPLL的输出才稳定。在这段时间(Lock Time)内,FCLK停振,CPU停止工作。
Lock Time的长短由寄存器LOCKTIME设定。
3.Lock Time之后,MPLL输出正常,CPU工作在新的FCLK(如:400MHZ)下。
设置S3C2440的时钟频率就是设置相关的几个寄存器:
CLKDIVN
寄存器用于设置FCLK、HCLK、PCLK三者的比例
★ HDIVN:位[2:1],用来设置HCLK与FCLK比例关系
★ PDIVN:位[0],用来设置PCLK与HCLK比例关系
例如:
FCLK:HCLK:PCLK=4:2:1
FCLK=400MHZ(主频)
HCLK=200M
PCLK=100M
void Set_Clk(void)
{
int i;
U8 key;
U32 mpll_val = 0 ;
i = 2 ;
switch ( i ) {
case 0: // 200
key = 12;
mpll_val = ( 92<< 12)|( 4<< 4)|( 1);
break;
case 1: // 300
key = 13;
mpll_val = ( 67<< 12)|( 1<< 4)|( 1);
break;
case 2: // 400
key = 14;
mpll_val = ( 92<< 12)|( 1<< 4)|( 1);
break; // FCLK=2*(92+8)*(12000000)/(3+2^1)=400000000=400MHz
case 3: // 440!!!
key = 14;
mpll_val = ( 102<< 12)|( 1<< 4)|( 1);
break;
default:
key = 14;
mpll_val = ( 92<< 12)|( 1<< 4)|( 1);
break;
}
ChangeMPllValue((mpll_val>> 12)& 0xff, (mpll_val>> 4)& 0x3f, mpll_val& 3); // 设置rMPLLCON得到FCLK
ChangeClockDivider(key, 12); / / 经过 CLKDIVE设置 ,确定FCLK、HCLK、PCLK三者之间的关系
}
int i;
U8 key;
U32 mpll_val = 0 ;
i = 2 ;
switch ( i ) {
case 0: // 200
key = 12;
mpll_val = ( 92<< 12)|( 4<< 4)|( 1);
break;
case 1: // 300
key = 13;
mpll_val = ( 67<< 12)|( 1<< 4)|( 1);
break;
case 2: // 400
key = 14;
mpll_val = ( 92<< 12)|( 1<< 4)|( 1);
break; // FCLK=2*(92+8)*(12000000)/(3+2^1)=400000000=400MHz
case 3: // 440!!!
key = 14;
mpll_val = ( 102<< 12)|( 1<< 4)|( 1);
break;
default:
key = 14;
mpll_val = ( 92<< 12)|( 1<< 4)|( 1);
break;
}
ChangeMPllValue((mpll_val>> 12)& 0xff, (mpll_val>> 4)& 0x3f, mpll_val& 3); // 设置rMPLLCON得到FCLK
ChangeClockDivider(key, 12); / / 经过 CLKDIVE设置 ,确定FCLK、HCLK、PCLK三者之间的关系
}
void ChangeClockDivider(
int hdivn_val,
int pdivn_val)
{
int hdivn= 2, pdivn= 0;
// hdivn_val (FCLK:HCLK)ratio hdivn
// 11 1:1 (0)
// 12 2:1 (1)
// 13 3:1 (3)
// 14 4:1 (2)
// pdivn_val (HCLK:PCLK)ratio pdivn
// 11 1:1 (0)
// 12 2:1 (1)
switch(hdivn_val) {
case 11: hdivn= 0; break;
case 12: hdivn= 1; break;
case 13:
case 16: hdivn= 3; break;
case 14:
case 18: hdivn= 2; break;
}
switch(pdivn_val) {
case 11: pdivn= 0; break;
case 12: pdivn= 1; break;
}
// Uart_Printf("Clock division change [hdiv:%x, pdiv:%x]\n", hdivn, pdivn);
rCLKDIVN = (hdivn<< 1) | pdivn; PCLK HCLK 分频
switch(hdivn_val) { //摄像头时钟分频
case 16: // when 1, HCLK=FCLK/8.
rCAMDIVN = (rCAMDIVN & ~( 3<< 8)) | ( 1<< 8);
break;
case 18: // when 1, HCLK=FCLK/6.
rCAMDIVN = (rCAMDIVN & ~( 3<< 8)) | ( 1<< 9);
break;
}
if(hdivn!= 0)
MMU_SetAsyncBusMode();
else
MMU_SetFastBusMode();
{
int hdivn= 2, pdivn= 0;
// hdivn_val (FCLK:HCLK)ratio hdivn
// 11 1:1 (0)
// 12 2:1 (1)
// 13 3:1 (3)
// 14 4:1 (2)
// pdivn_val (HCLK:PCLK)ratio pdivn
// 11 1:1 (0)
// 12 2:1 (1)
switch(hdivn_val) {
case 11: hdivn= 0; break;
case 12: hdivn= 1; break;
case 13:
case 16: hdivn= 3; break;
case 14:
case 18: hdivn= 2; break;
}
switch(pdivn_val) {
case 11: pdivn= 0; break;
case 12: pdivn= 1; break;
}
// Uart_Printf("Clock division change [hdiv:%x, pdiv:%x]\n", hdivn, pdivn);
rCLKDIVN = (hdivn<< 1) | pdivn; PCLK HCLK 分频
switch(hdivn_val) { //摄像头时钟分频
case 16: // when 1, HCLK=FCLK/8.
rCAMDIVN = (rCAMDIVN & ~( 3<< 8)) | ( 1<< 8);
break;
case 18: // when 1, HCLK=FCLK/6.
rCAMDIVN = (rCAMDIVN & ~( 3<< 8)) | ( 1<< 9);
break;
}
if(hdivn!= 0)
MMU_SetAsyncBusMode();
else
MMU_SetFastBusMode();
}
ARM920T有三种时钟模式:FastBus(快总线模式),synchronous(同步模式), asynchronous(异步模式)
FastBus(快总线模式)该模式将时钟BCLK作为时钟GCLK的源,时钟FCLK被忽略。主要用于带有高速存储器的系统。
synchronous(同步模式)
该模式主要用于带有低速存储器的系统。时钟BCLK和时钟FCLK作为时钟GCLK的源,BCLK用于控制AMBA存储接口,FCLK用于控制内部的ARM9TDMI处理器核和任何cache缓存的操作。 FCLK的频率必须比BCLK高且是其整数陪,且在FCLK是高电平时BCLK才跳变。
asynchronous(异步模式)
该模式主要用于带有低速存储器的系统。时钟BCLK和时钟FCLK作为时钟GCLK的源,BCLK用于控制AMBA存储接口,FCLK用于控制内部的ARM9TDMI处理器核和任何cache缓存的操作。FCLK的频率只需比BCLK高。
static
void cal_cpu_bus_clk(
void) //
cal =
“calculator”,计算器的简写
{ //这个函数用来 计算cpu总线时钟
static U32 cpu_freq;
static U32 UPLL;
U32 val;
U8 m, p, s;
val = rMPLLCON; //将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=400M FIN=12000000
val = rCLKDIVN; //将rCLKDIVN拆开
m = (val>> 1)& 3;
p = val& 1;
val = rCAMDIVN;
s = val>> 8;
switch (m) {
case 0:
HCLK = FCLK;
break;
case 1:
HCLK = FCLK>> 1;
break;
case 2:
if(s& 2)
HCLK = FCLK>> 3;
else
HCLK = FCLK>> 2;
break;
case 3:
if(s& 1)
HCLK = FCLK/ 6;
else
HCLK = FCLK/ 3;
break;
}
if(p)
PCLK = HCLK>> 1;
else
PCLK = HCLK;
if(s& 0x10)
cpu_freq = HCLK;
else
cpu_freq = FCLK;
val = rUPLLCON; / /rUPLLCON内存的值为0x00038022, 求出UPLL的值为48MHz;时钟分频控制寄存器CLKDIVN[3]=0时UCLK=UPLL
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; USBCLK的值必须是48MHz
Uart_Printf( " \nFCLK:%dMHz,HCLK:%dMHz,PCLK=%dMHZ\n ",FCLK/ 1000/ 1000,HCLK/ 1000/ 1000,PCLK/ 1000/ 1000);
}
/
{ //这个函数用来 计算cpu总线时钟
static U32 cpu_freq;
static U32 UPLL;
U32 val;
U8 m, p, s;
val = rMPLLCON; //将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=400M FIN=12000000
val = rCLKDIVN; //将rCLKDIVN拆开
m = (val>> 1)& 3;
p = val& 1;
val = rCAMDIVN;
s = val>> 8;
switch (m) {
case 0:
HCLK = FCLK;
break;
case 1:
HCLK = FCLK>> 1;
break;
case 2:
if(s& 2)
HCLK = FCLK>> 3;
else
HCLK = FCLK>> 2;
break;
case 3:
if(s& 1)
HCLK = FCLK/ 6;
else
HCLK = FCLK/ 3;
break;
}
if(p)
PCLK = HCLK>> 1;
else
PCLK = HCLK;
if(s& 0x10)
cpu_freq = HCLK;
else
cpu_freq = FCLK;
val = rUPLLCON; / /rUPLLCON内存的值为0x00038022, 求出UPLL的值为48MHz;时钟分频控制寄存器CLKDIVN[3]=0时UCLK=UPLL
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; USBCLK的值必须是48MHz
Uart_Printf( " \nFCLK:%dMHz,HCLK:%dMHz,PCLK=%dMHZ\n ",FCLK/ 1000/ 1000,HCLK/ 1000/ 1000,PCLK/ 1000/ 1000);
}
/
定时器
频率
计数值
void Timer0_init(
void)
{
rTCFG0 = 49; // pclk/(49+1)
rTCFG1 = 0x03; // 16分频=62500HZ
// 定时器频率 = 1M /(49+1)/16=62500HZ
rTCNTB0 = 62500/ 2; // TCNTB0[15:0]= 计数值
rTCMPB0 = 0; // 比较值
rTCON |=( 1<< 1); // 将 计数值装入 TCNTB0、TCMPB0
rTCON = 0x09; // 1001 自动 重载,启动。
ClearPending(BIT_TIMER0); // 清除SRCPND、INTPND 此处课省略
/* 当达到0.5秒时,执行中断函数IRQ_Timer0_Handle */
pISR_TIMER0 = (U32)IRQ_Timer0_Handle; // 中断向量 = 中断函数
EnableIrq(BIT_TIMER0); // 手动打 开屏蔽 INTMSK
}
static void __irq IRQ_Timer0_Handle( void)
{
ClearPending(BIT_TIMER0); // 清中断
Led1_run();
}
{
rTCFG0 = 49; // pclk/(49+1)
rTCFG1 = 0x03; // 16分频=62500HZ
// 定时器频率 = 1M /(49+1)/16=62500HZ
rTCNTB0 = 62500/ 2; // TCNTB0[15:0]= 计数值
rTCMPB0 = 0; // 比较值
rTCON |=( 1<< 1); // 将 计数值装入 TCNTB0、TCMPB0
rTCON = 0x09; // 1001 自动 重载,启动。
ClearPending(BIT_TIMER0); // 清除SRCPND、INTPND 此处课省略
/* 当达到0.5秒时,执行中断函数IRQ_Timer0_Handle */
pISR_TIMER0 = (U32)IRQ_Timer0_Handle; // 中断向量 = 中断函数
EnableIrq(BIT_TIMER0); // 手动打 开屏蔽 INTMSK
}
static void __irq IRQ_Timer0_Handle( void)
{
ClearPending(BIT_TIMER0); // 清中断
Led1_run();
}