s5pv210汇编实现时钟代码

1.6.6 章节

①。  先选择不使用PLL. 让外部24MHz 原始时钟直接过去,绕过APLL那条路

.global clock_init
clock_init:
	ldr	r0, =ELFIN_CLOCK_POWER_BASE
	
	// 1 设置各种时钟开关,暂时不使用PLL
	ldr	r1, =0x0
	// 芯片手册P378 寄存器CLK_SRC:Select clock source 0 (Main)
	str	r1, [r0, #CLK_SRC0_OFFSET]		

ldr    r0, =ELFIN_CLOCK_POWER_BASE    # 所有寄存器地址都是在ELFIN_CLOCK_POWER_BASE累加就可以了,这里是基础寄存器地址时钟几大寄存器的
    
    // 1 设置各种时钟开关,暂时不使用PLL
    ldr    r1, =0x0
    // 芯片手册P378 寄存器CLK_SRC:Select clock source 0 (Main)
    str    r1, [r0, #CLK_SRC0_OFFSET]                //基地址+偏移量 

# 在ELFIN_CLOCK_POWER_BASE   的基础上加上 CLK_SRC0_OFFSET 得到 r1地址

#  r0 就是CLK_SRC0 一共32位置,设置所有的位都为0 

** CLK_SRC0寄存器就是设置MUX开关,之类把改寄存器设置全为0, 主要bit0 和 bit4 设置为0,表示APLL 和 MPLL 寄存器 EPLL 暂时都不开启 

这里主要是 APLL_SEL 0  就是 FINPLL , 走下面的路线,上电的时候不经过倍频,默认24M

如果 APLL_SEL 1 那么 经过 APLL FOUT 输出 

 

②。 设置锁定时间, iROM 初始化系统时钟以后。 

	// 2 设置锁定时间,使用默认值即可
	// 设置PLL后,时钟从Fin提升到目标频率时,需要一定的时间,即锁定时间
     // 文档给的是0x00000FFF , demo源码给的是 0x0000FFFF	 没关系
// 给一个最长的是FFF 
	ldr	r1,	=0x0000FFFF					
	str	r1,	[r0, #APLL_LOCK_OFFSET]				
	str r1, [r0, #MPLL_LOCK_OFFSET]	 	

一开始的时候没有经过 APLL,后面要经过APLL,  设置锁定时间,后面一开APLL,不是马上让时钟过来,   延时后, 才让时钟过来,默认时间是  0xFFF , 现在给的最大 是 0xFFFF , pll从24M到1G需要时间, 就是水龙头一打开混的,过一段实际在接水

 原理图说明:

 ③。 设置分频,得到1G的时钟以后分频,决定由PLL出来的最高时钟如何分频得到各个分时钟

	// 3 设置分频
	// 清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]

   ldr r1, [r0, #CLK_DIV0_OFFSET]           就是  CLK_DIV0寄存器  设置为 0x14131440                        0x14131440                 就是  00010100000100110001010001000000

 0001 【30:28】: PCLK_PSYS_RATIO  =1 

 DIVPCLKP clock divider ratio,  PCLK_PSYS = HCLK_PSYS / (PCLK_PSYS_RATIO + 1)
PCLK_PSYS = HCLK_PSYS / (1+ 1)
如何看:上面框框中的div-PCLK_P 对应  下面框框中的 div-PCLK_P 

 div这里写错了,应该是div-PCLK_P   SYS_RATIO  

0100   [27:24]
DIVHCLKP clock divider ratio,
HCLK_PSYS = MOUT_PSYS / (HCLK_PSYS_RATIO + 1)

HCLK_PSYS = MOUT_PSYS / (4 + 1)

PCLK_DSYS_RATIO   [22:20]   001 
DIVPCLKD clock divider ratio,
PCLK_DSYS = HCLK_DSYS / (PCLK_DSYS_RATIO + 1)

PCLK_DSYS = HCLK_DSYS / (1+ 1)

........

HCLK_MSYS_RATIO
[10:8]   100 
DIVHCLKM clock divider ratio,
HCLK_MSYS = ARMCLK / (HCLK_MSYS_RATIO + 1)

HCLK_MSYS = ARMCLK / (4+ 1)

APLL_RATIO
[2:0]      
DIVAPLL clock divider ratio,
ARMCLK = MOUT_MSYS / (APLL_RATIO + 1)

ARMCLK = MOUT_MSYS / (0 + 1)

MOUT  mysys= 1G ,      DIVapll =1     最终 ARMCLK  = 1G   【重点理解】

设置以后的典型值:

 (3).  各个时钟的典型值 :   
• freq(ARMCLK) = 1000 MHz        1G
• freq(HCLK_MSYS) = 200 MHz
• freq(HCLK_IMEM) = 100 MHz
• freq(PCLK_MSYS) = 100 MHz
• freq(HCLK_DSYS) = 166 MHz
• freq(PCLK_DSYS) = 83 MHz
• freq(HCLK_PSYS) = 133 MHz
• freq(PCLK_PSYS) = 66 MHz
• freq(SCLK_ONENAND) = 133 MHz, 166 MHz

④。设置PLL , 主要设置PLL的倍频系统, 决定输入端24MHz 的原始频率可以得到多大的输出频率。 设置以后输出 ARMCLK为 1GHz   设置CON 

// 这些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)	

// 4 设置PLL
	// 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]
// MPLL_CON 0xE010_0108  
// #MPLL_CON_OFFSET               #define MPLL_CON_OFFSET			0x108

FOUT = MDIV*FIN/(PDIV*2^(SDIV-1))=0x7d*24/(0x3*2^(1-1))=1000 MHz  

FOUT 就是1G , FIN就是 24 确定的  MDIV= 0x7d  PDIV=0x3这些都是三星给的 

上面的7d这些, 数据手册有参考表!!! 

#define set_pll(mdiv, pdiv, sdiv)    (1<<31 | mdiv<<16 | pdiv<<8 | sdiv)
#define APLL_VAL            set_pll(APLL_MDIV,APLL_PDIV,APLL_SDIV)  把MPS 放到APLL_VAL  

1.6.7.章节: mpll设置 

         

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

//  这些都是三星给的输出1G  时钟,对pll有了解三星内部的人, 不是斗出来的!!

--上面给的0xc8不是的, 结果计算出来1.6G ,是0x7d 根据 3.3.1. 推荐表, 

//  把这些值放入APLL_CON0寄存器中 , 这些都需要M , P,S设置, 都手册去找

//   全部用宏定义定义出来 MPS都查数据手册中典型始终配置得来的,三星推荐的,测试了很多次,最稳定

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

⑤。  打开PLL 。 设置MUX开关    前。、面4步已经设置好了所有的开关和分频系数,本步骤打开PLL后PLL开始工作,锁定频率后输出,然后经过分频得到各个频率 

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

	mov	pc, lr

CLK_SRC0 , 

0x10001111   =  00010000000000000001000100010001

 MUXFLASH = 1 

 MUX_PSYS =0  

 Control MUX_DSYS  = 0 

Control MUX_MSYS =  0
Control MUXVPLL =1 
   根据上面名称, 上面值 0x10001111 找到图上位mux位置 一 一 对应

APLL 出来1000 ,  ARMCLK = 1000  HCLK_MSYS =  1000/5 = 200 ....  

MPLL = 667  , 

最后算出来的就是典型值:

5. 汇编 完整代码:

// 时钟控制器基地址
#define ELFIN_CLOCK_POWER_BASE		0xE0100000	

// 时钟相关的寄存器相对时钟控制器基地址的偏移值
#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

// 这些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)


.global clock_init
clock_init:
	ldr	r0, =ELFIN_CLOCK_POWER_BASE
	
	// 1 设置各种时钟开关,暂时不使用PLL
	ldr	r1, =0x0
	// 芯片手册P378 寄存器CLK_SRC:Select clock source 0 (Main)
	str	r1, [r0, #CLK_SRC0_OFFSET]				

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

	// 3 设置分频
	// 清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]

	// 4 设置PLL
	// 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]

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

	mov	pc, lr

6. 完整 c代码实现:

// 时钟控制器基地址
#define ELFIN_CLOCK_POWER_BASE		0xE0100000	

// 时钟相关的寄存器相对时钟控制器基地址的偏移值
#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

// 这些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)


#define REG_CLK_SRC0	(ELFIN_CLOCK_POWER_BASE + CLK_SRC0_OFFSET)
#define REG_APLL_LOCK	(ELFIN_CLOCK_POWER_BASE + APLL_LOCK_OFFSET)
#define REG_MPLL_LOCK	(ELFIN_CLOCK_POWER_BASE + MPLL_LOCK_OFFSET)
#define REG_CLK_DIV0	(ELFIN_CLOCK_POWER_BASE + CLK_DIV0_OFFSET)
#define REG_APLL_CON0	(ELFIN_CLOCK_POWER_BASE + APLL_CON0_OFFSET)
#define REG_MPLL_CON	(ELFIN_CLOCK_POWER_BASE + MPLL_CON_OFFSET)

#define rREG_CLK_SRC0	(*(volatile unsigned int *)REG_CLK_SRC0)
#define rREG_APLL_LOCK	(*(volatile unsigned int *)REG_APLL_LOCK)
#define rREG_MPLL_LOCK	(*(volatile unsigned int *)REG_MPLL_LOCK)
#define rREG_CLK_DIV0	(*(volatile unsigned int *)REG_CLK_DIV0)
#define rREG_APLL_CON0	(*(volatile unsigned int *)REG_APLL_CON0)
#define rREG_MPLL_CON	(*(volatile unsigned int *)REG_MPLL_CON)


void clock_init(void)
{
	// 1 设置各种时钟开关,暂时不使用PLL
	rREG_CLK_SRC0 = 0x0;
	
	// 2 设置锁定时间,使用默认值即可
	// 设置PLL后,时钟从Fin提升到目标频率时,需要一定的时间,即锁定时间
	rREG_APLL_LOCK = 0x0000ffff;
	rREG_MPLL_LOCK = 0x0000ffff;
	
	// 3 设置分频
	// 清bit[0~31]
	rREG_CLK_DIV0 = 0x14131440;
	
	// 4 设置PLL, 设置 pll锁相环
	// FOUT = MDIV*FIN/(PDIV*2^(SDIV-1))=0x7d*24/(0x3*2^(1-1))=1000 MHz
	rREG_APLL_CON0 = APLL_VAL;
	// FOUT = MDIV*FIN/(PDIV*2^SDIV)=0x29b*24/(0xc*2^1)= 667 MHz
	rREG_MPLL_CON = MPLL_VAL;
	
	// 5 设置各种时钟开关,使用PLL,就是设置Mux开关
	rREG_CLK_SRC0 = 0x10001111;
}

源码地址:s5pv210汇编和C实现时钟代码.zip-C文档类资源-CSDN下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值