问:T3 高精度时钟出现负数问题解决方案
1、问题描述
问题现象主要表现为连续获取两次高精度时钟,时间差为负数。即后一次获取的时间小于前一次。现象出现随机性较高,属于偶发事件。连续多次获取可复现此问题。后一次出现时间约比前一次少 1ms 左右,即一个 tick 值。
答:
基本解决思路就是使用锁使得获取时刻无法出现在更新tick操作和清中断操作中间。但由于更新 tick 操作和获取操作都在 base 中施加内核锁。因此不可以再重复加锁否则会造成死锁。目前的解决方案是将清中断操作添加在内核回调函数 bspTickHook() 中,因为 bspTickHook() 会和更新 tick 操作一同施加内核锁,这样可以保证获取操作无法插入清中断和更新 tick 操作之间,即可以解决问题。经多次实验,此方案实测有效。
1、原因分析
高精度时钟的基本原理是在 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:清中断在后