本文描述基于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行代码便不言而喻了。
关于第5、6行注释的理解:12MHZ转换为微秒为(10^6)/(12*10^6)=1/12=0.08333333333 将其放大保存在整型变量里,这里是说放大系数为2^15或2^14显得太低,精度不够。因此设置放大系数为2^16,并且2^16不会导致200HZ的频率上溢。200HZ频率表示5毫秒产生一个中断,假设时钟频率就是12M,则5毫秒需要12*(10^6)*(5/1000)=60000个时钟周期。((10^6)/(12*10^6))*(2^16)=5462(约等于), 5462*60000=0x13889C40,没有造成溢出。个人理解,如有错误之处,还请多多提点。
接下来再看另一段代码:
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行代码右移处理便是将上面进行放大倍数处理后的值还原为实际的结果值。
1<<(TIMER_USEC_SHIFT - 4) = 2^12, (2^12/2^16) 小于 1,因此起到向上取整的作用。
上一篇:ARM11 S3C6410 硬件浮点(VFP)实现
下一篇:玩转S3C6410之一 交叉工具链制作(gcc4.5.1-armv6-vfp)
推荐阅读最新更新时间:2024-11-12 11:35
设计资源 培训 开发板 精华推荐
- ADP2139CB-1.8EVALZ,ADP2138 评估板,800 mA,输出电压 1.8 V,3 MHz 降压稳压器
- STR-ACF-12V100WPSU-GEVB:启用 Strata 的 NCP1568 100W 交流到直流转换器
- AD8062AR-EB,AD8062ARZ 双通道高速运算放大器评估板,采用 8 引脚 SOIC 封装
- DC874A,用于具有 8 位 ADC 和 I2C 接口的 LTC4215 热插拔控制器的评估套件
- FireAnt:适用于制造商和硬件设计人员的低成本、拇指大小、适用于面包板的 FPGA 开发板(含原理图和源码等)
- 【排针存储器】 32Byte存储器
- NCV7424V1GEVB:NCV7424 四通道 LIN 收发器评估板
- 使用 Semtech 的 SC1541 的参考设计
- C5137697_CH432T双串口扩展芯片方案验证板
- LT3089EFE 并联线性稳压器的典型应用电路