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
用計數器初始值減去獲取時間那一時刻計數器中的值,就得到了獲取時間時刻計數器已經遞減的次數
用遞減一次的時間 *遞減的次數,就得到tick中斷產生時刻和獲取時間那一時刻之間的時間跨度
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++;
}
}
GuiFullCnt表示遞減計數器的初始值,也就是產生1個tick時間的計數值;Gui64NSecPerCnt7表示遞減一次的時間,但是這個時間被擴大了128倍,目的是爲了提高計算精度
uiDone表示獲取時間時刻計數器已經遞減的次數,uiCntCur表示獲取時間時刻計數器當前值
if (rSRCPND & BIT_TIMER4)用於特殊情況的判斷,條件成立表示系統的tick數還沒來得及更新,不成立表示系統的tick數已經被更新
當uiCntCur=0時,表示tick中斷剛剛產生,這時uiDone就已經代表一個tick的計數值,所以就無需再加上一個tick的計數值了
最後將修正後的時間賦值給tv_nsec成員