- 基本知识
- 主要寄存器介绍
- 源码
硬件平台:jz2440
软件平台:Ubuntu16.04 arm-linux-gcc-3.4.5
源码位置: https://github.com/lian494362816/C/tree/master/2440/007_clock
1.基本知识
1.1clock模块介绍
2440主要的时钟有4个2个PLL:FCLK,HCLK,PCLK,UCLK;MPLL,UPLL。
FCLK是给CPU用的,频率最高。HCLK是给高速外设用的,如LCD、NAND Flash、Camera。 PCLK是给低速外设用的,如UART,IIS,IIC等。HCLK和PCLK都是从FCLK分频得到的。UCLK是专门给USB使用的。
MPLL, UPLL主要是用来升频的,将外部的晶振(jz2440为12M)升频到需要频率。MPLL是用来给FCLK升频的,UPLL则是给UCLK升频的。
本博客主要介绍FCLK,HCLK,PCLK和MPLL;ULCK和UPLL暂时不讲。
1.2 时钟的比例
HCLK和PCLK是由FCLK分频得到,之间的分频比不是随意设置的,2440给出了一张可供挑选的表格。
在2440文档的Product Overview 章节(后面章节没有提过)查到FCLK最大400M, HCLK最大136M, PCLK最大68M。频率当然是越高越好,所以把FCLK设置成400M。再根据前面分频比的表格,选择1:4:8 的分频比。 PCLK 50M : HCLK 100M: FCLK 400M = 1:4:8
1.3 升频的过程
外部的晶振通过 MPLL/UPLL 升频后达到更高的频率,升频的过程需要一定的时间才可以稳定输出。(VCO:Voltage Controlled Oscillator )
2.主要寄存器介绍
2.1 LOCKTIME
LOCKTIME 就是用来设置升频过程中的lock time, 这里只关心MPLL[15:0]的设置,默认值就是最大值,也是最安全的值。
2.2 MPLLCON
设置MPLL的控制寄存器,最终影响FCLK的频率。
Mpll的最终输出会给到FCLK, 也就是FLCK的频率=Mpll的输出频率。FCLK要设置成400M,Mpll也就等于400M。
Mpll的计算公式为:
Mpll = (2 * m * Fin) / (p * 2^s)
m = (MDIV + 8), p = (PDIV + 2), s = SDIV
2440文档给出了一组参考配置,MDIV= 92, PDIV=1,SDIV=1,带入公式
m= (MDIV +8) =92+8=100
p=(PDIV+2)= 1+2=3
s=SDIV=1
Fin是外部晶振的频率=12M
Mpll =(2*100 * 12M)/(3 * 2^1) = 2400M / 6 = 400M
2.3 CLKCON
设置各个模块时钟的开关,使用默认值就可以了
2.4 CLKDIVN
HCLK, PCLK的分频比控制。
PCLK 50M : HCLK 100M: FCLK 400M = 1:4:8, 那么HCLK=FCLK/4 = 400M/4= 100M, PCLK=HCLK/2 = 100M / 2 = 50M 。所以HDIVN设置成10b,PDIVN设置成1b。其中的CAMDIVN[9]需要设置成0, 它的初始值就是0,所以不用管。
2440里面有个NOTE, 当HDIVN不等于0时(我们设置为10b),需要把将bus mode 设置为非同步总线模式。相关的寄存器说明在2410的手册查到,需要把CP15 (协处理器)的R1寄存器(控制寄存器)的[31:30] 设置为11b。具体的汇编代码为:
mrc p15,0,r0,c1,c0,0 /* 把CP15的R1的值读到r0*/
orr r0,r0, #0xc0000000 /* r0'或'上0xc0000000, 即r0 | 0xc0000000,把31,30bit设置为1 */
mcr p15,0,r0,c1,c0,0 /* 把r0的值写到CP15的R1 */
2.5 CLKSLOW
使用默认值即可。
3. 源码
start.s
.global _start
_start:
/* stop watch dog */
ldr r0, =0x53000000
mov r1, #0
str r1, [r0]
/* Source crystal oscillator 12M
FCLK 400M HCLK 100M PCLK 50M */
/* 1, set lock time LOCKTIME 0x4c000000 */
ldr r0, =0x4c000000
ldr r1, = 0xFFFFFFFF
str r1, [r0]
/*2, set CLKDIVN 0x4c000014
HDIVN = FLCK / 4
PDIVN = HCLK / 2
HDIVN->b10 PDIVN->1 */
ldr r0, = 0x4c000014
ldr r1, = ( (2 << 1) | (1 << 0) )
str r1, [r0]
/* HCLK = FCLK/4 when CAMDIVN[9] = 0
and thc CAMDIVN[9] default value is 0*/
/*3, if HDIVN is not 0, CPU bus mode must be asynchronous */
mrc p15,0,r0,c1,c0,0
orr r0,r0, #0xc0000000
mcr p15,0,r0,c1,c0,0
/* 4, set MPLLCON 0x4c000004
MDIV->92(0x5c), PDIV->1 SDIV->1
MPLL = (2 * m *Fin) / (p * 2 ^s)
m = (MVID + 8) = (92 + 8) = 100
p = (PDIV + 2) = (1 + 2) = 3
s= SDIV = 1
MPLL = (2 * 100 * 12M) / (3 * 2 ^ 1) = 400M
*/
ldr r0, =0x4c000004
ldr r1, =( (92 << 12) | (1 << 4) | (1 << 0))
str r1, [r0]
/* aoto switch nand or nor flash */
/* write 0 to address[0] and read it
* if address[0] is equal 0, it is nand
* because nand can wirte easy, but nor need send
* write-commond before wirte data, so write 0 to
* nor address[0] will fail, and get nor address[0]
* data is not equal 0
*/
mov r1, #0
ldr r0, [r1] /* r0=[0] store address[0] data*/
str r1, [r1] /* 0->[0] */
ldr r2, [r1] /* r2=[0] */
cmp r1, r2
ldr sp, =0x40000000 + 4096/* for nor */
ldreq sp, =4096 /* for nand */
streq r0, [r1] /* recover address[0] data */
bl main
loop:
b loop
源码很简单,就是按照之前介绍寄存器时的参数去设置就行了,不做过多的介绍。