I found the following code within an example for performing very fast changes on a PWM-output. It works, however I'm wondering about some details.
TIMER2 was set up in setup() as follows:
TCCR2A = 0; // We need no options in control register A
TCCR2B = (1 << CS21); // Set prescaller to divide by 8
TIMSK2 = (1 << OCIE2A); // Set timer to call ISR when TCNT2 = OCRA2
OCR2A = 32; // sets the frequency of the generated wave
sei(); // Enable interrupts to generate waveform!
If I understand that correctly, the timer will run until overflow and generate interrupts any time in between as defined by OCR2A.
ISR(TIMER2_COMPA_vect) { // Called each time TCNT2 == OCR2A
static byte index=0; // Points to successive entries in the wavetable
OCR1AL = wave[index++]; // Update the PWM output
asm("NOP;NOP"); // Fine tuning
TCNT2 = 6; // Timing to compensate for time spent in ISR
}
TIMER2 is used to call this routine in equidistant points in time. To adapt the timespan between two calls of the ISR the author sets OCR2A and within the ISR resets TCNT2. As the timer is reset at the end of the ISR there's some time "already gone" written into the start value of the timer. However there are two things I don't understand.
Why isn't CTC mode used by setting WGM21 in TCCR2A? This should call the ISR in precise intervals.
If not using CTC mode the counter has to be reset by the ISR. But why isn't that done directly at the beginning of the ISR? Everytime the ISR gets some minor changes the correction value written into TCNT2 has to be changed.
Am I missing some vital detail? Or is my idea of using CTC better?
For sake of completeness, the only other things done in setup() are configurations on timer1:
pinMode(9, OUTPUT); // Make timer's PWM pin an output
TCCR1B = (1 << CS10); // Set prescaler to full 16MHz
TCCR1A |= (1 << COM1A1); // PWM pin to go low when TCNT1=OCR1A
TCCR1A |= (1 << WGM10); // Put timer into 8-bit fast PWM mode
TCCR1B |= (1 << WGM12);
loop() is empty.