What the heck is double buffering, and why should you care?
While developing a new activity for my microcontrollers class, I learned the value of double buffering the hard way. I decided to do a “simple” activity where students use a potentiometer to set the value of OCR1A. Using timer/counter 1 in CTC mode with the Compare Output Mode bits set to toggle OC1A on a compare match, an LED connected to pin OC1A will toggle at a changing frequency based on the value read in from the potentiometer. This is a nice warm-up activity to get students to feel comfortable with the timer/counter output compare units before diving into pulse-width modulation modes.
However, I noticed that the LED would frequently skip toggles. (This is actually not what happened, keep reading to find out what really happened.) I confirmed that I had the timer/counter 1 registers assigned properly, the LED was functional, and OC1A was configured as an output pin using the data direction register. None of these pointed to the issue.
Time to break out the big guns: a tabletop multimeter and an oscilloscope. (I can hear my students collectively groaning at the very thought… you only grab the ‘scope when things have gone horribly wrong.) The multimeter confirmed I was getting normal outputs from my potentiometer. And the oscilloscope indicated that there was definitely something weird going on with the OC1A pin:

I then decided to use the serial monitor to display the values of the ADC, OCR1A, and TCNT1. I let the autoscroll hypnotize me until I noticed a skipped pulse, and then stopped autoscroll to see what was going on. I took a screenshot of the output:

Notice how, right when the value stored in TCNT1 is really close to OCR1A (which is the assigned value of TOP), the ADC value went from 580 to 579. This is very normal; any potentiometer output is going to be slightly noisy. At this point the new value assigned to OCR1A would be smaller than TOP, causing timer/counter 1 to completely miss a compare match.
What’s actually happening isn’t a skipped toggle. It’s a skipped compare match. What this means might be slightly more obvious if we consider a faster frequency output:

Notice on the oscilloscope for a faster pulse how a skipped compare match doesn’t just skip one expected period of oscillation. The value on timer/counter 1 didn’t reset at TOP (OCR1A). Instead, it counts up through MAX, overflows back to zero, and then has to make the next compare match before the pin will toggle again.
The datasheet for the ATmega328P has this to say about using the timer/counter units in CTC mode:
For the normal and clear timer on compare (CTC) modes of operation, the double buffering is disabled. The double buffering synchronizes the update of the OCR1x compare register to either TOP or BOTTOM of the counting sequence. The synchronization prevents the occurrence of odd-length, non-symmetrical PWM pulses, thereby making the output glitch-free.
Double buffering ensures that the value of TOP won’t change until after a compare match, preventing this issue from occurring. However, this feature is not enabled in CTC mode!
The moral of the story is this: if noise might cause the value of TOP to change when the value in the timer/counter output compare unit is close to TOP, then you might miss a compare match if the timer/counter is operating in CTC mode. This can be rectified either by using a PWM mode, or by using a less noisy input device to set the value of TOP.