三、s3c2440 裸机 系统时钟和定时器的设置

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/woshidahuaidan2011/article/details/51122945

三、系统时钟和定时器的设置

⑴系统时钟原理分析

时钟决定2440执行速度,2440可以使用外部提供的时钟源,也可以使用外部的晶振然后通过内部的晶振获得时钟频率;具体选择使用哪一个时钟源看下图:


开发板一般吧引脚M2和M3连接的GND,所以说全部使用的是晶振(crystal)

除此之外,2440提供了3个时钟源FCLK(用于cpu核),HCLK(advancedhigh performance bus,用于AHB总线设备,比如cpu核,dma,usb等),PCLK(advanced performance bus,用于外围设备,比如看门狗,pwm定时器,adc等等),对于锁相环,2440拥有两种PLL其中一个为UPLL,其专用于usb设备,还有一个是MPLL用于设置fclk,hclk,pclk。

假如不设置PLL此时FCLK为Fin 也就是外部晶振为12M。

设置PLL后,就是设置相应的寄存器来得到所需要的值,S3C2440使用了三个倍频因子MDIV、PDIV和SDIV来设置倍频,通过寄存器MPLLCON和UPLLCON可设置倍频因子。其中MPLLCON寄存器用于设置处理器内核时钟主频FCLK,其输入输出频率间的关系为


  FCLK=MPLL=(2*m*Fin)/(p*2^s)

其中m=(MDIV+8), p=(PDIV+2), s=SDIV。

其中UPLLCON寄存器用于产生48MHz或96MHz,提供USB时钟(UCLK),其输入输出频率间的关系为

UCLK=UPLL=(m *Fin) / (p * 2^s)

其中m=(MDIV+8), p=(PDIV+2), s=SDIV。

上面的MPLLCON和UPLLCON与MDIV,PDIV,SDIV的关系为:


也就PLLCON的01位是SDIV,4-9位是PDIV,12-19位MDIV。

为了方便,2440的芯片手册给出了参考设置PLL的数值:

假设晶振为12M,可以参考上图的蓝色加深部分的设置数值。上图的48M和96M是设置UPLLCLK使用的。

通过表可以完成FCLK的设置,正如前面所说的,除了FCLK还有HCLK和PCLK需要设置,接下来就可以设置HCLK和PCLK,此时需要两个寄存器:

对于CLKDIVN


通过此寄存器可以得到相应的HCLK和PCLK。但是由于在设置HDIVN(也就是CLKDIVN的1、2位)的时候需要用到CAMDIVN的第8位和第9位,CAMDIVN寄存器为:


结合在上面的这两个寄存器可以得到频率。通过上面的两个表格可以得到四个值:HDIVN ,PDIVN,HCLK3_HALF和 HCLK4_HALF,为了方面描述它们的关系,可以参考表:

 

下手册的后面有对时钟的如下注释:


这是说假如HDIVN不是0的话要加上:

mrcp15,0,r0,c1,c0,0
orr r0,r0,#R1_nF:OR:R1_iA
mcr p15,0,r0,c1,c0,0

 

通过上面的设置可以完成设置FCLK、HCLK、PCLK,实际上2440在设置时钟前后的运行状态是这样的:(下面再给出设置MPLL的过程图(UPLL类似))

 

 

 

通过上图可以看到,在上电一段是时间后,等待nRESET信号(复位信号)恢复高电平后,然后可以执行PLL有关寄存器的操作了。其中OSC为晶振的频率大小为12M,VCO为输出频率。还可以看到在设置完PLL需要等待一段时间才可以输出设定频率,这个等待时间是可以通过LOCKTIME寄存器来设置,这个时间是需要满足一定的最小值的,使用默认值就可以。该寄存器说明见下图:

 

 

总结:

设置时钟相对来说比较简单,这里给出的其设置流程:

1、  设置cpu由新的时钟频率到旧的频率下的间隔时间 设置LOCKTIME(默认值即可)

2、  设置FCLK、HCLK、PCLK频率比例,可以通过设置寄存器CLKDIVN 辅助CAMDIVN

3、  /* 如果CLKDIVN 中的HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronousbus mode” */

_asm__(

 "mrc    p15, 0, r1, c1, c0,0\n"        /* 读出控制寄存器 */

 "orr    r1, r1,#0xc0000000\n"          /* 设置为“asynchronous bus mode” */

 "mcr   p15, 0, r1, c1, c0, 0\n"       /* 写入控制寄存器 */

 );

4、  根据个人要求设置FCLK时钟 可以通过设置MPLLCON来设置

5、  假如有需要,设置UCLK时钟,可以通过设置UPLLCON来设置

 

测试设定代码:

void mpll_init(void )

