SylixOS高精度时钟分析

gewenbin
gewenbin
gewenbin
188
文章
15
评论
2020年12月24日22:06:21 评论 613

1. tick工作原理简介

其实这应该说“定时器工作原理简介”更合适些,1个系统tick就是一个定时器硬件中断,定时器的工作原理很简单,就是内部有一个递减的计数器,当减到0时产生一个中断:

SylixOS高精度时钟分析

假设定时器模块的输入频率是1MHz,系统定义的1S内tick数是100,也就是100Hz,那么可以计算出递减计数器要设置的值为1MHz/100Hz=10000。可以看出递减计数器相当于一个分频器,输入端每来一个脉冲,其值就减去1,当减到0时产生一个中断,同时其值自动重载成10000,如此循环下去。

2. 系统获取时间操作

系统获取时间相关接口是基于tick来工作的。但是这是有误差的:

SylixOS高精度时钟分析

虚线表示一个tick中断还未产生,如果此时来获取时间,获取到的时间只是之前tick累计的时间。假设tick中断产生时刻和获取时间那一时刻之间的跨度是4ms,那么获取的时间就有4ms的误差,高精度时钟就是为了消除这种误差而诞生的。

3. 高精度时钟原理

3.1 基本原理

我们知道,上述误差产生的根本原因是没有将tick中断产生时刻和获取时间那一时刻之间的跨度更新到时间里去,如果我们能计算出这段时间并加到时间里去不就行了吗?看到没有,so easy!

结合第1小节和第2小节中的图,分析如下:

  • 1个tick时间其实等价于递减计数器的初始值,假设是10000,也就是说递减10000次相当于过了一个tick时间
  • 我们用1000 * 1000 * 1000 / 10000得到递减一次的时间,单位是ns
  • 我们用计数器初始值减去获取时间那一刻计数器中的值,就得到了获取时间时刻计数器已经递减的次数
  • 拿递减一次的时间 * 递减的次数 = tick中断产生时刻和获取时间那一时刻之间的时间跨度

3.2 特殊情况

当系统是多核时,系统产生了一个由cpu0来处理的tick中断,当cpu0还没有更新整个系统的tick数时,这时cpu1来获取时间,按照3.1的方法计算后还要加上一个tick的时间才是正确的。

4. 代码展示

/*********************************************************************************************************
** 函数名称: bspTickHighResolution
** 功能描述: 修正从最近一次 tick 到当前的精确时间.
** 输 入  : ptv       需要修正的时间
** 输 出  : NONE
** 全局变量:
** 调用模块:
*********************************************************************************************************/
VOID  bspTickHighResolution (struct timespec *ptv)
{
    REGISTER UINT32  uiCntCur, uiDone;

    uiCntCur = (UINT32)timerGetCnt(4);
    uiDone   = GuiFullCnt - uiCntCur;

    /*
     *  检查是否有 TICK 中断请求
     */
    if (rSRCPND & BIT_TIMER4) {
        /*
         *  这里由于 TICK 没有及时更新, 所以需要重新获取并且加上一个 TICK 的时间
         */
        uiCntCur = (UINT32)timerGetCnt(4);
        uiDone   = GuiFullCnt - uiCntCur;

        if (uiCntCur != 0) {
            uiDone   += GuiFullCnt;
        }
    }

    ptv->tv_nsec += (LONG)((Gui64NSecPerCnt7 * uiDone) >> 7);
    if (ptv->tv_nsec >= 1000000000) {
        ptv->tv_nsec -= 1000000000;
        ptv->tv_sec++;
    }
}
  • GuiFullCnt表示递减计数器的初始值,也就是产生1个tick时间的计数值;Gui64NSecPerCnt7表示递减一次的时间,但是这个时间被扩大了128倍,目的是为了提高计算精度。
  • uiDone表示获取时间时刻计数器已经递减的次数,uiCntCur表示获取时间时刻计数器当前值
  • if (rSRCPND & BIT_TIMER4)用于3.2小节特殊情况的判断,条件成立表示系统的tick数还没来得及更新,不成立表示系统的tick数已经被更新
  • 当uiCntCur=0时,表示tick中断刚刚产生,这时uiDone就已经代表一个tick的计数值,所以就无需再加上一个tick的计数值了
  • 最后将修正后的时间赋值给tv_nsec成员
gewenbin
  • 本文由 发表于 2020年12月24日22:06:21
  • 转载请务必保留本文链接:http://www.databusworld.cn/9736.html
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: