linux内核中S3C6410 timer相关代码理解
本文描述基于mini6410平台的time.c中的相关代码,主要描述下对部分代码的理解。
先贴上代码:
1 /* we use the shifted arithmetic to work out the ratio of timer ticks 2 * to usecs, as often the peripheral clock is not a nice even multiple 3 * of 1MHz. 4 * 5 * shift of 14 and 15 are too low for the 12MHz, 16 seems to be ok 6 * for the current HZ value of 200 without producing overflows. 7 * 8 * Original patch by Dimitry Andric, updated by Ben Dooks 9 */ 10 11 /* timer_mask_usec_ticks 12 * 13 * given a clock and divisor, make the value to pass into timer_ticks_to_usec 14 * to scale the ticks into usecs 15 */ 16 static inline unsigned long 17 timer_mask_usec_ticks(unsigned long scaler, unsigned long pclk) 18 { 19 unsigned long den = pclk / 1000; 20 21 return ((1000 << TIMER_USEC_SHIFT) * scaler + (den >> 1)) / den; 22 }
该函数主要的功能为换算出在某个时钟频率下,每个时钟周期所对应的微秒数,且该微秒数经过放大处理。
首先第19行代码将时钟频率由MHZ转换为KHZ,当然前提是pclk以MHZ为单位计算。
分析下一行代码前,先看下频率转换为微秒的计算公式:t = (10^6)/(pclk/scaler),上述公式表示在分频后的时钟频率下一个时钟周期对应的微秒数。显然上述公式可能出现小数部分,在计算机中我们用整型变量来保存数据时,为了不减小精度,一般会将数据放大处理,因此将上述公式放大一定的倍数,在得到最后结果前,再缩小相应的倍数得到最后结果。在这里将上述公式放大了2^16倍,得到公式:
t = (10^6)*(2^16)/(pclk/scaler),
对上述公式变量替换并推导:t = ((10^6)/1000)*(2^16)/((pclk/1000)/scaler) = ((10^3)<<16)/(den/scaler)
= ((1000<<16)*scaler)/den。
为了减小误差,对上述公式进行四舍五入则得到公式:
((1000<<16)*scaler)/den + (1/2) = ((1000<<16)*scaler)/den + (den/2den) = ((1000<<16)*scaler+den/2)/den
= ((1000<<16)*scaler+(den>>1))/den。
TIMER_USEC_SHIFT宏定义为16,由此第21行代码便不言而喻了。
接下来再看另一段代码:
1 /* timer_ticks_to_usec 2 * 3 * convert timer ticks to usec. 4 */ 5 6 static inline unsigned long timer_ticks_to_usec(unsigned long ticks) 7 { 8 unsigned long res; 9 10 res = ticks * timer_usec_ticks; 11 12 res += 1 << (TIMER_USEC_SHIFT - 4); /* round up slightly */ 13 14 return res >> TIMER_USEC_SHIFT; 15 }
该函数的主要功能是将时钟周期数转换为微秒数,第10行代码中全局变量timer_usec_ticks为由timer_mask_usec_ticks函数返回得到的值。该值乘以具体时钟周期数便得到该时钟周期数对应的微秒数。后面第12行又加上了一个值,该值目的是进行向上取整处理,以提高精度。第14行代码右移处理便是将上面进行放大倍数处理后的值还原为实际的结果值。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。