{

//1      设置cpu由新的时钟频率到旧的频率下的间隔时间设置LOCKTIME(默认值即可)

 

 

//2      设置FCLKHCLKPCLK频率比例,可以通过设置寄存器CLKDIVN  CAMDIVN

//若设置FCLK为400M HCLK=100M   PCLK=50M

//hdivn=2  pdivn=1

rCLKDIVN |= (2<<1) | 1;

rCAMDIVN &=~(1<<9);

 

//3       /*如果CLKDIVN中的HDIVN0CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */

__asm{

  mrc    p15, 0, r1, c1, c0, 0      /* 读出控制寄存器 */

  orr    r1, r1, #0xc0000000          /* 设置为“asynchronous bus mode” */

  mcr    p15, 0, r1, c1, c0, 0        /* 写入控制寄存器 */

 };

 

//  MMU_SetAsyncBusMode();

 

//4      根据个人要求设置FCLK时钟可以通过设置MPLLCON来设置

 // FCLK=MPLL=(2*m*Fin)/(p*2^s)

 // 其中m=(MDIV+8), p=(PDIV+2), s=SDIV

 // MDIV=0X5C PDIV=1  SDIV=1  FCLK=400M

 //

rMPLLCON=((0x5c<<12) | (1<<4) | 1);

 

//5      假如有需要,设置UCLK时钟,可以通过设置UPLLCON来设置

}

 

⑵定时器原理分析

s3c2440拥有Timer0,1,2,3,4五个16位定时器,其中Timer0,1,2,3具有Pulse Width Modulation (PWM)功能,Timer4引脚没有输出,Timer0比较特殊,拥有适用于大电流的死区生成器。

定时器0 和1 共享一个8 位的预分频器(预定标器),定时器2,3,4 共享另一个8 位预分频器,其构造图如图所示:


可以看出,定时器的时钟源为PCLK,首先经过预分频器降低频率后,进入第二个分频.可以生成5 种不同的分频信号(1/2,1/4,1/8,1/16 和外部时钟TCLK0、TCLK1。

这两个预分频器可以使用TCFG0寄存器来设置,其功能如图:


 

可以看到,TCFG0的0-7位设置分频器0,用来控制定时器0和定时器1,8到15位用来设置预分频器1,用来控制定时器2、3、4。其频率的计算公式就是:

定时器的时钟频率 = PCLK / {prescaler value+1 } /{divider value}

prescaler value的大小就是上面的寄存器设置每个8位大小是0到255 ,divider value的大小通过TCFG1来设置可以取值2、4、8、16,看下图:

 

通过上面两个寄存器设置完时钟之后,就可以来控制定时器了,包括是否打开定时器,定时器的时间等等。

首先,需要看到的是TCON,用来控制定时器的打开与关闭,是否自动重新装入初值:



通过上表可实现对5个定时器的控制,其中在人工装入定时器值的时候需要注意,每次重新写入初值的时候需要清零后再写。以timer3为例,介绍一下每一位作用:

Timer 3 auto reload on/off   这是说定时器是是否自动载入定时时间,或者定时器是否是周期性的。

Timer 3 output inverter on/off 这是说是否开启反转模式,开通与否的效果为:


Timer 3 manualupdate该为设置为1是手工把数据装入TCNTB3 & TCMPB3(下面会介绍这两个寄存器)。

Timer 3 start/stop 打开或者关系定时器3.

在打开定时器之前,还需要给定时器装入初值,以确定定时器触发的时间,这里需要两个寄存器:TCMPBn,TCNTBn,这里以定时器0为例,接扫一下,先看寄存器介绍:

 

通过上表可以看出,TCMPBn用来设置比较值,TCNTBn用来设置初值。设定好这两个寄存器后,定时器就会在规定的频率下,TCNTBn开始减去1计数,直到减小到TCMPBn设定的比较值,此时可以通过读取TCNTOn来观察TCNTBn的值。

 

使用定时器设置如下:

1、  选定timer0-5定时器,设置预分频器 TCFG0  和分频器TCFG1

2、  给定时器设定定时时间,也就是给TCNTB0装入初值 和 装入TCMPBn寄存器比较器(默认0)

3、  设置定时时间载入方式及其打开定时器 使用寄存器TCON  

定时器设置参考代码:

/*

void timer0_init()

{

 

//1、选定timer0-5定时器,设置预分频器TCFG0 分频器TCFG1

    //定时器的时钟频率 = PCLK / {prescaler value+1 } / {divider value}

// PCLK=50m    {prescaler value+1} / {divider value}

   rTCFG0 &= ~(0xFF) ;

     rTCFG0 |= 99 ;  //预分频系数为99

     rTCFG1 &= ~(0xf);

     rTCFG1 |= 0x03;  //16分频

    

     //定时器的时钟频率=50000000/100/16=31250

//2     给定时器设定定时时间,也就是给TCNTB0装入初值装入TCMPBn寄存器比较器(默认0

 

     rTCNTB0=31250;//每秒一次

//TCMPBn取默认值0

 

//3     设置定时时间载入方式及其打开定时器使用寄存器TCON

     rTCON |=  (1 << 1) ; //TCNTB0TCMPB0装入内部的TCNT0TCMP0

     rTCON &=~(0xf);

     rTCON |= 0x09 ;  //自动重载并且打开定时器0

    

    

     rINTMSK&=~(1<<10);//打开定时器0 中断

     timer0_service_Init();//中断服务函数初始化

 

}

参考:

http://www.cnblogs.com/idle_man/archive/2011/03/01/1968168.html

http://blog.csdn.net/mr_raptor/article/details/6555734 

http://www.cnblogs.com/hnrainll/archive/2011/06/28/2092292.html

阅读更多
换一批

没有更多推荐了,返回首页