1 arm时钟框图
-
Fclk(400MHZ,给CPU提供时钟)。
-
Hclk(136MHZ,给AHB总线提供时钟)。
-
Pclk(68MHZ,给APB总线提供时钟)。
2 arm时钟产生过程
-
Fclk时钟产生:时钟源->OM选择那个时钟源->传给MPLL和UPLL锁相环倍频->不分配给Fclk。
-
Hclk时钟产生:时钟源->OM选择那个时钟源->传给MPLL和UPLL锁相环倍频->HDIVN->Hclk。
-
Pclk时钟产生:时钟源->OM选择那个时钟源->传给MPLL和UPLL锁相环倍频->PDIVN->Pclk。
-
时钟源:晶振或外 部时钟源,本开发板时12MHZ晶振。
-
时钟源选择:配置OM引脚电平,本开发板两个引脚都接地,故主MPLL和UPLL都是晶振提供时钟源。
-
Fclk时钟:MP LL倍频后的时钟信号不分频获得。
-
Hclk时钟:MPLL倍频后时钟信号经过HDIVN分频获得。
-
Pclk时钟:MPLL倍频后时钟信号经过PDIVN分配获得。
3 时钟产生时序图
1 上电,复位电平需要维持低电平一段时间才稳定,借助复位芯片nRESET引脚。
2 根据OM引脚来接入时钟源,按照默认配置产生Fclk电平,此时等于晶振。
3 锁存OM的值,运行PLL。
4 设置PLL的锁存时间并设置PLL的倍频比,此时fclk停止工作。
5 设置打开PLL。
6 Fclk时钟重新产生,且值等于锁相环MPLL,CPU运行。
4 Clock相关寄存器
4.1 锁存时间
-
高十六位设置USB的UPLL锁存时间。
-
低十六位设置MPLL锁存时间。
4.2 MPLLCON、UPLLCON
MPLLCON:用来设置MPLL时钟。
UPLLCON:用来设置UPLL时钟。
第二幅图为不同频率对应的推荐设置值。
- 频率计算公式:
4.3 CLKCON
- 时钟控制寄存器:完成各个外设的使能和失能。
4.4 CLKDIVN
-
CLKDIVN:配置时钟的分频比。
-
DIVN_UPLL:配置UPLL的分频比。
-
HDIVN:需要配置成4分配,则需要CAMDIVN第九位为0,但本开发板默认为0。
-
PDIVN:配置Pclk的分频比。
4.5 CAMDIVN
- CAMDIVN:相机时钟分频寄存器。
4.6 CLKSLOW
- CLKSLOW:低速时钟控制器。
5 设置时钟步骤
5.1 设置PLL的分频比
- 目标时钟频率:Fclk = 400MHZ,Hclk = 100MHZ,Pclk = 50MHZ。
- 即分频比:Fclk : Hclk : Pclk = 4:1:2。
- 需要设置CLKDIVN、CAMDIVN。
- 设置Fclk: Hclk = 4 : 1,需要设置CLKDIVN[2:1] (HDIVN) = 10,且CAMDIVN[9] = 0(默认值为0)。
- 设置Hclk: Pclk = 2 : 1,需要设置CLKDIVN[0] = 1,二分频。
- CLKDIVN = 0X5
5.2 配置锁相环寄存器
-
MPLLCON、UPLLCON,其中UPLLCON用在USB时钟上,目前不用。
-
按照配置的推荐表分别设置:MDIV、PDIV、SDIV。
-
MPLLCON = MDIV << 12 | PDIV << 4 | SDIV = (92 << 12 ) | (1 << 4) | 1
5.3 配置locatime
- 400 = (2 * (92 + 8) * 12) / (1 + 2 ) * 2^1。
5.4 配置异步模式
- 如果HDIVN不为0,但是没有配置为异步模式时,CPU会以Hclk的时钟运行。
- 其中:mrc是将写处理CP15中的值读搭配寄存器中,mcr则是将寄存器的值写到协处理器中。
- 将这段指令拷贝到start.s的最上面。
6 代码实现
6.1 start.S
.text
.global _start
_start:
/* ==========================关闭看门狗========================*/
mov r0,#0
ldr r1,=0x53000000
str r0,[r1]
/* ===========================================================*/
/* ======设置fclk = 400MHZ, hclk = 100MHZ, pclk = 50MHZ ======*/
/*1. 设置localtime*/
ldr r0,=0xFFFFFFFF
ldr r1,=0x4C000000
str r0,[r1]
/*2. 设置CLKDIVN = 0x05*/
mov r0,#0x05
ldr r1,=0x4C000014
str r0,[r1]
/*3. 配置CPU异步模式*/
mrc p15,0,r0,c1,c0,0
orr r0,r0,#0xc0000000 //R1_nF:OR:R1_iA
mcr p15,0,r0,c1,c0,0
/*4. 设置MPLLCON = MDIV << 12 | PDIV << 4 | SDIV = (92 << 12 ) | (1 << 4) | 1*/
ldr r0,=(92 << 12 ) | (1 << 4) | (1 << 0)
ldr r1,=0x4C000004
str r0,[r1]
/* ===========================================================*/
/**/
/*判断nor还是nand启动*/
/*将0地址的值读到r0*/
mov r1,#0
ldr r0,[r1]
/*将0写到0地址*/
str r1,[r1]
/*从0地址读取值放在r2*/
ldr r2,[r1];
/*假设sp从nand启动*/
ldr sp,=0x40000000 + 4096
/*如果是nand启动,则修改sp*/
cmp r0,r2
/*如果r0 == r2,则修改sp*/
moveq sp,#4096
/*如果是nand启动,那么此时0处的值被修改了,需要改回去*/
streq r0,[r1]
bl main
_halt:
b _halt
6.2 led.c
#include "s3c2440_soc.h"
void Delay(unsigned int x){
while(x --);
}
int main(void){
/*将8~13清零*/
GPFCON &= ~((3<<8) | (3<< 10) | (3 << 12));
/*将8、10、12置1*/
GPFCON |= ((1<<8) | (1<< 10) | (1 << 12));
/*将456置1熄灭所有led*/
GPFDAT |= (7 << 4);
while(1){
GPFDAT &= ~(1 << 4);
Delay(100000);
GPFDAT |= (1 << 4);
GPFDAT &= ~(1 << 5);
Delay(100000);
GPFDAT |= (1 << 5);
GPFDAT &= ~(1 << 6);
Delay(100000);
GPFDAT |= (1 << 6);
}
}