汇编实现时钟代码详解

1、实验项目文件介绍:文件包括mkv210_image.c 、Makefile(在这里第一行的依赖里要添加clock.o)、 led.c、 start.S(这里面用bl调用clock.S中实现时钟设置的函数)、 (这几个文件是在汇编写启动代码之开iCache复制来的),增加了一个clock.S
2、宏定义的应用:
(1)、寄存器访问:时钟模块基地址(ARM里面所有的寄存器都是按模块分的,每个模块里的寄存器地址都是彼此挨着的): 所以我们可以利用宏定义基址 + 宏定义变址(相对基址偏移量)的方式实现访问当前寄存器。
(2)、
//定义APLL中计算倍频系数参数M、P、S的值
#define APLL_MDIV 0x7d // 125
#define APLL_PDIV 0x3
#define APLL_SDIV 0x1

//定义MPLL中计算倍频系数参数M、P、S的值
#define MPLL_MDIV 0x29b // 667
#define MPLL_PDIV 0xc
#define MPLL_SDIV 0x1

//因为APLL和MPLL要设置的寄存器bit位和值都相同,所以这里定义一个公用宏(和C语言中定义一个函数的功能相同)
#define set_pll(mdiv, pdiv, sdiv) (1<<31 | mdiv<<16 | pdiv<<8 | sdiv)
//代入各自参数定义相应的宏
#define APLL_VAL set_pll(APLL_MDIV,APLL_PDIV,APLL_SDIV)
#define MPLL_VAL set_pll(MPLL_MDIV,MPLL_PDIV,MPLL_SDIV)

3、代码分析:
整个代码流程:
1选择不使用PLL:不倍频绕过PLL。
2、设置锁定时间:倍频后要得到稳定时钟要有个时间段,倍频后的延时。
3、设置PLL倍频:主要是设置PLL的倍频系数,决定由输入端24MHz的原始频率可以得到多大的输出频率。我们按照手册建议设置值输出为ARMCLK(主频)为1GHz。
4、设置分频系统(DIV):决定由PLL出来的最高时钟如何分频得到各个分时钟。
5、开启PLL:前面4步已经设置好了所有的开关和分频系数,本步骤打开PLL后PLL开始工作,锁定频率后输出,然后经过分频得到各个频率。

总结:以上5步,其实真正涉及到的寄存器只有5个而已。
CLK_SRC寄存器的设置分析:
CLK_SRC:寄存器其实是用来设置MUX开关的。在这里先将该寄存器设置为全0,主要是bit0和bit4设置为0,表示APLL和MPLL暂时都不启用。

CLK_LOCK寄存器的设置分析:
CLK_LOCK:设置PLL锁定延时的。官方推荐值为0xFFF,我们设置为oxFFFF。

CLK_DIV寄存器设置分析:(0x14131440用这个值去对照分析)
( 0 ~ 2bit ) ARMCLK = MOUTmsys / 1
( 4 ~ 6bit ) SCLK_A2M = SCLK_APLL / 5
( 8 ~ 10bit ) HCLK_MSYS = ARMCLK / 5
( 12 ~ 14bit ) PCLK_MSYS = HCLK_MSYS / 2
( 16 ~ 19bit ) HCLK_DSYS = MOUTsys / 4
( 20 ~ 22bit ) PCLK_DSYS = HCLK_DSYS / 2
( 24 ~ 27bit ) HCLK_PSYS = MOUTpsys /5
( 28 ~ 30bit ) PCLK_PSYS = HCLK_PSYS / 1

APLL_CON 0寄存器分析:
APLL_CON 0 主要设置PLL倍频系数的,计算公式是:FOUT = MDIV X FIN / (PDIV × 2SDIV-1)
这些M、P、S的配置值都是查数据手册中典型时钟配置值的推荐配置得来的。
这些配置值是三星推荐的,因此工作最稳定。如果是自己随便瞎拼凑出来的那就要

