Вопрос

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