Timer/counter2 - ordering of setup gives different outcomes

I have been working through the Atmega328P datasheet sections on timers and would appreciate advice about why very similar code gives different results.

Using a nano clone with IDE version 1.8.12

The code toggles pin 13 using Timer/counter 2 in match/compare mode when the counter (prescaled by 1024) reaches OxFF (set in register OCR2A).

Pin 13 should have a frequency of about 30 Hz. When OCR2A is set after the control registers it works as expected. When OCR2A is set before the control registers the output is at about 8 kHz which is what would happen if it was set to zero. I can’t find anything in the datasheet which explains why setting the compare register value before setting the control registers has this effect. While an explanation is desirable, being pointed to where this behaviour is documented would be even more welcome.

Thanks in advance.

void setup() {
  pinMode(13, OUTPUT);
  cli();

  OCR2A = 0xFF; // when set here => pin13 toggles at ~ 8 kHz  

  TCCR2A = (1 << WGM21); //set to mode 2 (compare match timer/counter with OCR2A)
  TCCR2B = (1 << CS22) | (1 << CS21) | (1 << CS20) ; //prescaler to 1024
  TIMSK2 = (1 << OCIE2A); //enables ISR for compare match

//  OCR2A = 0xFF; // when set here => pin13 toggles at 30.5 Hz as expected

  sei();
}

ISR(TIMER2_COMPA_vect) { //ISR runs on counter/OCR2A match => toggles pin13
  PORTB ^= (1 << PB5);
}

void loop() {
}

Arduino configures and runs the timers for analogWrite(). Clear the configuration registers before reconfiguring the timer.

  TCCR2A = 0;
  TCCR2B = 0;
  TIMSK2 = 0;

  OCR2A  = 0xFF; // now this works as expected

  TCCR2A = (1 << WGM21); //set to mode 2 (compare match timer/counter with OCR2A)
  TCCR2B = (1 << CS22) | (1 << CS21) | (1 << CS20) ; //prescaler to 1024
  TIMSK2 = (1 << OCIE2A); //enables ISR for compare match

Thanks, but I still have the same issue because I don’t understand where the difference is coming from: the values for TCCR2A/B and TIMSK2 are the same when the following sketch is run when OCR2A isset before/after the timer control registers even if they are explicitly zeroed as you suggest:

set OCR2A before timer control registers:
TCCR2A: 10b
TCCR2B: 111b
TIMSK2: 10b
OCR2A: 11111111b

pin toggles at 8 kHz

set OCR2A after timer control registers:
TCCR2A: 10b
TCCR2B: 111b
TIMSK2: 10b
OCR2A: 11111111b

pin toggles at 30 Hz

There is clearly some difference happening somewhere and I am still at a loss to work out what is controlling the timer behaviour other than these registers and would like to know where it is coming from. I am glad you can point me to the analog write area but some more detail would be very helpful.

void setup() {
  Serial.begin(115200);
  cli();
  OCR2A = 0xFF; // when enabled => pin13 toggles at ~ 8 kHz
  pinMode(13, OUTPUT);
  TCCR2A = 0;
  TCCR2B = 0;
  TIMSK2 = 0;
  TCCR2A = (1 << WGM21); //set to mode 2 (compare match timer/counter with OCR2A)
  TCCR2B = (1 << CS22) | (1 << CS21) | (1 << CS20) ; //prescaler to 1024
  TIMSK2 = (1 << OCIE2A); //enables ISR for compare match
//  OCR2A = 0xFF; // when enabled => pin13 toggles at 30.5 Hz
  sei();
  Serial.print("TCCR2A: \t"); Serial.println(TCCR2A, BIN);
  Serial.print("TCCR2B: \t"); Serial.println(TCCR2B, BIN);
  Serial.print("TIMSK2: \t"); Serial.println(TIMSK2, BIN);
}

ISR(TIMER2_COMPA_vect) { //toggles pin13
  PORTB ^= (1 << PB5);
}

void loop() {
}

Or as a single sketch - TCCR2A/B, TIMSK2, OCR2A are the same throughout but the output differs.

void setup() {
  Serial.begin(115200);
  cli();
  OCR2A = 0xFF; // when enabled => pin13 toggles at ~ 8 kHz
  pinMode(13, OUTPUT);
  TCCR2A = 0;
  TCCR2B = 0;
  TIMSK2 = 0;
  TCCR2A = (1 << WGM21); //set to mode 2 (compare match timer/counter with OCR2A)
  TCCR2B = (1 << CS22) | (1 << CS21) | (1 << CS20) ; //prescaler to 1024
  TIMSK2 = (1 << OCIE2A); //enables ISR for compare match
  sei();
}

