Timer 基于带溢出计数器的硬件定时器的时间戳
我想为基于msp430的平台实现时间戳功能 我的目标是使用硬件计时器,并计算其溢出的次数,以生成长时间戳值(通常为溢出计数器的uint32,与硬件计时器的uint16值组合) 这就是我所拥有的:Timer 基于带溢出计数器的硬件定时器的时间戳,timer,embedded,interrupt,msp430,Timer,Embedded,Interrupt,Msp430,我想为基于msp430的平台实现时间戳功能 我的目标是使用硬件计时器,并计算其溢出的次数,以生成长时间戳值(通常为溢出计数器的uint32,与硬件计时器的uint16值组合) 这就是我所拥有的: 溢出计数器在中断时递增 每次请求时间戳时都会检查其值(这由中断锁保护) 溢出计数器值与当前硬件计时器值组合为一个大的时间戳 当我考虑到中断的时间时,我遇到了问题 我拥有的第一个天真的实现: uint16_t timer_value = timer_value_get(); __istate_t
- 溢出计数器在中断时递增
- 每次请求时间戳时都会检查其值(这由中断锁保护)
- 溢出计数器值与当前硬件计时器值组合为一个大的时间戳
我拥有的第一个天真的实现:
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;
这一次也不起作用,因为在禁用中断后,但在分配秒计时器\u值之前,计时器可能溢出。这会使溢出\u count\u local
太少
然而,我试图扭转这一局面,似乎总是有一个案件没有涵盖。有没有一个已知的方法可以让这项工作
一些限制:
- 计时器还用于其他功能(带有捕获/比较功能),可能不会停止
- msp430的RTC模块可能不用于此目的,因为它用于保持一天的实际时间
- 没有32位计时器可用
可能是这样的。我认为没有必要用这个来禁用中断
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
}
timer_value_1=timer_value_get();
溢出计数\u快照=溢出计数;
定时器_值_2=定时器_值_get();
如果(计时器值\u 2<计时器值\u 1)
{
return(timer_value_2+)(overflow_count可能是这样的。我认为没有必要用它来禁用中断
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
}
timer_value_1=timer_value_get();
溢出计数\u快照=溢出计数;
定时器_值_2=定时器_值_get();
如果(计时器值\u 2<计时器值\u 1)
{
返回(计时器\u值\u 2+(溢出\u计数以下算法是无锁的(不需要中断禁用):
获取溢出,然后使用计时器(按该顺序),直到溢出与计时器读取的任一侧相同
uint32_t hi ;
uint16_t lo ;
do
{
hi = overflow_count ;
lo = timer_value_get() ;
} while( hi != overflow_count )
return (hi << 16 ) | lo ;
uint32\t hi;
uint16_t lo;
做
{
hi=溢出计数;
lo=定时器值获取();
}while(hi!=溢出\u计数)
返回(hi以下算法无锁(无需中断禁用):
获取溢出,然后使用计时器(按该顺序),直到溢出与计时器读取的任一侧相同
uint32_t hi ;
uint16_t lo ;
do
{
hi = overflow_count ;
lo = timer_value_get() ;
} while( hi != overflow_count )
return (hi << 16 ) | lo ;
uint32\t hi;
uint16_t lo;
做
{
hi=溢出计数;
lo=定时器值获取();
}while(hi!=溢出\u计数)
返回(问题是,我不确定分配是原子的,特别是因为<代码>溢出流计数是32位。如果分配不是原子的,中断发生在中间,结果可能会变得丑陋。如果TimeRealValue2.2TimeRealValue1,那么你应该忽略快照。但是很可能中断刚刚发生。o再次读取溢出计数应该是安全的(即,它在一段时间内不会再次改变)。我想你可以读取两次溢出计数来确定。如果定时器值>定时器值>1,那么就没有中断,溢出计数快照是好的。我明白了。溢出计数快照
可能是胡说八道,但如果是,那么它就不会被使用。有趣的是,我不确定赋值是否是原子的,特别是如果代码不是原子的,中断发生在中间,则结果可能会变得丑陋。如果TimeRealValue2.2TimeRealValue1您应该忽略快照,但是它很可能发生了中断,因此再次读取溢出流应该是安全的。(也就是说,一段时间内不会再改变)。我想你可以读取两次溢出计数来确定。如果timer\u value\u 2>timer\u value\u 1,那么没有中断,溢出计数\u快照是好的。我明白了。overflow\u count\u snapshot
可能是胡说八道,但如果是,那么它就不会被使用。有趣。不错。因为循环主体中两行的顺序很重要,我想将hi
和lo
设置为volatile
s是合适的。溢出计数已经是volatile了,所以这里不需要它,但是对于lo
。@Gauthier:这不会有什么坏处。只是一个警告,只有在启用中断时,它才能正常工作(或者,更具体地说,如果此代码可由计时器IRQ中断)。通常情况下,MSP430(或任何微控制器)代码是中断驱动的,如果这是从中断处理程序中调用的,其中MSP430全局禁用中断,则您将具有与OP示例中相同的竞争条件(在获取时间戳期间发生硬件溢出,但无法调用IRQ以增加溢出计数,因为中断已禁用).很好。由于循环主体中两行的顺序很重要,我想将hi
和lo
设置为volatile
s?overflow\u count
已经是volatile了,所以这里不需要它,但是对于lo
。@Gauthier:这不会有什么害处。只是一个警告,只有当我中断被启用(或者,更具体地说,如果此代码可被计时器IRQ中断)。通常,MSP430(或任何微控制器)代码是中断驱动的,如果这是从中断处理程序中调用的,其中MSP430全局禁用中断,那么您将具有与OP示例中相同的竞争条件(在获取时间戳期间发生硬件溢出,但无法调用IRQ以增加溢出计数,因为中断已禁用)。