1.Tick工作原理简介
Tick工作原理其实就是硬件定时器的工作原理,1个系统tick就代表一个定时器硬件中断。定时器的工作原理很简单,就是内部有一个递减的计数器,当减到0时产生一个中断,如图 1-1所示:
图 1-1定时器工作原理
假设定时器模块的输入频率是1MHz,系统定义的1S内tick数是100,也就是100Hz,可以计算出递减计数器要设置的值为1MHz/100Hz=10000。可以看出递减计数器相当于一个分频器,输入端每来一个脉冲,其值就减去1,当减到0时产生一个中断,同时其值自动重载成10000,如此循环下去。
2.系统获取时间操作
系统获取时间相关接口是基于tick来工作的,但是这是有误差的,如图 2-1所示:
图 2-1系统获取时间
虚线表示下一个tick中断还未产生,如果此时来获取时间,获取到的时间只是之前tick累计的时间。假设tick中断产生时刻和获取时间那一时刻之间的跨度是4ms,那么获取的时间就有4ms的误差,高精度时钟就是为了消除这种误差而诞生的。
3.高精度时钟原理
3.1基本原理
上述误差产生的根本原因是没有将tick中断产生时刻和获取时间那一时刻之间的跨度更新到时间里去,如果计算出这段时间并加到获取的时间里去就可以校正获取的时间了。结合图 1-1和图 2-1,基本的校正原理如下所述:
1个tick时间等价于递减计数器的初始值,假设是10000,也就是说递减10000次相当于过了一个tick时间
用1000 * 1000 * 1000 / 10000得到递减一次的时间,单位是ns
3.2特殊情况
当系统是多核时,系统产生一个由cpu0来处理的tick中断,当cpu0还没有更新整个系统的tick数时,这时cpu1来获取时间,按照基本原理的计算之后还要加上一个tick的时间才是正确的。
4.代码展示
程序清单 4-1
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++;
}
}