I'm trying to implement a global timer, so that I can call time_us() anywhere in program and the function will return microseconds since program start. I've done this using TIMER2 (8-bit clock) and interrupt on overflow, and counting the overflows:
volatile uint64_t _time_overflow_cnt;
void time_reset(){
TCCR2A=0; // no pin output,
TCCR2B=(1<<CS21); // prescaler=8
TIMSK2=1<<TOIE2; // interrupt on overflow (256 cycles)
sei();
TCNT2=0; // reset timer to 0
_time_overflow_cnt=0;
}
ISR(TIMER2_OVF_vect){
_time_overflow_cnt++;
}
uint64_t time_us(){
return (_time_overflow_cnt*256 + TCNT2)/(F_CPU/8/1000000ULL);
}
However, this code has a race condition, which is in my case quite noticeable - if we rewrite this code into assembly, we see that the time_us is quite lengthy (64-bit calculations take some time) and if TCNT2 overflows during this time, the calculations is skewed by whole 256 cycles. I tried turning interrupts off before and turning them back on after calculation, but this does not help - it only secures the overflow counter, while the TCNT2 keeps increasing. I also tried saving overflow counter, then saving TCNT2, checking if the former changed in between, and a few other 'solutions' similar to this one, but all off them had some TOCTOU (Time Of Check to Time Of Use) problems. Have you got a better idea for implementation?