Issues with HiResTimer
Posted: Wed May 14, 2014 8:00 pm
I think there are two issues with the HiResTimer on the MOD5441x:
1) In delay_uSec(), I believe init_ticks() should be called with ReferenceTicks, not delayTime. I noticed this when I tried to use delay_uSec() directly instead of delay(). For cases when the delay is known in advance, it is better to use delay_uSec() and avoid the floating point math in delay().
2) There may be a race condition in readTime(). If a counter overflow occurs after the USER_ENTER_CRITICAL call but before readLow() is called, then the time will be under reported by 34 seconds (2^32 * 8 ns) because resetCount didn't get updated. Disabling interrupts is a good strategy but in this case may actually make the problem worse. A safer way to do it would be as follows:
A variation of this is to read H, L, H and see if H changes. But if H changes, then it's not clear what to set L to so it's easier to just read them at the same time. Even though there's the potential of an infinite loop, there's virtually no chance of hitting that loop more than twice. If that is a concern, just read H, L, H, L and go with it.
-Bob
1) In delay_uSec(), I believe init_ticks() should be called with ReferenceTicks, not delayTime. I noticed this when I tried to use delay_uSec() directly instead of delay(). For cases when the delay is known in advance, it is better to use delay_uSec() and avoid the floating point math in delay().
2) There may be a race condition in readTime(). If a counter overflow occurs after the USER_ENTER_CRITICAL call but before readLow() is called, then the time will be under reported by 34 seconds (2^32 * 8 ns) because resetCount didn't get updated. Disabling interrupts is a good strategy but in this case may actually make the problem worse. A safer way to do it would be as follows:
Code: Select all
OSLock(); // Allow interrupts to occur so resetCount_ will update but prevent task switching
DWORD lowTime_1 = readLow();
DWORD highTime_1 = readHigh(); // same as reading resetCount_ but clearer
DWORD lowTime_2;
DWORD highTime_2;
do
{
lowTime_2 = readLow();
highTime_2 = readHigh();
} while (highTime_2 != highTime_1);
OSUnlock();
// continue calculations using lowTime_2 and highTime_2
-Bob