您的位置:首页 > 编程语言

[smart210] 通过PLL设置各时钟频率的方法以及代码注释

2013-07-21 17:00 656 查看
平台:smart210(tiny210v2)

CPU:S5PV210

目标:

设置APLL (提供MSYS domain 与DSYS domain 下各时钟的来源,最高1Ghz)

设置MPLL(提供MSYS domain 与DSYS domain 下各时钟的来源,最高2Ghz)

设置EPLL(Audio相关时钟)

设置VPLL(Video相关时钟,54Mhz)

知识储备:

1. MSYS主要为CPU,DRAM控制器,3D,IRAM,IROM,中断控制器等提供时钟

DSYS主要为显示相关部件FIMC,FIMD,JPEG,Multimedia IPs提供时钟

PSYS为外设I2S,SPI,I2C,UART等提供时钟

2. 官方文档有时钟domain的【时钟继承图】(自造词。。)



从图上我们能发现,MSYS domain包含有ARMCLK、HCLK_MSYS、PCLK_MSYS、HCLK_IMEM、SCLK_DMC0 这几个时钟信号,追本溯源,这些时钟信号主要都源于APLL或者MPLL经过各种分频倍频环节得到的,而其他的CLOCK domain下的子时钟也如此,换句话说,只要先把外置时钟源FIN=24Mhz转换成我们需要的APLL,MPLL这两个主要的PLL时钟,其余大部分的时钟我们就能轻松设置了。

3 官方还给出了直观的各子时钟的设置来源与推荐值:



4 同样的,官方P364给出了从FIN到设置最终子时钟的整个流程:

①打开APLL:APLL_CON0[31]=1;这里能看到bit31是使能控制端



②等待PLL锁定

③在锁定时钟稳定后,令APLL输出:CLK_SRC0[0]=1;这里能看到bit0(APLL_SEL)控制MUX_APLL的时钟输出,同时bit16(MUX_MSYS_SEL)控制了MUX_MSYS的输出


④改变分频值,设置PMS,其实就是PDIV,MDIV,SDIV的值,相关寄存器仍是APLL_CON0,参考步骤①的附图,而设置的PMS有什么用呢?我们最终要得到的是APLL的时钟,这个时钟通过FIN与PMS三个分频系数计算得到,使用的是下面这条公式 FOUT=MDIV*FIN/(PDIV*2^(SDIV-1)) 。下面附图给出了公式以及PMS的取值范围:



⑤设置各CLOCK domain下的子时钟的分频比,从而确定了最终的MSYS domain、PSYS domain与DSYS domain各子时钟的频率,相关寄存器CLK_DIV0、CLK_DIV1、CLK_DIV2,这里贴出主要的CLK_DIV0



5.好了,现在整理一下那5个步骤,其实顺序可以打乱,只要设置得当就行,这5个步骤中,有几个关键点要注意的:

①初始输入频率FIN为24Mhz,通过设置APLL_CON来控制PLL使能,以及设置PMS的值,设置完这些,我们基本上得到了APLL的FOUT,一般都是先想好需要多快的FOUT,再去设置PMS的值的。

②获取到FOUT APLL之后,通过设置CLK_SRC0的相关位把FOUT APLL作为MUX APLL的输出(从最上面那个【时钟继承图】上可以看出MUX APLL可以选择FIN或者FOUT APLL作为输出,输出的时钟名为SCLK_APLL )同时,我们还要通过设置CLK_SRC0的相关位如MUX_MSYS_SEL(【时钟继承图】上的又一个多路复用器)将SCLK_APLL作为该MUX的输出,输出的时钟名为MOUT_MSYS

③最后就是通过设置CLK_DIV0来设置各子时钟的分频比了,可以发现,只要有了MOUT_MSYS,MSYS domain里面的子时钟都能通过设置这个寄存器而得到!

6.下面再不厌其烦地给出直观的讲解图



终于到了代码阶段了,有了上面的知识储备,程序的事也是手到擒来是吧!

1.首先start.s关好看门狗,设置堆栈后,进入clock_init

.global _start
_start:
ldr	r0, =0xE2700000
mov	r1, #0
str	r1, [r0]
ldr	sp, =0x40000000
bl clock_init
bl main
halt:
b halt

