《朱老师物联网大讲堂》学习笔记
学习地址:www.zhulaoshi.org
这次的代码,可以在上次重定位的代码基础上进行添加,或者icache设置代码基础上增加,
这里我是选择的是重定位的代码。
新增代码的位置,选择的是关看门狗后。
bl clock_init
初始化时钟单独通过一个函数来实现,
通过这句代码跳转到对应函数。
为了能更好的解释代码,我选择了在解释代码的同时,在旁边附上对应数据手册的图片。
那么开始吧!
#define ELFIN_CLOCK_POWER_BASE0xE0100000
在这里定了一个基地址,通过使用 基地址 + 偏移地址 的方法来定位到我们要访问的寄存器位,
这个用法在重定位也用过,
对于那些寄存器功能相关,地址相连的寄存器,很适合使用这种方法。
见数据手册P367,有没有看到第一个32位寄存器的地址就是我上面那句话的值,
这里只是为了说明,所以就没把后面那好几大页贴出来。
后面就是偏移量的宏定义,
#define APLL_LOCK_OFFSET 0x00
#define MPLL_LOCK_OFFSET 0x08
#define APLL_CON0_OFFSET 0x100
#define APLL_CON1_OFFSET 0x104
#define MPLL_CON_OFFSET 0x108
#define CLK_SRC0_OFFSET 0x200
#define CLK_SRC1_OFFSET 0x204
#define CLK_SRC2_OFFSET 0x208
#define CLK_SRC3_OFFSET 0x20c
#define CLK_SRC4_OFFSET 0x210
#define CLK_SRC5_OFFSET 0x214
#define CLK_SRC6_OFFSET 0x218
#define CLK_SRC_MASK0_OFFSET 0x280
#define CLK_SRC_MASK1_OFFSET 0x284
#define CLK_DIV0_OFFSET 0x300
#define CLK_DIV1_OFFSET 0x304
#define CLK_DIV2_OFFSET 0x308
#define CLK_DIV3_OFFSET 0x30c
#define CLK_DIV4_OFFSET 0x310
#define CLK_DIV5_OFFSET 0x314
#define CLK_DIV6_OFFSET 0x318
#define CLK_DIV7_OFFSET 0x31c
#define CLK_DIV0_MASK 0x7fffffff
#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)
.global clock_init
clock_init:
ldr r0, =ELFIN_CLOCK_POWER_BASE
ldr r1, =0x0
str r1, [r0, #CLK_SRC0_OFFSET]
这里暂时不是用PLL进行倍频,
看CLK_SRC0的第0位。
ldr r1, =0x0000FFFF
str r1,[r0, #APLL_LOCK_OFFSET]
str r1, [r0, #MPLL_LOCK_OFFSET]
这几句,设置锁定时间为FFFF,不过默认的是FFF,详细见下图数据手册,
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]
这里是在设置分频,试着把0x14131440换算成二进制就是
0001 0100 0001 0011 0001 0100 0100 0000
在结合数据手册可以得到如下关系
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
str r1, [r0, #APLL_CON0_OFFSET]
ldr r1, =MPLL_VAL
str r1, [r0, #MPLL_CON_OFFSET]
这里就是设置PLL倍频参数了,不过APLL_VAL是什么鬼啊?
嘿嘿~是个宏定义。
#define APLL_MDIV 0x7d // 125#define MPLL_VAL set_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]
ldr r2, =0x10001111
orr r1, r1, r2
str r1, [r0, #CLK_SRC0_OFFSET]
mov pc, lr
有一个地方,orr,也是有些想不明白,感觉多次一举,
不过根据下面一节C语言实现,可以这样理解,
这是个32位的寄存器,
怕赋值的时候,有些为0的位没设置到,
不过这里设置的值其实已经对这些位的设置涉及到了,
所以可以不用管了,
不过这次思考的过程还是挺有意义。