Weird behaviour of the Atmega328p Timer1 in CTC mode

I am using Arduino Pro Mini with Atmega328P, 3.3V, 8MHz. I need it to generate permanently a 125kHz square wave. For that, I use the 16-bit Timer1 in the CTC mode with output to OC1A connected to pin 9. (Why the 16-bit timer? Because Timer0 is used by the core for micros(), and Timer2 uses either the MOSI or INT1 pins, which I need for something else.)

Here's what I do:

void setup() {
  // Timer 1, CTC: 125 kHz carrier:
  OCR1A = 31; // This divides the timer frequency -- 8MHz -- by 32*2 = 64 
  TCCR1A = bit(COM1A0); // Toggle
  TCCR1B = bit(WGM12) | bit(CS10);
  pinMode(9, OUTPUT);
}

void loop() {
}

This is supposed to generate what I need, but instead I get a wave of about 4MHz, no matter what value I put into OCR1A. It was very puzzling and frustrating.

Eventually I decided to check what was the actual value of OCR1A:

void setup() {
  Serial.begin(115200);
  while(!Serial) {}
  // Timer 1, CTC: 125 kHz carrier:
  OCR1A = 31; // This divides the timer frequency -- 8MHz -- by 32*2 = 64
  TCCR1A = bit(COM1A0); // Toggle
  TCCR1B = bit(WGM12) | bit(CS10);
  pinMode(9, OUTPUT);
}

bool firstTime = true;
void loop() {
  if(firstTime) {
    firstTime = false;
     Serial.print("OCR1A "); Serial.println(OCR1A);
    // Timer 1, CTC: 125 kHz carrier:
    OCR1A = 31;
    Serial.println("===============");
     Serial.print("OCR1A "); Serial.println(OCR1A);
  }
}

Guess what the output was:

22:36:52.768 -> OCR1A 0
22:36:52.768 -> ===============
22:36:52.768 -> OCR1A 31

I assumed originally that the Arduino core was at fault by nullifying register OCR1A in between setup() and loop(). But @van_der_decken kindly advised that this was done by writing to TCCR1A, thank you! I believe this was not documented in the datasheet.

Additional Serial.prints revealed that it was the write to TCCR1A that zeroed out OCR1A, not the core.

Writing to OCR1A after setting up TCCR1A and TCCR1B resulted in a 125KHz signal on pin 9.

void setup() {
  Serial.begin(115200);
  while(!Serial) {}
  TCCR1A = bit(COM1A0); // Toggle
  TCCR1B = bit(WGM12) | bit(CS10);
  // Timer 1, CTC: 125 kHz carrier:
  OCR1A = 31;
  pinMode(9, OUTPUT);
}

bool firstTime = true;
void loop() {
  if(firstTime) {
    firstTime = false;
    Serial.print("OCR1A "); Serial.println(OCR1A);
  }
}
baudrate=115200
Connected to /dev/ttyUSB0! Press CTRL-C to exit.
OCR1A 31
1 Like

Great finding, thank you!

I must apologize: this was not the core's bug, but rather the Atmel's one. At least they didn't mention that in the datasheet.

Should I change the title or remove the post altogether?

Section 16.7. At the bottom of page 124 in the copy I have. Right under figure 16-4

The OCR1x Register is double buffered when using any of the twelve Pulse Width Modulation
(PWM) modes. 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 Com-
pare Register to either TOP or BOTTOM of the counting sequence.

It wasn't being zeroed. It was buffered and hadn't changed yet. When you switch to CTC mode the buffering got turned off so it never got loaded.

2 Likes

There are several gotchas with the timers due to the double buffering.

Experienced people learned to clear/set the timer control registers TCCR1A and B before making any changes to other timer registers.

3 Likes

You can change the title if you want, but don't delete it. It may be useful to someone else later. And it would be against the forum rules.

1 Like

Another thing to be careful with when using CTC mode is that if TCNT1 is ahead of OCR1 when you set it then you have to wait until the timer wraps all the way around before your pulse starts. Usually I zero out TCNT1 on the line immediately before or after I set OCR1.

This is especially important when setting OCR1 to small values like you are.

1 Like

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