一、S3C2440 时钟
1、时钟树
从s3c2440的技术手册的时钟树可以了解到,它的时钟分四大块FCLK,HCLK,PCLK,UCLK。FCLK主要用于CPU的运行时钟,HCLK主要用于内存控制器,中断控制器等一些高速设备的时钟,PCLK主要用于GPIO控制器,I2C控制器等一些较低速设备的时钟,UCLK主要给USB控制器提供时钟的。时钟树如下图:
2、S3C2440支持的时钟速率
1、S3C2440的最高速率:FCLK最高支持400MHz,HCLK最高支持136MHz,PCLK最高支持68MHz。
2、在本实验将 FCLK设置为400MHz,HCLK设置为100MHz,PCLK设置为50MHz。
二、设置时钟
1、时钟源的选择
1、s3c2440的时钟源,可以从晶振里来也可以从外部时钟来。来源于哪里可以由OM2和OM3管脚设置。
2、由于我的板子接了12MHz的晶振,所以将晶振设置为输入的时钟源;OM2和OM3都设置为0。
2、锁相环设置(MPLLCON寄存器)
MPLLCON寄存器:
MPLL 时钟的计算公式:
S3C2440技术手册提供了配置值,直接使用它的配置值,这里就不自己计算了。
3、配置HCLK和PCKL分频(CLKDIVN寄存器)
4、设置锁存存时间(LOCKTIME)
由于配置锁相环的时候需要等待它输出稳定的时钟,等待的这段时间由LOCKTIME配置
LOCKTIME 寄存器使用默认的值0xFFFFFFFF即可
5、设置异步模式
S3C2440技术手册有说明,如果FCLK的时钟频率不等于HCLK的频率时需要配置成异步模式,否则CPU使用HCLK作为运行的时钟频率。设置的方法手册上也有,需要通过设置它的协处理器。
对于#R1_nF:OR:R1_iA这个立即数是什么,在S3C2440手册上没有给出。一般这些跟CPU核相关的设置,我们可以去看它的CPU核的技术文档(S3C2440的CPU核是arm920t)。在arm920t技术文档找到了nF和iA。如下图:
三、程序编写
1、汇编程序(Startup.S)
因为要设置p15协处理器,所以初始化时钟用汇编语言来写。
.text /*定义代码段*/
.global _start /*标号_start是GNU连接器用来指定第一个要执行所必须的(只能出现在一个模块),.global将_start声明为全局可见*/
_start:
/* 关看门狗 */
ldr r1,=0x53000000
mov r0,#0x00000000
str r0,[r1]
/* 设置栈 */
/* 自动分辨是nor flash 启动还是nand flash启动 */
/* 先将一个数写道0地址,然后读出来判断跟写入的值是否一样;跟写入的一样则是nand flash启动,跟写入的值不一样则是nor flash 启动 */
mov r1, #0
ldr r0, [r1] /* 读出原来的值备份 */
str r1, [r1] /* 0->[0] */
ldr r2, [r1] /* r2=[0] */
cmp r1, r2 /* r1==r2? 如果相等表示是NAND启动 */
ldr sp, =0x40000000+0x1000 /* 先假设是nor启动,0x40000000 + 4k处 */
moveq sp, #0x1000 /* nand启动, 将栈设置在4k处 */
streq r0, [r1] /* 恢复原来的值 */
#if 1
/* 初始化时钟 */
/* 设置锁存时间 LOCKTIME=0xffffffff */
ldr r1,=0x4C000000
ldr r0,=0xffffffff
str r0,[r1]
/* 设置HDIVN,PDIVN分频系数,让FCLK:HCLK:PCLK=1:4:8 */
ldr r1,=0x4C000014
mov r0,#0x00000005
str r0,[r1]
/* 设置Mpll锁相环 MDV=0x5c,PDIV=1,SDIV=1 */
ldr r1,=0x4C000004
ldr r0,=((0x5c<<12)|(1<<4)|(1<<0))
str r0, [r1]
/* 设置锁相环时钟源,使能锁相环 */
ldr r1,=0x4C000010
mov r0,#0x00000004
str r0,[r1]
/* 设置时钟为异步模式 */
mrc p15,0,r0,c1,c0,0
orr r0,r0,#0xc0000000
mcr p15,0,r0,c1,c0,0
#endif
b main
loop:
b loop
2、主程序(main.c)
main函数里面主要做了led灯闪烁的事情
/* 定义GPFCON 寄存器 */
#define GPFCON *((volatile unsigned long*)0x56000050)
/* 定义GPFDAT 寄存器 */
#define GPFDAT *((volatile unsigned long*)0x56000054)
void delay(int tim){
while(tim--);
}
int main(){
/* 清零 */
GPFCON &= ~(0x03 << 8);
/* 设置为output */
GPFCON |= (0x01<<8);
while(1){
/* 将 GPF4 输出低电平 */
GPFDAT &= ~(1<<4);
delay(0x10000);
/* 将 GPF4 输出高电平 */
GPFDAT |= (1<<4);
delay(0x10000);
}
return 0;
}
3、Makefile
all:
arm-linux-gcc -c Startup.S -o Startup.o
arm-linux-gcc -c main.c -o main.o
arm-linux-ld -Ttext 0 Startup.o main.o -o Led.elf
arm-linux-objcopy -O binary -S Led.elf Led.bin
arm-linux-objdump -D Led.elf > led.dis
clean:
rm *.o *.elf *.bin *.dis
四、实验现象
通过初始化时钟后和不初始化时钟的led灯闪烁的快慢成都不一样。通过现象可以看到初始化时钟后led灯闪烁的更快,也就是说CPU的运行频率更快了。