Hi all,
I have a problem which I think I know what the problem is, but have no clue what to do about it.
I have a timer driven ISR which will light an LED (infrared actually - but that doesn't matter) and I "push in" a pulse count into a volatile uint16_t which the ISR uses to count pulses. Outside the ISR in the real world, I run a simple loop to check when the uint16_t is decremented to 0 (telling me the ISR is done and ready for more).
At this point it may help to look at the code snippet (first, the ISR):
ISR (TIMER1_COMPA_vect)
{
if (count) { // if a count was pushed in...
state ? IO_PORT &= ~_BV (IR_BIT) : onoff ? IO_PORT |= _BV (IR_BIT) : IO_PORT &= ~_BV (IR_BIT);
count -= state; // decrement count (on times only)
state = state ? 0 : 1; // if led was on set it off, else set it on
}
}
"count" is a uint16_t (volatile) and state is a uint8_t (also volatile) which only has the value 0 or 1.
Now here's what "pushes" values into "count" and then waits for it to finish:
void send_cmd (const uint16_t *command)
{
uint16_t *ptr;
IO_DDR |= _BV (IR_BIT); // set IR drive pin as an output
onoff = 0; // reset on/off LED polarity
ptr = (uint16_t *) command; // point to command table
while ((count = pgm_read_word (ptr++))) { // push pulse count in
onoff = ((ptr - command) % 2); // set LED on or off
while (count);
if (count) { fprintf (stdout, "FAILED!!! %u\n", count); }
}
IO_DDR &= ~_BV (IR_BIT); // set IR drive pin back to an input
}
Just look at the while loop (that's the only "important" part). I get a 16 bit value from PROGMEM, then stuff it into "count", then wait until the ISR decrements it down to zero (the "while (count);" statement in the middle of the while loop).
I was looking at the generated waveforms on the silly-scope and occasionally if would "screw up". I eventually found that putting ANOTHER "while (count);" in the loop (that is, two in a row) stopped the problem, but I didn't like it because I was MASKING a deeper problem.
So I stuck the printf line inside as a diagnostic and what do I find? Whenever it fails, "count" has a value of 255 when the previous line (while (count)
said it was zero.
Ah ha! Now I see (I think I see) what's happening. The two 8 bit halves of the uint8_t are not being updated together (atomically??)
So what I need to know is how to decrement "count" and when it tests as zero, it really is zero to any and all who look at it.
Any help or advice will be greatly appreciated. Thanks!