1 問題描述

      問題現象主要表現為連續獲取兩次高精度時鐘,時間差為負數。即後一次獲取的時間小於前一次。現象出現隨機性較高,屬於偶發事件。連續多次獲取可復現此問題。後一次出現時間約比前一次少1ms左右,即一個tick值。

2 原因分析

      高精度時鐘的基本原理是在tick中斷基礎上使用定時器當前值校正時間。定時器使用T3的timer0,timer0從一個預設值遞減到0表示1ms。並在遞減到0時產生中斷,定時器恢復到預設值。中斷處理中主要執行更新tick值操作。獲取高精度時鐘分為如下兩種情況:

1)獲取時刻發生在兩個tick中斷之間

      獲取時刻發生在兩個tick中斷之間,這時需要通過讀取定時器計數值計算從上一次中斷髮生到當前經過的時間△t,再在當前 tick值的基礎上加上△t得出高精度時鐘值。如圖 2.1所示。

                                               圖2.1獲取時刻發生在兩個tick中斷之間

2)獲取時刻發生在某個tick中斷處理時

      當獲取時刻發生在tick中斷處理時情況就比較複雜,主要是硬體定時器會復位,△t的值是當前中斷髮生到現在時間差,即少了一個tick值。這裡做了特殊處理,在獲取高精度時間時判斷中斷狀態暫存器中的值,若此時發生中斷則將最終的結果加上一個tick,如圖 2.2所示。

                                    圖2.2獲取時刻發生在某個tick中斷處理時

 

      從上述第二種情況可以看出實際的結果會被清中斷的時刻所影響。若清中斷操作在更新tick操作之前,且獲取時刻在兩者之間,則會缺少1個tick,如圖 2.3所示。

                                                            圖2.3清中斷在前

      若清中斷操作在更新tick操作之後,且獲取時間在兩者之間,則會多計算1個tick,如圖 2.4所示。

                                                 圖2.4清中斷在後

3 解決方案

      基本解決思路就是使用鎖使得獲取時刻無法出現在更新tick操作和清中斷操作中間。但由於更新tick操作和獲取操作都在base中施加核心鎖。因此不可以再重複加鎖否則會造成死鎖。目前的解決方案是將清中斷操作新增在核心回撥函式bspTickHook()中,因為bspTickHook()會和更新tick操作一同施加核心鎖,這樣可以保證獲取操作無法插入清中斷和更新tick操作之間,即可以解決問題。經多次實驗,此方案實測有效。