1、板子上我们的晶振提供的时钟只有12M,但6410号称可以跑5、6百兆,这是怎么回事呢?
显然,从晶振出来的12M时钟 到给CPU提供的时钟中间经过了某个部件的处理。这个部件就叫做PLL。它将12M的时钟提高到五、六百兆,再供给CPU。我们今天就来设置这个PLL,让它实现这样的功能。
2、怎么设置这个PLL呢?
查看6410手册S3C6410X.pdf,
3、还是从代码来分析吧
1)以下是启动代码 :start.S
.globl _start
_start:
/* 硬件相关的设置 : 把外设的基地址告诉CPU*/
/* Peri port setup */
ldr r0, =0x70000000
orr r0, r0, #0x13
mcr p15,0,r0,c15,c2,4 @ 256M(0x70000000-0x7fffffff)
/* 关看门狗 */
/* 往WTCON(0x7E004000)写0 */
ldr r0, =0x7E004000
mov r1, #0
str r1, [r0]
/*设置时钟 */
bl clock_init
/* 设置栈, 调用C函数 */
ldr sp, =8*1024
bl main
halt:
b halt
2)下面是点led的测试程序:led.c
void delay()
{
volatile int i = 0x10000;
while (i--);
}
int main()
{
int i = 0;
volatile unsigned long *gpmcon = (volatile unsigned long *)0x7F008820;
volatile unsigned long *gpmdat = (volatile unsigned long *)0x7F008824;
/* gpm0,1,2,3设为输出引脚 */
*gpmcon = 0x1111;
while (1)
{
*gpmdat = i;
i++;
if (i == 16)
i = 0;
delay();
}
return 0;
}
3)以下是时钟设置的代码:clock.S
.globl clock_init
clock_init:
/* 1.设置LOCK_TIME */
ldr r0, =0x7E00F000 /* APLL_LOCK */
ldr r1, =0x0000FFFF
str r1, [r0]
str r1, [r0, #4] /* MPLL_LOCK */
str r1, [r0, #8] /* EPLL_LOCK */
#define OTHERS 0x7e00f900
@ set async mode /* 当CPU时钟 != HCLK时,要设为异步模式 */
ldr r0, =OTHERS
ldr r1, [r0]
bic r1, r1, #0xc0 /* 1100,0000 */
str r1, [r0]
loop1: /* 等待,直到CPU进入异步模式 */
ldr r0, =OTHERS
ldr r1, [r0]
and r1, r1, #0xf00
cmp r1, #0
bne loop1
/* SYNC667 */
/* MISC_CON[19] = 0 */
#define ARM_RATIO 0 /* ARMCLK = DOUTAPLL / (ARM_RATIO + 1) */
#define HCLKX2_RATIO 1 /* HCLKX2 = HCLKX2IN / (HCLKX2_RATIO + 1) */
#define HCLK_RATIO 1 /* HCLK = HCLKX2 / (HCLK_RATIO + 1) */
#define PCLK_RATIO 3 /* PCLK = HCLKX2 / (PCLK_RATIO + 1) */
#define MPLL_RATIO 0 /* DOUTMPLL = MOUTMPLL / (MPLL_RATIO + 1) */
ldr r0, =0x7E00F020 /* CLK_DIV0 */
ldr r1, =(ARM_RATIO) | (MPLL_RATIO << 4) | (HCLK_RATIO << 8) | (HCLKX2_RATIO << 9) | (PCLK_RATIO << 12)
str r1, [r0]
/* 2.配置时钟 */
/* 2.1 配置APLL */
/* 2.1.1 设置APLL
* 2.1.2 MUXAPLL
* 2.1.3 SYNC667
* 2.1.4 DIVAPLL
*/
#define APLL_CON_VAL ((1<<31) | (266 << 16) | (3 << 8) | (1))
ldr r0, =0x7E00F00C
ldr r1, =APLL_CON_VAL
str r1, [r0] /* APLL_CON, FOUTAPL = MDIV * Fin / (PDIV*2^SDIV) = 266*12/(3*2^1) = 532MHz */
/* 2.2 配置MPLL */
/* 2.2.1 设置MPLL
* 2.2.2 MUXMPLL
* 2.2.3 SYNCMUX
* 2.2.4 SYNC667
* 2.2.5 HCLKX2_RATIO
* 2.2.6 PCLK_RATIO
*/
#define MPLL_CON_VAL ((1<<31) | (266 << 16) | (3 << 8) | (1))
ldr r0, =0x7E00F010
ldr r1, =MPLL_CON_VAL
str r1, [r0] /* MPLL_CON, FOUTMPL = MDIV * Fin / (PDIV*2^SDIV) = 266*12/(3*2^1) = 532MHz */
/* 3.选择PLL的输出作为时钟源 */
ldr r0, =0x7E00F01C
ldr r1, =0x03
str r1, [r0]
mov pc, lr
1> 我们要把12M时钟提高到5 6百兆,不可能瞬间完成,需要一个时间差,这个时间差就是LOCK_TIME. 以下是时序图:
LOCK_TIME 就是锁定时间,在这段时间PLL就开始工作,把时钟提高。
2> APP MPLL EPLL
这里有3个PLL,分别是给不同的控件提供时钟的,APLL是给CPU用的,MPLL是给HCLK( 一般是我们的内存,DDR ),PCLK(片上外设),EPLL给其它设备用的。
上面是汇编的,以下是其时钟设置C版,功能都一样:
#define APLL_LOCK (*((volatile unsigned long *)0x7E00F000))
#define MPLL_LOCK (*((volatile unsigned long *)0x7E00F004))
#define EPLL_LOCK (*((volatile unsigned long *)0x7E00F008))
#define OTHERS (*((volatile unsigned long *)0x7e00f900))
#define CLK_DIV0 (*((volatile unsigned long *)0x7E00F020))
#define ARM_RATIO 0 /* ARMCLK = DOUTAPLL / (ARM_RATIO + 1) */
#define HCLKX2_RATIO 4 /* HCLKX2 = HCLKX2IN / (HCLKX2_RATIO + 1) = 100MHz */
#define HCLK_RATIO 0 /* HCLK = HCLKX2 / (HCLK_RATIO + 1) = 100MHz */
#define PCLK_RATIO 1 /* PCLK = HCLKX2 / (PCLK_RATIO + 1) = 50MHz */
#define MPLL_RATIO 0 /* DOUTMPLL = MOUTMPLL / (MPLL_RATIO + 1) */
#define APLL_CON (*((volatile unsigned long *)0x7E00F00C))
#define APLL_CON_VAL ((1<<31) | (250 << 16) | (3 << 8) | (1))
#define MPLL_CON (*((volatile unsigned long *)0x7E00F010))
#define MPLL_CON_VAL ((1<<31) | (250 << 16) | (3 << 8) | (1))
#define CLK_SRC (*((volatile unsigned long *)0x7E00F01C))
void clock_init(void)
{
APLL_LOCK = 0xffff;
MPLL_LOCK = 0xffff;
EPLL_LOCK = 0xffff;
/* set async mode 当CPU时钟 != HCLK时,要设为异步模式 */
OTHERS &= ~0xc0;
while ((OTHERS & 0xf00) != 0);
CLK_DIV0 = (ARM_RATIO) | (MPLL_RATIO << 4) | (HCLK_RATIO << 8) | (HCLKX2_RATIO << 9) | (PCLK_RATIO << 12);
APLL_CON = APLL_CON_VAL; /* 500MHz */
MPLL_CON = MPLL_CON_VAL; /* 500MHz */
CLK_SRC = 0x03;
}