ATMega328P Timer2 in CTC mode

I thought I knew how the AVR timers worked, but apparently not! I've been tearing my hair out for the last couple of hours trying to understand why the following code on an Arduino Nano running at 16 Mhz doesn't generate a 1 KHz square wave on pin 11.

void setup(void) {
   pinMode(11, OUTPUT);
   TCCR2B = 0; // stop and setup timer2 for 1 Khz square wave on OC2A (pin 11)
   TCNT2 = 0;
   TIMSK2 = 0; // no interrupts needed
   //OCR2A = F_CPU / (1000UL * 2 * 64)  - 1; // (clk/(freq*2*prescale)) - 1
   OCR2A = 125;
   TCCR2A = 0b01000010;  // "toggle OC2A on match, CTC mode"
   TCCR2B = 0b00000100;  // "CTC mode, clk/64 prescaling, GO!"
}
void loop(void) { }

It's generating a 125 Khz square wave, as if OCR2A were zero. What am I doing wrong??

I ALWAYS clear TCCRxA first, and in this case, that fixes your problem too.

I don't know why that works, and yours does not.

BTW OCR2A should be set to 124 for 1 kHz.

void setup(void) {
   pinMode(11, OUTPUT);
   TCCR2A = 0;  // ALWAYS clear this first
   TCCR2B = 0; // stop and setup timer2 for 1 Khz square wave on OC2A (pin 11)
   TCNT2 = 0;
   TIMSK2 = 0; // no interrupts needed
   //OCR2A = F_CPU / (1000UL * 2 * 64)  - 1; // (clk/(freq*2*prescale)) - 1
   OCR2A = 125;
   TCCR2A = 0b01000010;  // "toggle OC2A on match, CTC mode"
   TCCR2B = 0b00000100;  // "CTC mode, clk/64 prescaling, GO!"
}
void loop(void) { }

Thank you, thank you! That indeed fixes it, and I don't know why either. I thought that turning off the timer by setting CS22=CS21=CS20=0 in TCCR2B would put it in a state to be initialized, but apparently not.
You are right about OCR2A needing to be 124, of course. I forgot the -1 when I "hand compiled" the compile-time expression to make sure there wasn't some overflow going on.

There is a clear reason for this and I can explain.

First, when setup() in Arduino core initialize Timer2 with Phase Correct PWM Mode. (TCCR2A = 0x01)
Because use for analogWrite().
In Phase Correct PWM mode, the update timing of OCR2A is when the timer reaches the TOP value.

And you changed timer mode immediately after writing OCR2A and before it was updated.
This means that the setting you are writing to has not yet been update to the OCR2A register.
It is the OCR2A update was not done, the buffered value has been lost.

Yes, that the value of OCR2A is still 0.
This causes the corresponding phenomenon.

If you clear the Timer mode first, OCR2A will update immediately.

Thanks for that explanation! Karma added.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.