我想为基于msp430的平台实现时间戳功能。
我的目标是使用硬件定时器,并计算它溢出的次数,以生成一个长时间戳值(通常是溢出计数器的uint32,结合硬件定时器的uint16值)。
这就是我所拥有的:
当我考虑到中断的时间时,我遇到了问题。
我的第一个天真实施:
uint16_t timer_value = timer_value_get();
__istate_t istate = interrupt_disable();
uint64_t overflow_count_local = overflow_count; // the volatile incremented on interrupt
interrupt_restore(istate);
return (overflow_count_local << 16u) + timer_value;
在获取定时器值之后但在禁用中断之前发生溢出时,这将失败。 overflow_count_local
将比分配timer_value
时更大1。
我试图添加其他检查以检测此可能的中断
uint16_t timer_value = timer_value_get();
__istate_t istate = interrupt_disable();
uint16_t second_timer_value = timer_value_get();
uint64_t overflow_count_local = overflow_count; // the volatile incremented on interrupt
interrupt_restore(istate);
if (second_timer_value < timer_value) {
// A HW timer overflow occured just before disabling interrupts.
overflow_count_local--;
}
return (overflow_count_local << 16u) + timer_value;
这不是要么工作,这次是因为定时器在禁用中断后可能已经溢出,但在分配second_timer_value
之前。这会使overflow_count_local
太少。
然而,我试图扭转局面,似乎总是有一个未涵盖的案例。是否有一种已知的方法可以使这项工作?
一些限制:
答案 0 :(得分:3)
以下算法无锁(无需中断禁用):
获取溢出然后定时器(按此顺序),直到溢出与定时器读取的任何一侧相同。
uint32_t hi ;
uint16_t lo ;
do
{
hi = overflow_count ;
lo = timer_value_get() ;
} while( hi != overflow_count )
return (hi << 16 ) | lo ;
这通常应该最多进行零次或一次迭代,除非有异常长的上下文切换到另一个线程或中断,在此期间定时器再次溢出。
答案 1 :(得分:1)
也许是这样的。我认为不需要用这个来禁用中断。
timer_value_1 = timer_value_get();
overflow_count_snapshot = overflow_count;
timer_value_2 = timer_value_get();
if (timer_value_2 < timer_value_1)
{
return (timer_value_2 + (overflow_count << 16)); // not the snapshot
}
else
{
return (timer_value_2 + (overflow_count_snapshot << 16)); // you could use timer_value_1 or 2
}