ISR(TIMER2_COMPA_vect) { //toggles pin13
  PORTB ^= (1 << PB5);
}

void loop() {
  while (millis() < 1000) {}
  Serial.println("\npin13 toggles at 8 kHz");
  Serial.print("TCCR2A: \t"); Serial.println(TCCR2A, BIN);
  Serial.print("TCCR2B: \t"); Serial.println(TCCR2B, BIN);
  Serial.print("TIMSK2: \t"); Serial.println(TIMSK2, BIN);
  Serial.print("OCR2A: \t"); Serial.println(OCR2A, BIN);
  OCR2A = OCR2A;
  Serial.println("\npin13 toggles at 30 Hz");
  Serial.print("TCCR2A: \t"); Serial.println(TCCR2A, BIN);
  Serial.print("TCCR2B: \t"); Serial.println(TCCR2B, BIN);
  Serial.print("TIMSK2: \t"); Serial.println(TIMSK2, BIN);
  Serial.print("OCR2A: \t"); Serial.println(OCR2A, BIN);
  while (1) {}
}

I think there is some sort of compiler action setting OCR2A to 0 .

If you add these lines before the early setting of OCR2A = FF , you see the 30Hz.

Serial.println(TCCR2A,BIN);
  Serial.println(TCCR2B,BIN);

I can’t recreate your experience: If I put those lines before setting OCR2A as 0xFF I still get an 8 KHz output on pin 13 for the first 1000ms until OCR2A is overwritten with itself.

In case I haven’t been clear - the previous code (updated and shown below to include the lines suggested) still produces an 8 kHz square wave for the first 1000 ms until the OCR2A register is read and written back to itself without anything changed from when it does what one expects (a 30 Hz output). Reading those registers again shows no change in their value. As you have replied, something is clearly going on, but I would appreciate knowing how the same values for TCCR2A/B, TIMSK2 and OCR2A (read initially after 1000ms and then after setting OCR2A to itself) can result in different outputs.

I can find nothing in the Timer2 section of the Atmega328P datasheet to point me to what is, seemingly, initially hiding the value of OCR2A from itself and would appreciate some hints to what is going on. Are there any other registers which are affecting this behaviour for example? The suggestion that it is a compiler phenomenon is hard to understand as I am reading the register values from a running, post-compilation Nano and the relevant values (as far as I understand) don’t change.

void setup() {
  Serial.begin(115200);
  cli();
  Serial.println(TCCR2A, BIN);
  Serial.println(TCCR2B, BIN);
  OCR2A = 0xFF; // when enabled => pin13 toggles at ~ 8 kHz
  pinMode(13, OUTPUT);
  TCCR2A = 0;
  TCCR2B = 0;
  TIMSK2 = 0;
  TCCR2A = (1 << WGM21); //set to mode 2 (compare match timer/counter with OCR2A)
  TCCR2B = (1 << CS22) | (1 << CS21) | (1 << CS20) ; //prescaler to 1024
  TIMSK2 = (1 << OCIE2A); //enables ISR for compare match
  sei();
}

ISR(TIMER2_COMPA_vect) { //toggles pin13
  PORTB ^= (1 << PB5);
}

void loop() {
  while (millis() < 1000) {}
  //Pin 13 showing a 8 kHz output and when the control and compare registers are read after 1000ms you get this: 
  Serial.println("\npin13 toggles at 8 kHz");
  Serial.print("TCCR2A: \t"); Serial.println(TCCR2A, BIN);
  Serial.print("TCCR2B: \t"); Serial.println(TCCR2B, BIN);
  Serial.print("TIMSK2: \t"); Serial.println(TIMSK2, BIN);
  Serial.print("OCR2A: \t"); Serial.println(OCR2A, BIN);
  // read the OCR2A register and put it back into OCR2A unchanged 
  OCR2A = OCR2A;
  // results in Pin 13 now showing a 30 Hz output on an oscilloscope 
  // the control and compare registers, when read, are identical to those when the output was 8 kHz
  Serial.println("\npin13 toggles at 30 Hz");
  Serial.print("TCCR2A: \t"); Serial.println(TCCR2A, BIN);
  Serial.print("TCCR2B: \t"); Serial.println(TCCR2B, BIN);
  Serial.print("TIMSK2: \t"); Serial.println(TIMSK2, BIN);
  Serial.print("OCR2A: \t"); Serial.println(OCR2A, BIN);
  while (1) {}
}

I can find nothing in the Timer2 section of the Atmega328P datasheet to point me to what is, seemingly, initially hiding the value of OCR2A from itself and would appreciate some hints to what is going on.

I'm with you, and don't understand. My practice, and every example you see, sets all the specific details after the mode selection.

My advice is to live with it and move on. :slight_smile: