Live & Learn
分类: 嵌入式
2011-03-22 15:26:41
Mpll=(m×Fosc×2)÷(p×2^s) 记住是2的s次幂 2410 不必乘2
m=MDIV+8
p=PDIV+2
s=SDIV
Upll=(m×Fosc×2)÷(p×2^s)
这里的m,p,s 分别都在MPLLCON 寄存器的[19:12],[9:4],[1:0]或UPLLCON寄存器的[19:12],[9:4],[1:0]里进行设置, 他们的取值详见官方的推荐表:
MPLLCON和UPLLCON的值根据上面的两个公式计算而来,而这两个寄存器的设置值决定了系统的工作主频,和USB的主时钟分频前的频率。
如果用到USB或串口的话,那就需要小心的设置CLKDIVN寄存器了,这个寄存器的DIVN_UPLL位决定了USB的时钟,且必须为48M,
例如:
你的UPLL设置为48M时 则不需要分频,DIVN_UPLL位为0就可以了,反之,如果你的UPLL设置为96M时,为保持USB时钟为48M,这里的DIVN_UPLL必须设置 为1.
HDIVN设置则要稍微复杂些,需要根据CAMDIVN[9]来综合决定,原则是首先确定你想要的HCLK频率,然后再结合系统的频率限制合理的来设置。
PDIVN设置直接决定你的串口能否正常工作了,同样举个例子:
当前系统的主频为MPLL 为400M ,UPLL为48M,CAMDIVN[9]位为0,那么想得到115200的波特率,CLKDIVN寄存器应该 设置为多少?首先可以确定DIVN_UPLL位为0,解释见上面,接下来确定HDIVN和PDIVN了,s3c24x0的波特率计算公式为
UBRDIV=PCLK/(baudrate×16)-1
波特率直接和PCLK有关,假设UBRDIV设置为0x1A,则PCLK为50M,是PCLK的1/8,所以 HDIVN=2 PDIVN=1。
在SMDK2410基础上进行2440的移植时钟部分要注意两个地方,第一个是start.s里关于时钟的设置,还有一个是speed.c里 get_HCLK函数和get_PLLCLK函数。需要你根据相应的时钟寄存器进行修改。
speed.c中的get_FCLK,get_PCLK等函数都修改好了,可是串口一直出现乱码。查看MPLLCON, CLKDIVN,寄存器的值都是正确,就是UBRDIV0不正确,源代码找了好久都找不到错来。这问题一直纠缠了好几天。后来发现是在 get_PLLCLK中出错。
原来代码:
static ulong get_PLLCLK(int pllreg)
{
struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
ulong r, m, p, s;
if (pllreg == MPLL)
r = readl(&clk_power->MPLLCON);
else if (pllreg == UPLL)
r = readl(&clk_power->UPLLCON);
else
hang();
m = ((r & 0xFF000) >> 12) + 8; //200
p = ((r & 0x003F0) >> 4) + 2; //3
s = r & 0x3; //2
#if defined(CONFIG_S3C2440)
if (pllreg == MPLL)
{
return ((CONFIG_SYS_CLK_FREQ * m * 2) /(p << s));
}
else if (pllreg == UPLL)
#endif
return (CONFIG_SYS_CLK_FREQ * m) / (p << s);
}
问题就出在: return ((CONFIG_SYS_CLK_FREQ * m * 2) /(p << s));
CONFIG_SYS_CLK_FREQ为12MHZ , 12M*200*2结果已经超出了32bit的范围而导致数据溢出了,所以结果出错了,悲剧,浪费了我这么多时间。
修改方法:
ulong clk_tmp = (CONFIG_SYS_CLK_FREQ * m )/(p << s);
return (clk_tmp*2);
//return ((CONFIG_SYS_CLK_FREQ * m * 2) /(p << s));
这样u-boot在串口就可以打印出正常字符了。