Reading a variable that gets updated in an interrupt

I have some code that runs like this:

volatile uint16_t foo = 0;
uint16_t delta_foo = 0;
uint16_t bar_01 = 0;
uint16_t bar_02 = 0;

ISR(TIMER2_COMPA_vect) {
foo = foo + 1;
}

int main (void)
{

bar_01 = foo;

// interrupt gets called at some point in the coding here

bar_02 = foo;

delta_foo = bar_02 - bar_01;

Serial.println(delta_foo);

}

Mostly my Serial.println of delta_foo returns numbers of 2-3, but every now and then I get outputs of 256 and 65281.

What is going on? Did the interrupt get called while foo was being read and copied to bar_01 or bar_02?

I think that writing and reading 16 bit variables takes more than one clock cycle, so I suspect that the interrupt is causing problems when it occurs at an inconvenient moment.

Why is delta_foo unsigned?

Why are delta_foo, bar_01 and bar_02 global?

What is going on? Did the interrupt get called while foo was being read and copied to bar_01 or bar_02?

Quite possibly.

I think that writing and reading 16 bit variables takes more than one clock cycle

Correct. On an 8 bit system, reading and write 16 bit values are not atomic operations.

so I suspect that the interrupt is causing problems when it occurs at an inconvenient moment.

Disable interrupts. Copy the values. Reenable interrupts. No mo problems.

PaulS:
Why is delta_foo unsigned?

Why are delta_foo, bar_01 and bar_02 global?

It's just something I wrote quickly so that nobody had to bother reading all the code that was irrelevant to my question.

PaulS:
Disable interrupts. Copy the values. Reenable interrupts. No mo problems.

Thanks. If I do that, will the interrupt be in a queue when I re-enable interrupts, or does disable interrupts also stop interrupts from being queued or stored in any way? My preference would be to queue the interrupt so that it is not totally lost.

will the interrupt be in a queue when I re-enable interrupts

Yes, but the queue can only hold one interrupt, so re-enable them as soon as you've copied the data you need to copy.

My preference would be to queue the interrupt so that it is not totally lost.

Your preferences do not matter. You did get lucky, though.

PaulS:
Yes, but the queue can only hold one interrupt, so re-enable them as soon as you've copied the data you need to copy.
Your preferences do not matter. You did get lucky, though.

Thank you. While looking at disable interrupts I found a library called atomic.h.

http://www.nongnu.org/avr-libc/user-manual/atomic_8h.html

It seems I can do the same thing just by adding it as an include. Am I understanding that right? Or would I need to do more than just adding it at the start of my code?

Yes, you need to do more then just add it... It just gives you some macro's to enable and disable interrupts easy by putting it into a block. Aka, disabling global interrupts when entering the block and enabling them again when exiting. But yeah, it's up to you to make the blocks then...

septillion:
Yes, you need to do more then just add it... It just gives you some macro's to enable and disable interrupts easy by putting it into a block. Aka, disabling global interrupts when entering the block and enabling them again when exiting. But yeah, it's up to you to make the blocks then...

Sounds like I'd be better off just adding the sei and cli around the commands that matter!

Sounds like I'd be better off just adding the sei and cli around the commands that matter!

Add some comments, too, and have everything that the library offers.

Also if your interrupt is being triggered by something external (button push, etc..) then you will want to debounce it.