汇编实现时钟设置代码详解1~2

《朱老师物联网大讲堂》学习笔记

学习地址:www.zhulaoshi.org


这次的代码,可以在上次重定位的代码基础上进行添加,或者icache设置代码基础上增加,

这里我是选择的是重定位的代码。


新增代码的位置,选择的是关看门狗后。

blclock_init

初始化时钟单独通过一个函数来实现,

通过这句代码跳转到对应函数。


为了能更好的解释代码,我选择了在解释代码的同时,在旁边附上对应数据手册的图片。

那么开始吧!


#define ELFIN_CLOCK_POWER_BASE0xE0100000

在这里定了一个基地址,通过使用 基地址 + 偏移地址 的方法来定位到我们要访问的寄存器位,

这个用法在重定位也用过,

对于那些寄存器功能相关,地址相连的寄存器,很适合使用这种方法。

见数据手册P367,有没有看到第一个32位寄存器的地址就是我上面那句话的值,

这里只是为了说明,所以就没把后面那好几大页贴出来。


后面就是偏移量的宏定义,

#define APLL_LOCK_OFFSET0x00
#define MPLL_LOCK_OFFSET0x08


#define APLL_CON0_OFFSET0x100
#define APLL_CON1_OFFSET0x104
#define MPLL_CON_OFFSET0x108


#define CLK_SRC0_OFFSET0x200
#define CLK_SRC1_OFFSET0x204
#define CLK_SRC2_OFFSET0x208
#define CLK_SRC3_OFFSET0x20c
#define CLK_SRC4_OFFSET0x210
#define CLK_SRC5_OFFSET0x214
#define CLK_SRC6_OFFSET0x218
#define CLK_SRC_MASK0_OFFSET0x280
#define CLK_SRC_MASK1_OFFSET0x284


#define CLK_DIV0_OFFSET0x300
#define CLK_DIV1_OFFSET0x304
#define CLK_DIV2_OFFSET0x308
#define CLK_DIV3_OFFSET0x30c
#define CLK_DIV4_OFFSET0x310
#define CLK_DIV5_OFFSET0x314
#define CLK_DIV6_OFFSET0x318
#define CLK_DIV7_OFFSET0x31c


#define CLK_DIV0_MASK0x7fffffff


#define APLL_MDIV      0x7d// 125
#define APLL_PDIV       0x3
#define APLL_SDIV       0x1


#define MPLL_MDIV0x29b// 667
#define MPLL_PDIV0xc
#define MPLL_SDIV0x1


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


.global clock_init
clock_init:
ldrr0, =ELFIN_CLOCK_POWER_BASE

ldr r1, =0x0
strr1, [r0, #CLK_SRC0_OFFSET]

这里暂时不是用PLL进行倍频,

看CLK_SRC0的第0位。



ldr r1,=0x0000FFFF
strr1,[r0, #APLL_LOCK_OFFSET]
str r1, [r0, #MPLL_LOCK_OFFSET]

这几句,设置锁定时间为FFFF,不过默认的是FFF,详细见下图数据手册,



ldr r1, [r0, #CLK_DIV0_OFFSET]
ldrr2, =CLK_DIV0_MASK
bicr1, r1, r2
ldrr2, =0x14131440
orrr1, r1, r2
strr1, [r0, #CLK_DIV0_OFFSET]

这里是在设置分频,试着把0x14131440换算成二进制就是

00010100 00010011 00010100 01000000

在结合数据手册可以得到如下关系

PCLK_PSYS = HCLK_PSYS / (PCLK_PSYS_RATIO + 1) 这里对应为(1+1)
HCLK_PSYS = MOUT_PSYS / (HCLK_PSYS_RATIO + 1)这里对应为(1+4
PCLK_DSYS = HCLK_DSYS / (PCLK_DSYS_RATIO + 1) 这里对应为(1+1)
HCLK_DSYS = MOUT_DSYS / (HCLK_DSYS_RATIO + 1) 这里对应为(1+3)
PCLK_MSYS = HCLK_MSYS / (PCLK_MSYS_RATIO + 1) 这里对应为(1+1)
HCLK_MSYS = ARMCLK / (HCLK_MSYS_RATIO + 1)这里对应为(1+4)
SCLKA2M = SCLKAPLL / (A2M_RATIO + 1)这里对应为(1+4)
ARMCLK = MOUT_MSYS / (APLL_RATIO + 1)这里对应为(1+0)

对应的数据手册为


这里的设置弄bic,orr什么的,让人有些不是很明白,

不过在下一节用C语言实现中,解释了下,可能是由于以前版本Reserved位的原因留下的,

不过这些不是很关键,所以没事。



ldr r1, =APLL_VAL
strr1, [r0, #APLL_CON0_OFFSET]
ldrr1, =MPLL_VAL
strr1, [r0, #MPLL_CON_OFFSET]

这里就是设置PLL倍频参数了,不过APLL_VAL是什么鬼啊?

嘿嘿~是个宏定义。

#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_VALset_pll(MPLL_MDIV,MPLL_PDIV,MPLL_SDIV)


这里有个不同于前面设置的地方,就是这些参数,比如参数M,P,S的设置,

不是单纯的依靠数据手册中的公式就可以了,那个只是纯数学的角度来看的,

实际上,这里还涉及到元器件自身适合的工作条件。

所以具体设置多少,不是你你软件工程师能够决定的,你需要去看看相关推荐值,见下图。


这里只列出了两个,在数据手册p357.

解释一下,如果你想要到达1GHz,也就是FOUT = 1000.00MHz,

相应的P,M,S推荐值为3,123,1,

FIN在我们这个开发板是固定的24MHz。


ldr r1, [r0, #CLK_SRC0_OFFSET]
ldrr2, =0x10001111
orrr1, r1, r2
strr1, [r0, #CLK_SRC0_OFFSET]


mov pc, lr

有一个地方,orr,也是有些想不明白,感觉多次一举,

不过根据下面一节C语言实现,可以这样理解,

这是个32位的寄存器,

怕赋值的时候,有些为0的位没设置到,

不过这里设置的值其实已经对这些位的设置涉及到了,

所以可以不用管了,

不过这次思考的过程还是挺有意义。




MSYS domain comprises(包含) Cortex A8 processor,


Figure 3-3shows block diagram of the clock generation logic. An externalcrystal clock is connected to the
oscillation(震荡) amplifier(放大器).


The clock generator block also includes a built-in logic to stabilize the clock frequency after each system reset, since
clock takes time before stabilizing.

时钟发生器块还包括一个内置的逻辑,以稳定每个系统复位后的时钟频率,因为时钟稳定之前需要时间。