Chinaunix首页 | 论坛 | 博客
  • 博客访问: 29932483
  • 博文数量: 230
  • 博客积分: 2868
  • 博客等级: 少校
  • 技术积分: 2223
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-08 21:48
个人简介

Live & Learn

文章分类

全部博文(230)

文章存档

2022年(2)

2019年(5)

2018年(15)

2017年(42)

2016年(24)

2015年(13)

2014年(1)

2012年(5)

2011年(58)

2010年(56)

2009年(9)

我的朋友

分类: 嵌入式

2011-03-22 15:26:41

1:时钟问题,  以前总是一知半解,这次彻底搞明白了,2440的PLL分为两种,MPLL和UPLL,MPLL用来做系统时钟,UPLL则是USB时钟(必须为 48M),两种时钟的计算方法一样:

           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在串口就可以打印出正常字符了。

阅读(5111) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~