The values shown in the debugger are:
- IL_TimNow = 865280
- lastReceivedLed = 865055
- timeSinceLast = 4294967265
Note that 4294967265 is also what you get when you convert -31 to a uint32_t
. This suggests that the value of IL_TimNow
returned by IL_TimTimeNow()
just before the subtraction was actually lastReceivedLed - 31
, which is 865055 - 31, which is 865024.
The difference between the value of IL_TimNow
shown in the debugger (865280), and the value of IL_TimNow
just before the subtraction (865024), is 256. Moreover, the least-significant 8 bits of both values are all zero. This suggests that the value was being read just as the least-significant byte was wrapping round to 0 and the next byte was being incremented. The comment in IL_TimTimeNow()
says // Incremented in timer ISR
. Since the 8-bit microcontroller can only read one byte at a time, it seems that the timer ISR occurred while the four bytes of IL_TimNow
were being read by the function.
There are two ways to solve the problem. The first way is to disable the timer interrupt in IL_TimTimeNow()
while the value of IL_TimNow
is being read. So the IL_TimTimeNow()
function can be changed to something like this:
uint32_t IL_TimTimeNow(void)
{
uint32_t curTime;
disable_timer_interrupt();
curTime = IL_TimNow;
enable_timer_interrupt();
return curTime;
}
However, you will need to check that disabling the timer interrupt temporarily only results in the interrupt being delayed, and not skipped altogether (otherwise you will lose timer ticks).
The other way to solve the problem is to keep reading IL_TimNow
in IL_TimTimeNow()
until you get two identical values. So the IL_TimTimeNow()
function can be changed to something like this:
uint32_t IL_TimTimeNow(void)
{
uint32_t prevTime, curTime;
curTime = IL_TimNow;
do
{
prevTime = curTime;
curTime = IL_TimNow;
} while (curTime != prevTime);
return curTime;
}
There will usually be a single iteration of the do ... while
loop, reading IL_TimNow
twice. Occasionally, there will be two iterations of the loop, reading IL_TimNow
three times. In practice, I wouldn't expect more than two iterations of the loop, but the function can handle that as well.
A less safe, but possibly slightly faster version of the above would be to only read IL_TimNow
twice when the least-significant byte is 0:
uint32_t IL_TimTimeNow(void)
{
uint32_t curTime;
curTime = IL_TimNow;
if ((curTime & 0xFF) == 0)
{
// Least significant byte possibly just wrapped to 0
// so remaining bytes may be stale. Read it again to be sure.
curTime = IL_TimNow;
}
return curTime;
}
If performance is not an issue, use one of the safer versions.