I have a 32 bit hardware timer that I'd like to extend to 64 bit effective length in software.
In my embedded system, I have available a 32-bit hardware "core timer" (CT) that ticks at ~ 40 MHz, so it rolls over in about 107 seconds.
That's great for precise timing of periods up to 107 seconds. But I'd like to do equally precise timing of longer periods.
It also has a 32-bit "period" register - when the CT value matches the period register, an interrupt is generated.
My ISR looks like this (simplified for clarity):
const UINT32 ONE_MILLISECOND = TICK_RATE/1000;UINT64 SwRTC;void CT_ISR(void) { PeriodRegister += ONE_MILLISECOND; SwRTC += ONE_MILLISECOND; ClearCTInterrupt();}
So, now I have a 64 bit "SwRTC" that can be used to measure longer periods, but only to a precision of 1 millisecond, plus the 32-bit hardware timer that is precise to 1/40 MHz (25 nanoseconds). Both use the same units (TICK_RATE).
How can I combine both to get a 64 bit timer that's equally precise, while still getting interrupts at 1000 Hz?
My first try looked like this:
UINT64 RTC(void){ UINT64 result; DisableInterrupts(); // to allow atomic operations result = (SwRTC & 0xFFFFFFFF00000000ull) + ReadCoreTimer(); EnableInterrupts(); return result;}
But that's no good, because if the CT rolls over while interrupts are disabled then I'll get a result with a small number in the low-order 32 bits, but without the high-order bits having been incremented by the ISR.
Maybe something like this would work - read it twice and return the higher value:
UINT64 RTC(void){ UINT64 result1, result2; DisableInterrupts(); // to allow atomic operations result1 = (SwRTC & 0xFFFFFFFF00000000ull) + ReadCoreTimer(); EnableInterrupts(); DisableInterrupts(); // again result2 = (SwRTC & 0xFFFFFFFF00000000ull) + ReadCoreTimer(); EnableInterrupts(); if (result1 > result2) return result1; else return result2;}
I'm not sure if that'll work or if there is a hidden problem there I've missed.
What is the best way to do this?
(Some may ask why I need to time such long periods so precisely in the first place. It's mainly for simplicity - I don't want to use 2 different timing methods depending on the period; I'd prefer to use the same method all the time.)