关于系统时钟慢的解决方法,芯片是r8610,内核是linux-3.0.4.下面是自己的解决过程,记录下来,希望对也做这一块的同学有所帮助,错误之处,在所难免,欢迎指出啊。
2月前移植的linux-3.0.4又有问题啦,系统时钟比硬件时间慢,而且慢的很多。
今天又听到消息啦,系统时钟慢。于是我那一台设备,接串口,验证。
首先date设置系统时钟,然后hwclock -w同步。然后计时。经过验证,结论如下:
大概每30分钟慢236s,也就是说每7.6s就会慢1s,12.7%。我靠,慢的也太厉害啦。
首先,我怀疑添加的驱动有问题,把驱动,一些应用都关了。只跑系统。
继续测试,涛声依旧啊。基本一样。
linux系统时间和硬件时间是有一些偏差,由于内核定时器,锁机制的应用,是可能产生一些差距,但是这12.7%确实有点高啊。
先google查找,看看有没有预见同样情况的,一查不要紧,这问题很多啊,看样linux系统的时间确实和硬件时间有一定差距不是个案啊。解决方法一般有下面两种:
1 定时同步,也就是每隔一定时间,进行一次hwclock -s
2 用buxybox提供的adjtimex来调时间
第一种方案,首先肯定的是我这里是可以借鉴的,但是每分钟慢7或者8秒,这个同步周期是不得很短啊。尽管设备对时间要求不是非常严格,但是也不能每分钟有7秒的差距啊。再说每10秒同步一次也不合适啊。
第二种方案,编译完busybox后,用这个命令调时间的话,-t和-f参数是有范围的。我设置参数达到极限值,确实有所改观,但是只能达到每30分钟慢72秒,这也不小啊。
然后我看了看,别人用这两种方法来调试系统时间,一般是差距不很大的情况。我感觉应该是我的系统是有问题的,即使通过同步做的表面上看起来时间差不多,但是这个时间差距这么大会不会有其它潜在的风险呢?
本着负责的态度来重新看待这个问题,不能只停留在解决的层面,要找到原有才是硬道理啊。
首
先,给芯片提供商打个电话,确定一下。芯片厂商一个FAE接我的电话,说这个芯片支持从网上下载的标准内核,任何都不用修改,我再三确定,对方很负责任的
告诉你,没有任何问题,他们都这么用。我问他们有没有验证过,对方也是很负责任的告诉我在他们的板子上根本就没有这问题,肯定没有这问题。
停了对方这么肯定的回答,我想到三个方面:
1 问题肯定有
2 可能是我的内核编译选项有不合理的地方
3 我们的硬件和厂商的提供的板子有区别
第一步,查看内核选项,只要和时间,定时器,RTC,hwclick,HZ有关的选项我都仔细的看了看。应该没有错误的地方。然后抱着不太相信自己,相信FAE的态度把一些选项修改,再测试。还是那样。问题没有解决。
第二步,把厂商提供的板子的pdf版原理图拿来看看,和我们的板子很大部分都一样。尤其时钟部分肯定一样。
没有进展,实在没有办法,只能看原理图+datasheet啦。我们采用的这颗cpu是r8610,和pc486完全兼容的。
看系统tick这一块,这破datasheet说的也太含糊啦,关键细节地方都没有提及,估计由于和486兼容,让参考相关486芯片呢吧。
r8610的系统时钟是有82c54提供的,82c54确实是pc也采用的定时芯片,一般情况用timer0方式3产生固定838ns周期方波来实现。
默
认采用14.31818m的外部时钟来提供,根据写到芯片计数器里的初值来计算有多少个838ns的时间间隔来产生irq0,而这个irq0产生的频率就
是linux系统里的HZ。例如,在我的系统里HZ设置为250,那么1秒内irq0就要产生250次中断。这个值也就是我们查看/proc
/interrupt所显示的第一行的内容。
在linux-3.0.4内核目录下的include/linux目录下的timerx.h这个文件里有这么一个定义:
#define PIT_TICK_RATE 1193182ul
这个就是系统默认使用的定时芯片的采用的计数时钟,
在linux-3.0.4内核目录下的arch/x86/include/asm/timex.h文件有这样的定义:
#define CLOCK_TICK_RATEPIT_TICK_RATE
在linux-3.0.4内核目录下的include/linux目录下的jiffies.h文件里有这么一个宏:
#define LATCH ((CLOCK_TICK_RATE + HZ/2)/HZ,而这个值就是要写入定时器的初始值。我根据我的环境计算了一下,
(1193182+250/2)
/250 =
4773.228,这个值写入82c54,这个值也就是说82c54需要经过这么多个838ns的周期才产生一次irq0中断。两次中断之间的时间间隔
是:4773.228×838(ns)=
3999965.064.这个值应该就是HZ的倒数。即3999965.064×250应该等于1.而实际计算结果是999991266,基本相等,说明
在这个芯片上的linux系统定时器和硬件定时器产生联系的地方就是这里。
上面的计算是理想状态,也就是说如果硬件按照上面的计算过程来运行的话,系统时间也是会有时间差距的,但是很小,以为我们实际计算结果是999991266,每秒还慢8734ns,但是那已经很小了。
我
首先考虑到的就是我的定时器时钟可能不是1193182。于是,继续研读r8610 datasheet,看其中关于clock
source的选择,可惜,没有提到。于是继续google,打不开啦,被和谐啦,baidu,别用啦,更本找不到啊。等会。抽烟,喝杯茶。30分钟以
后,google 查到下面,对我有十分巨大的提示啊:
8254 工作时钟的来历最
初在对个人电脑设计时,出于成本考虑,主板上采用了当时广泛应用于电视机且价格最便宜的一个 14.31818MHz
振荡器,该振荡器的频率远高于系统其他器件所需要的频率。所以设计师采用 3 分频后得到 4.77MHz 驱动中央处理器 8088 ;采用 4
分频后得到 3.58MHz 用于驱动彩色图形适配器;最后将系统各种频率的基频 1.1931816 MHz (各种频率的最大公约数,即 12
分频) 作为系统可编程定时器芯片的输入时钟。为了保持兼容性,可编程定时器 8254 就一直采用这个频率的时钟作为输入。
也就是说,这就是14.31818和1193182的关系,是12分频啊。在r8610 datasheet上没有用到外部的14.31818,而是内部的12.5m啊。并且在一个并不起眼的地方发现有下面一句话:
NOTE: the following clock is 14.318MHZ/12(external) or 12.5MHZ/12(internal)
我的个妈呀,不容易啊,终于找到了啊,我要找的就是这一句啊。严重鄙视自己对datasheet的粗心阅读。
也就是说在r8610这颗cpu里面,82c54采用的clk是12.5M/12 = 1041667.
在修改以前,大概计算一下:1193182-1041667/1193182 = 0.126983 = 12.7%。我靠,太正了,啥也别说了,都是眼泪。
赶紧的,注释,修改,测试。
时间ok啦。
以上就是我调试系统时间慢的过程,总结:
1 如果时间慢的很多,可以从硬件入手看看时钟设置是否正确
2 阅读datasheet一定要仔细,一字不落的阅读
3 不要盲目相信FAE
希望以上内容对大家有所帮助