s3c2440裸机编程-时钟体系

1 总线框架#

下图是s3c2440的总线框架,其中有AHB(Advanced High performance Bus)高速总线,APB(Advanced Peripheral Bus)外围总线。

不同总线对应不同的时钟。

SOC <-> FCLK
AHB <-> HCLK	
APB <-> PCLK 

其中:

1.使用AHB总线的有:LCD控制器、usb控制器、中断控制器、内存控制器等…
2.使用APB总线的有:i2c、spi、timer、gpio、adc等…具体上图。

2 时钟框架#

下图表示s3c2440 Soc的时钟框图:

下面从细节上讲解时钟体系:

2.1 如何选择时钟源#

s3c2440时钟源有2个,一个是OSC,一个是外部时钟EXTCLK,上面的时钟框图有标记,当然大家也可以查看手册“Figure 7-1. Clock Generator Block Diagram”。

那么如何选择是OSC还是EXTCLK呢?

打开原理图,OM3,OM2的引脚接地,那么OM[3,2]=00.所以根据手册“Table 7-1. Clock Source Selection at Boot-Up”可知时钟源为OSC晶振。

2.2 如何得到HCLK,PCLK,UCLK#

先了解下PLL, DIV

PLL:用锁相环进行倍频
DIV:用分频器进行分频

如下图:

生成的MPLL(Main PLL)和UPLL(USB PLL),MPLL直接提供给FCLK,通过HDIVN分频给HCLK,通过PDIVN分频给PCLK,再传给下面的各个设备。
osc经过UPLL(USB PLL)得到UCLK。

3 配置时钟控制器#

3.1 s3c2440时钟时序#

下图是2440时钟配置时序:

1.上电后,nRESET复位信号拉低,此时cpu还无法取指令工作。
2.nRESET复位信号结束后变为高电平,此时cpu开始工作。此时cpu主频FCLK=osc。
3.此时可以配置PLL,经过lock time后,FCLK倍频成新的时钟。

3.2 如何配置时钟#

在参考手册的特性里介绍了S3C2440的工作频率,Fclk最高400MHz,Hclk最高136MHz,Pclk最高68MHz。那么 我们干脆配置FCLK:HCLK:PCLK= 400:100:50 (MHz).

3.2.1 配置lock time#

我们取芯片手册上的推荐值。
1
2
3
4
/* LOCKTIME(0x4C000000) = 0xFFFFFFFF */
ldr r0, =0x4C000000
ldr r1, =0xFFFFFFFF
str r1, [r0]

3.2.2 配置MPLL得到FCLK#

也可参考配置表取值

1
2
3
4
5
6
7
8
9
10
11
12
/*
** MPLL(FCLK) = 2*m*Fin/(p*2^s)
** 不妨取:
** m = MDIV+8 = 92+8=100
** p = PDIV+2 = 1+2 = 3
** s = SDIV = 1
** 则:
** FCLK= 2*100*12/(3*2^1)=400M
*/
ldr r0, =0x4C000004
ldr r1, =(92<<12)|(1<<4)|(1<<0)
str r1, [r0]

注意:如果也要配置了UPLL,那么先配置UPLL,要个7个NOP后才能再配置MPLL.

###3,配置CLKDIVN得到HCLK,PCLK

1
2
3
4
/* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8  */
ldr r0, =0x4C000014
ldr r1, =0x5
str r1, [r0]

注意:如果HDIV设置为非0,CPU的总线模式要进行改变,默认情况下FCLK = HCLK,CPU工作在fast bus mode快速总线模式下,HDIV设置为非0后, FCLK与HCLK不再相等,要将CPU改为asynchronous bus mod异步总线模式.

1
2
3
4
/* 设置CPU工作于异步模式 */
mrc p15, 0, r1, c1, c0, 0         /* 读取CP15 C1寄存器 */ 
orr r1, r1, #0xc0000000         /* 设置CPU总线模式 */ 
mcr p15, 0, r1, c1, c0, 0         /* 写回CP15 C1寄存器 */

3.2.2 完整汇编代码#

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
.text
.global _start

_start:
/* 关闭看门狗 */
ldr r0, =0x53000000
ldr r1, =0
str r1, [r0]

/* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */
/* LOCKTIME(0x4C000000) = 0xFFFFFFFF */
ldr r0, =0x4C000000
ldr r1, =0xFFFFFFFF
str r1, [r0]

/* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8 */
ldr r0, =0x4C000014
ldr r1, =0x5
str r1, [r0]

/* 设置CPU工作于异步模式 */
mrc p15,0,r0,c1,c0,0
orr r0,r0,#0xc0000000 //R1_nF:OR:R1_iA
mcr p15,0,r0,c1,c0,0

/* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0)
* m = MDIV+8 = 92+8=100
* p = PDIV+2 = 1+2 = 3
* s = SDIV = 1
* FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M
*/
ldr r0, =0x4C000004
ldr r1, =(92<<12)|(1<<4)|(1<<0)
str r1, [r0]

/* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定
* 然后CPU工作于新的频率FCLK
*/

/* 设置内存: sp 栈 */
/* 分辨是nor/nand启动
* 写0到0地址, 再读出来
* 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动
* 否则就是nor启动
*/
mov r1, #0
ldr r0, [r1] /* 读出原来的值备份 */
str r1, [r1] /* 0->[0] */
ldr r2, [r1] /* r2=[0] */
cmp r1, r2
ldr sp, =0x40000000+4096
moveq sp, #4096 /* r1=r2, nand启动,修改栈指针=4096(此时sram对应0地址) */
streq r0, [r1] /* 恢复原来的值 */

bl main

halt:
b halt