2.clock.c中,有写好的clock_init函数

// 时钟相关寄存器
#define APLL_LOCK 			( *((volatile unsigned long *)0xE0100000) )
#define MPLL_LOCK 			( *((volatile unsigned long *)0xE0100008) )

#define APLL_CON0 			( *((volatile unsigned long *)0xE0100100) )
#define APLL_CON1 			( *((volatile unsigned long *)0xE0100104) )
#define MPLL_CON 			( *((volatile unsigned long *)0xE0100108) )

#define CLK_SRC0 			( *((volatile unsigned long *)0xE0100200) )
#define CLK_SRC1 			( *((volatile unsigned long *)0xE0100204) )
#define CLK_SRC2 			( *((volatile unsigned long *)0xE0100208) )
#define CLK_SRC3 			( *((volatile unsigned long *)0xE010020c) )
#define CLK_SRC4 			( *((volatile unsigned long *)0xE0100210) )
#define CLK_SRC5 			( *((volatile unsigned long *)0xE0100214) )
#define CLK_SRC6 			( *((volatile unsigned long *)0xE0100218) )
#define CLK_SRC_MASK0 		( *((volatile unsigned long *)0xE0100280) )
#define CLK_SRC_MASK1 		( *((volatile unsigned long *)0xE0100284) )

#define CLK_DIV0 			( *((volatile unsigned long *)0xE0100300) )
#define CLK_DIV1 			( *((volatile unsigned long *)0xE0100304) )
#define CLK_DIV2 			( *((volatile unsigned long *)0xE0100308) )
#define CLK_DIV3 			( *((volatile unsigned long *)0xE010030c) )
#define CLK_DIV4 			( *((volatile unsigned long *)0xE0100310) )
#define CLK_DIV5 			( *((volatile unsigned long *)0xE0100314) )
#define CLK_DIV6 			( *((volatile unsigned long *)0xE0100318) )
#define CLK_DIV7 			( *((volatile unsigned long *)0xE010031c) )

#define CLK_DIV0_MASK		0x7fffffff

#define APLL_MDIV       	0x7d
#define APLL_PDIV       	0x3
#define APLL_SDIV      	 	0x1
#define MPLL_MDIV			0x29b
#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 PLL_OFF		//屏蔽此句才能顺利启用PLL设置

void clock_init()
{
// 1 设置各种时钟开关,暂时不使用PLL
CLK_SRC0 = 0x0;	//根据手册显示,0代表使用FINPLL即默认外置时钟源(此时FIN=24Mhz)
//CLK_SRC0寄存器中控制位:[0]->APLL_SEL,[4]->MPLL_SEL,[8]->EPLL_SEL,[12]->VPLL_SEL
#ifndef PLL_OFF

// 2 设置锁定时间,使用默认值即可
// 设置PLL后,时钟从Fin提升到目标频率时,需要一定的时间,即锁定时间
APLL_LOCK = 0x0000FFFF;
MPLL_LOCK = 0x0000FFFF;

// 3 设置分频
CLK_DIV0 = 0x14131440;

//以APLL为例,这里CLK_DIV0设置了APLL_RATIO的值为0,则根据公式 ARMCLK=MOUT_MSYS/(APLL_RATIO + 1)=MOUT_MSYS

// 4 设置PLL
//解析为APLL_CON0=APLL_VAL=(1<<31|0x7d<<16|0x3<<8|0x1)意思就是APLL_CON0寄存器[31]位使能,允许PLL控制
//[25:16]位为MDIV(倍频因子)值,[13:8]为PDIV(分频因子)值,[2:0]为SDIV值,FOUT计算公式如下
// FOUT= MDIV * FIN / (PDIV*2^(SDIV-1)) = 0x7d*24/(0x3*2^(1-1))=1000 MHz
//上式采用MDIV=0x7d(125),PDIV=0x3(3),SDIV=0x1(1)
APLL_CON0 = APLL_VAL;
// FOUT = MDIV*FIN/(PDIV*2^SDIV)=0x29b*24/(0xc*2^1)= 667 MHz
MPLL_CON  = MPLL_VAL;

// 5 设置各种时钟开关,使用PLL
CLK_SRC0 = 0x10001111;
#endif
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