转载:http://www.techbulo.com/1388.html有了上一节《
Exynos4412时钟体系分析》的基础,这一节我们来做几个和时钟有关的实验。其实,Exynos 4412的 IROM代码已经设置了PLL,我们可以通过串口把IROM设置的PLL寄存器值打印出来,这些值打印出来是这样的(摘自韦东山老师的《嵌入式Linux系统开发完全手册_基于4412__上册》):123456789101112131415161718192021222324252627282930
CLK_SRC_CPU = 0x01000001
CLK_DIV_DMC0 = 0x00111713
CLK_DIV_DMC1 = 0x01011171
CLK_SRC_TOP0 = 0x01110000
CLK_SRC_TOP1 = 0x00001000
CLK_DIV_TOP = 0x00015470
CLK_SRC_LEFTBUS = 0x00000001
CLK_DIV_LEFTBUS = 0x00000013
CLK_SRC_RIGHTBUS = 0x00000001
CLK_DIV_RIGHTBUS = 0x00000013
APLL_LOCK = 0x00000960
MPLL_LOCK = 0x00000000
EPLL_LOCK = 0x00000FFF
VPLL_LOCK = 0x00000FFF
CLK_DIV_CPU0 = 0x00773730
CLK_DIV_CPU1 = 0x00000077
APLL_CON1 = 0x00003800
APLL_CON0 = 0xA0640301
MPLL_CON1 = 0x00003800
MPLL_CON0 = 0xA0640301
EPLL_CON2 = 0x00000080
EPLL_CON1 = 0x66010000
EPLL_CON0 = 0x00600302
VPLL_CON2 = 0x00000080
VPLL_CON1 = 0x66016000
VPLL_CON0 = 0x006F0302
CLK_SRC_CPU = 0x01000001
CLK_SRC_DMC = 0x00111000
CLK_SRC_TOP0 = 0x01110000
CLK_SRC_TOP1 = 0x00001000
现在来计算 ARMCLK的时钟频率:由上一节《
Exynos4412时钟体系分析》的介绍我们知道,ARMCLK 有如下计算公式:如下图所示:
由上边打印的寄存器CLK_SRC_CPU 的值为:十六进制:0x01000001二进制:0000 000
1 000
0 000
0 0000 0000 0000 000
1① BIT[0] 控制第1个MUX (即 MUXAPLL) ,该位值为1.② BIT[16]控制 第2个 MUX( 即MUXCORE) ,该位值为0.所以由此看出ARMCLK时钟走的是如下的路线:
所以:ARMCLK = MUXCORE的输出 / DIVCORE / DIVCORE2ARMCLK = MDIV x FIN / (PDIV x 2 ^ SDIV) / (CORE_RATIO + 1) / (CORE2_RATIO + 1)= 0x64 x 24MHz / (3 x 2 ^ 1) / (0 + 1) / (0 + 1)= 400 MHz 本次实验涉及3个小实验:① 4.system_clock_disable_apll:不使用 APLL,让CPU运行于 24MHz 频率,观察 LED 闪烁是否变慢② 5.system_clock_apll:重新设置APLL,让 CPU 运行于1.4GHz频率,观察 LED 闪烁是否变快③ 6.system_clock_plls:参考厂家提供的u-boot代码,设置所有PLL供后续章节使用
第一个小实验实现的目标:不使用 APLL,让CPU运行于 24MHz 频率,观察 LED 闪烁是否变慢
一、程序说明我们在前一个实验,《
Tiny4412之C语言实现流水灯》的基础上修改。start.S大部分相同,只是增加一条函数调用语句1
bl system_clock_init
如下图所示:
启动文件链接脚本system_clock.lds的内容和上一个实验key.lds完全相同,只把名字改了改;Makefile的内容也大部分一样,也只是改了改里边文件的名字,led.c文件和LED实验时完全相同,
新增加了文件system_clock.c,代码如下:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
#define CLK_SRC_CPU (*(volatile unsigned int *)0x10044200)
#define CLK_DIV_CPU0 (*(volatile unsigned int *)0x10044500)
#define CLK_DIV_CPU1 (*(volatile unsigned int *)0x10044504)
#define CLK_SRC_DMC (*(volatile unsigned int *)0x10040200)
#define CLK_DIV_DMC0 (*(volatile unsigned int *)0x10040500)
#define CLK_DIV_DMC1 (*(volatile unsigned int *)0x10040504)
#define CLK_SRC_TOP0 (*(volatile unsigned int *)0x1003C210)
#define CLK_SRC_TOP1 (*(volatile unsigned int *)0x1003C214)
#define CLK_DIV_TOP (*(volatile unsigned int *)0x1003C510)
#define CLK_SRC_LEFTBUS (*(volatile unsigned int *)0x10034200)
#define CLK_DIV_LEFTBUS (*(volatile unsigned int *)0x10034500)
#define CLK_SRC_RIGHTBUS (*(volatile unsigned int *)0x10038200)
#define CLK_DIV_RIGHTBUS (*(volatile unsigned int *)0x10038500)
#define APLL_LOCK (*(volatile unsigned int *)0x10044000)
#define MPLL_LOCK (*(volatile unsigned int *)0x10044008)
#define EPLL_LOCK (*(volatile unsigned int *)0x1003C010)
#define VPLL_LOCK (*(volatile unsigned int *)0x1003C020)
#define APLL_CON1 (*(volatile unsigned int *)0x10044104)
#define APLL_CON0 (*(volatile unsigned int *)0x10044100)
#define MPLL_CON0 (*(volatile unsigned int *)0x10040108)
#define MPLL_CON1 (*(volatile unsigned int *)0x1004010c)
#define EPLL_CON2 (*(volatile unsigned int *)0x1003C118)
#define EPLL_CON1 (*(volatile unsigned int *)0x1003C114)
#define EPLL_CON0 (*(volatile unsigned int *)0x1003C110)
#define VPLL_CON0 (*(volatile unsigned int *)0x1003C120)
#define VPLL_CON1 (*(volatile unsigned int *)0x1003C124)
#define VPLL_CON2 (*(volatile unsigned int *)0x1003C128)
void
system_clock_init(
void
)
{
CLK_SRC_CPU = 0x0;
}
没什么可说的,很简单,前部分是后期会用到的一些寄存器地址的定义,主要的是下边system_clock_init这个函数,在这个函数中将CLK_SRC_CPU寄存器的值设为0,这样ARMCLK的频率将走下面这条路径,设置为24MHZ:
二、编译、烧写实验按照前几节介绍的方法,将程序上传到服务器编译,并烧写到SD卡上,给开发板上电,可以明显感觉到LED闪烁的频率大大降低,说明我们设置的时钟起作用了,这里就不上图了(上了图大家也看不出来)。
第二个小实验实现的目标:重新设置APLL,让 CPU 运行于1.4GHz频率,观察 LED 闪烁是否变快
一、程序说明文件同第一个小实验,只是在它的基础上对system_clock.c文件中的system_clock_init函数进行修改:12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
void
system_clock_init(
void
)
{
CLK_SRC_CPU = 0x0;
APLL_LOCK = 270 * 3;
CLK_DIV_CPU0 = ((0<<28) | (2<<24) | (1<<20) | (6<<16) | (7<<12) | (7<<8) | (3<<4) | 0);
CLK_DIV_CPU1 = ((5 << 8) |(0 << 4) | (6));
APLL_CON1 = 0x00803800;
APLL_CON0 = (1<<31 | 0xAF<<16 | 3<<8 | 0x0);
CLK_SRC_CPU = 0x01000001;
}
注释的已经很清楚了,
需要注意的就是:上电之后 IROM设置了APLL ,CPU工作于APLL提供的时钟;当我们要改变 APLL时,要先使得CPU工作于另一个时钟源,即晶振。设置完APLL后,再让CPU重新工作于APLL提供的时钟。
二、编译、烧写实验按照前几节介绍的方法,将程序上传到服务器编译,并烧写到SD卡上,给开发板上电,可以明显感觉到LED闪烁的频率大大提高(比《
Tiny4412之C语言实现流水灯》时闪烁的还要快,因为当时CPU运行在400MHZ,现在运行在1.4GHZ),说明我们设置的时钟起作用了,这里就不上图了(上了图大家也看不出来)。
第三个小实验实现的目标:参考厂家提供的u-boot代码,设置所有PLL供后续章节使用
一、程序说明文件同第一个小实验,只是在它的基础上对system_clock.c文件中的system_clock_init函数进行修改:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
void
system_clock_init(
void
)
{
CLK_SRC_CPU = 0x0;
CLK_DIV_DMC0 = ((0x0 << 28) | (0x0 << 24) | (0x1 << 20) | (0x1 << 16) | (0x1 << 12) | (0x1 << 8) | (0x1 << 4) | (0x3));
CLK_DIV_DMC1 = 0x07071713;