문제

I want to implement a timestamp functionality for my msp430-based platform.

My aim is to use a hardware timer, and count the number of times it overflows, to generate a long timestamp value (typically an uint32 for overflow counter, combined with the uint16 value of the hardware timer).

This is what I have:

  • The overflow counter is incremented on interrupt,
  • its value is checked every time a timestamp is requested (this is protected by interrupt locks).
  • the overflow counter value is combined with the current hardware timer value to a large timestamp.

I run into problems when I take into consideration the timing of interrupts.


The first naive implementation I had:

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;    

This is going to fail when an overflow occurs after getting the timer value, but before the interrupts are disabled. overflow_count_local would then be 1 greater than what it was upon assigning timer_value.


I have tried to add other checks to detect this possible interrupt

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;    

This is not either going to work, this time because the timer might have overflown after disabling the interrupts, but before assigning second_timer_value. This would then make overflow_count_local one too little.


However I try to turn this around, there seems to always be a case which is not covered. Is there a known way to make this work?

Some limitations:

  • The timer is used for other functionality as well (with capture/compare) and may not be stopped.
  • The msp430's RTC module may not be used to that effect, because it is used to keep the actual time of the day.
  • No 32 bit timer is available.
도움이 되었습니까?

해결책

The following algorithm is lock free (no interrupt disable required):

Get overflow then timer (in that order) until overflow is the same either side of the timer read.

uint32_t hi ;
uint16_t lo ;
do
{
    hi = overflow_count ;
    lo = timer_value_get() ;

} while( hi != overflow_count )

return (hi << 16 ) | lo ; 

This should normally take zero or one iteration at most, unless there is an exceptionally long context switch to another thread or interrupt during which the timer overflowed again.

다른 팁

Maybe something like this. I don't see a need to disable interrupts with this.

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
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top