第一步:选择不使用PLL。相关寄存器是CLK_SRC0。我们这里做实验只设置了MUXAPLL(bit0)和MUXMPLL(bit 4),所以把32全设置为0。

//时钟模块基地址
#define ELFIN_CLOCK_POWER_BASE 0xE0100000
// 时钟相关的寄存器相对时钟控制器基地址的偏移值
#define CLK_SRC0_OFFSET 0x200
ldr r0, =ELFIN_CLOCK_POWER_BASE
ldr r1, =0x0
str r1, [r0, #CLK_SRC0_OFFSET ]

第一步对应MUX图解:
汇编实现时钟代码详解_第1张图片
第一步对应CLK_SRC0寄存器设置图解:
汇编实现时钟代码详解_第2张图片
第二步:设置PLL锁定时间:
默认值为oxFFF,保险起见我们设置为oxFFFF

#define APLL_LOCK_OFFSET 0x00
#define MPLL_LOCK_OFFSET 0x08
// 设置锁定时间,使用默认值即可
// 设置PLL后,时钟从Fin提升到目标频率时,需要一定的时间,即锁定时间
ldr r1, =0x0000FFFF
str r1, [r0, #APLL_LOCK_OFFSET ] //APPL_LOCK
str r1, [r0, #MPLL_LOCK_OFFSET ] //MPPL_LOCK

第二步图解:
汇编实现时钟代码详解_第3张图片
第三步:设置DIV分频系数(相关寄存器是CLK_DIV0)
#define CLK_DIV0_OFFSET 0x300
#define CLK_DIV0_MASK 0x7fffffff

// 3 设置分频(我们给的值0x14131440)
// 清bit[0~31]
ldr r1, [r0, #CLK_DIV0_OFFSET]
ldr r2, =CLK_DIV0_MASK
bic r1, r1, r2
ldr r2, =0x14131440
orr r1, r1, r2
str r1, [r0, #CLK_DIV0_OFFSET]

第三步图解3:
汇编实现时钟代码详解_第4张图片
第三步图解2:
汇编实现时钟代码详解_第5张图片

第四步:设置PLL倍频系数(相关寄存器APLL_CON 0)

// 这些M、P、S的配置值都是查数据手册中典型时钟配置值的推荐配置得来的。
// 这些配置值是三星推荐的,因此工作最稳定。如果是自己随便瞎拼凑出来的那就要
// 经过严格测试,才能保证一定对。
#define APLL_MDIV 0x7d // 125
#define APLL_PDIV 0x3
#define APLL_SDIV 0x1

#define MPLL_MDIV 0x29b // 667
#define MPLL_PDIV 0xc
#define MPLL_SDIV 0x1

#define set_pll(mdiv, pdiv, sdiv) (1<<31 | mdiv<<16 | pdiv<<8 | sdiv)
#define APLL_VAL set_pll(APLL_MDIV,APLL_PDIV,APLL_SDIV)
#define MPLL_VAL set_pll(MPLL_MDIV,MPLL_PDIV,MPLL_SDIV)

// FOUT = MDIV*FIN/(PDIV*2^(SDIV-1))=0x7d*24/(0x3*2^(1-1))=1000 MHz
ldr	r1, =APLL_VAL						
str	r1, [r0, #APLL_CON0_OFFSET]
// FOUT = MDIV*FIN/(PDIV*2^SDIV)=0x29b*24/(0xc*2^1)= 667 MHz
ldr	r1, =MPLL_VAL						
str	r1, [r0, #MPLL_CON_OFFSET]

第四步图解:
汇编实现时钟代码详解_第6张图片

第五步: 设置各种时钟开关,使用PLL
ldr r1, [r0, #CLK_SRC0_OFFSET]
ldr r2, =0x10001111
orr r1, r1, r2
str r1, [r0, #CLK_SRC0_OFFSET]

mov	pc, lr

时钟分配详图:
汇编实现时钟代码详解_第7张图片

你可能感兴趣的:(朱老师视频笔记)