Using Timer/Counter1 to toggle OC1A

I am trying to set up Timer/Counter1 to toggle OC1A (Arduino Pin #9) at a frequency of 50 Hz. I have written the following code.

void setup() {
  cli();//stop interrupts while we set up the timer
  TCCR1B = B00000000;// Stop Timer/Counter1 clock by setting the clock source to none.
  TCCR1A = B00000000;// Set Timer/Counter1 to normal mode.
  TCNT1  = 0;// Set Timer/Counter1 to 0
  OCR1A = 19999;// Set the Output Compare A for Timer/Counter1, 100 Hz
  TCCR1A = B01000010;// Set Timer/Counter1 to CTC mode. Set OC1A to toggle.
  TCCR1B = B00000010;// Start Timer/Counter1 clock by setting the source to CPU source. Set prescalar to 1/8 (2Mhz).
  sei();//allow interrupts
  DDRB |= B00000010; //Set OC1A as an Output.
}
void loop() {
}

I get no errors from the compiler, but on an oscilloscope and/or frequency counter, I get no output.

What am I missing?

TCCR1A = B01000010;// Set Timer/Counter1 to CTC mode. Set OC1A to toggle.

I do not think you have the correct mode. Where did you get that mode 2 (bit set in WGM11) is CTC to OCR1A? It is PWM to 511.

For CTC to OCR1A use Mode 4 (bit set in WGM12)

TCCR1A = B01000100;// Set Timer/Counter1 to CTC mode. Set OC1A to toggle.

cattledog:
For CTC to OCR1A use Mode 4 (bit set in WGM12)

TCCR1A = B01000100;// Set Timer/Counter1 to CTC mode. Set OC1A to toggle.

Thank you!
That fixed it partly... I am getting an output.
My output is 15 Hz, not 50 Hz.
I am using a full-power oscillator on XTAL1 and XTAL2, 16 MHz. So, my prescaler is set to 8 (16000000/8 = 2000000) and I am counting 2000. I thought I fixed my error in OCR1A

OCR1A = 1999;// Set the Output Compare A for Timer/Counter1, (16000000 / (8 * 100)) -1

But, my output is still about 15 Hz.

I think that OCR1A should be 20000. At 16Mhz, each clock cycle is .0625us and with a prescaler 8 > .5 us per tick. So, you get a compare match ever 10000us = 10ms. You toggle the output so each complete square wave period is at 20ms = 50Hz.

How are you measuring the 15Hz.? I think something is wrong with the either the measurement technique or the oscillator frequency.

cattledog:
I think that OCR1A should be 20000. At 16Mhz, each clock cycle is .0625us and with a prescaler 8 > .5 us per tick. So, you get a compare match ever 10000us = 10ms. You toggle the output so each complete square wave period is at 20ms = 50Hz.

How are you measuring the 15Hz.? I think something is wrong with the either the measurement technique or the oscillator frequency.

I am measuring the frequency with an oscilloscope, HP 54645D. I have ground connected to ground and the probe on physical pin 15 of the ATmega328P. If I connect the probe to physical pin 9 or 10, and adjust the time division and voltage trigger, I get very close to 16 MHz.
I have found that it doesn’t matter what I change the value to in the following line…

OCR1A = 19999;

I still get 15 Hz.

In the complete datasheet, there is something about accessing 16-bit registers for OCR1A, but I am unclear if this applies here. Do I need to set the high and low bytes seperately? If so, what does that code look like?

I apologize, but I gave you some wrong advice. To set Mode 4 CTC to OCR1A you need to set the bit in WGM12 which is on TCCR1B, not TCCR1A. The waveform generation mode bits are split across two registers.

Use these settings

TCCR1A = B01000000;// Set OC1A to toggle.
  TCCR1B = B00001010;//Set WGM12 for CTC to OCR1A, pre scaler 8

n the complete datasheet, there is something about accessing 16-bit registers for OCR1A, but I am unclear if this applies here. Do I need to set the high and low bytes seperately?

No. The Arduino ide and compiler takes care of that.

cattledog:
I apologize, but I gave you some wrong advice. To set Mode 4 CTC to OCR1A you need to set the bit in WGM12 which is on TCCR1B, not TCCR1A. The waveform generation mode bits are split across two registers.

Use these settings

TCCR1A = B01000000;// Set OC1A to toggle.

TCCR1B = B00001010;//Set WGM12 for CTC to OCR1A, pre scaler 8





No. The Arduino ide and compiler takes care of that.

The datasheet says the compiler should take care of that, and thank you for confirming. When you posted to set TCCR1A to B01000100, I went and looked at the datasheet again, and the table for WGM1, and the table for the register, and saw bits 3 and 4 having no defined use. But, I couldn't see where WGM12 or WGM13 and didn't think they'd be split up into a different register, but they are. Thank you for catching that, and thanks for your help. 50 Hz exactly, hardware CTC, love it!

cattledog:
I think that OCR1A should be 20000.

No, 19999 is correct, this is the value of TOP, and the counter counts upto and including TOP before
wrapping to zero in fast mode.

Now that I have set up the Timer/Counter1 to toggle OC1A, I want to add an ISR that increments a count each time OC1A toggles.

ISR(TIMER1_COMPA_vect) { // Interrupt Service Routine to increment count each time timer1 rolls over
  thousandthsOfSeconds++;
}

This never fires unless I disable OC1A pin toggle.
Do they share the same interrupt vector?
According to the datasheet, this vector clears when handled by the ISR...
Would it be better to move the pin toggle into my own ISR and increment and toggle in the same ISR?
Would it be better or is it possible to trigger an ISR based on the toggle of the pin?

This never fires unless I disable OC1A pin toggle.

I can not confirm this. Please post our code. Have you enabled the Output Compare Interrupt

 TIMSK1 = B00000010;//enable compare matchinterrupt

Here’s a test sketch where I toggle pin9 with your CTC to OCR1A toggle routine. I jumper pin 9 to pin 2 and count those outpulse pulses with an interrupt. I also have a compare match count with an output compare interrupt.

volatile unsigned long pulseInterruptCount = 0;
unsigned long copyPulseInterruptCount = 0;

volatile unsigned long compareMatchCount = 0;
unsigned long copyCompareMatchCount = 0;

unsigned long lastRead = 0;
unsigned long interval = 1000;//one second

void setup()
{
  Serial.begin(115200);
  Serial.println("start...");

  cli();//stop interrupts while we set up the timer
  TCCR1B = B00000000;// Stop Timer/Counter1 clock by setting the clock source to none.
  TCCR1A = B00000000;// Set Timer/Counter1 to normal mode.
  TCNT1  = 0;// Set Timer/Counter1 to 0
  OCR1A = 19999;// Set the Output Compare A for Timer/Counter1, 100 Hz
  TCCR1A = B01000000;// Set Timer/Counter1 to CTC mode. Set OC1A to toggle.
  TCCR1B = B00001010;// Start Timer/Counter1 clock by setting the source to CPU source. Set prescalar to 1/8 (2Mhz).
  TIMSK1 = B00000010;//enable compare matchinterrupt
  sei();//allow interrupts
  DDRB |= B00000010; //Set OC1A as an Output.

  pinMode(2, INPUT_PULLUP);
  attachInterrupt(0, isrCount, RISING); //rising interrupt signal to pin 2 will be half of compare match count
  //attachInterrupt(0, isrCount, CHANGE); //change interrupt signal to pin 2 will be equal to compare match count
}

void loop()
{
  if (millis() - lastRead >= interval) //read interrupt count every second
  {
    lastRead  += interval;
    // disable interrupts,make copy of count,reenable interrupts
    noInterrupts();
    copyPulseInterruptCount = pulseInterruptCount;
    pulseInterruptCount = 0;
    copyCompareMatchCount = compareMatchCount;
    compareMatchCount = 0;
    interrupts();
    Serial.print("Interrupt count  ");
    Serial.println(copyPulseInterruptCount);
    Serial.print ("Compare Match count ");
    Serial.println(copyCompareMatchCount);

  }
}

void isrCount()
{
  pulseInterruptCount++;
}

ISR(TIMER1_COMPA_vect) // Interrupt Service Routine to increment count each time timer1 rolls over
{ 
  compareMatchCount++;
}

cattledog:
Please post our code.

I did have TIMSK1 set to enable compA vector. It wasn't a problem with the ISR, but how I was handling the variables.... I don't know what exactly I changed, but it works now, without having to jumper pins etc.

const int PrintTimeButtonPin = 2;// push-button to GND
const int CalibrationPin = 15;// OCR1A
int lastPrintTimeButtonState = HIGH;
volatile unsigned long thousandthsOfSeconds = 0UL;// named to avoid use of milliseconds; to avoid confusion from overuse
unsigned long serialOutTimestamp = 0UL;

void setup() {
  cli();//stop interrupts while we set up the timer
  TCCR1B = B00000000;// Stop Timer/Counter1 clock by setting the clock source to none.
  TCCR1A = B00000000;// Set Timer/Counter1 to normal mode.
  TCNT1  = 0;// Set Timer/Counter1 to 0
  OCR1A = 1999;// Set the Output Compare A for Timer/Counter1, 1 MHz
  TIMSK1 |= B00000010;// Set to enable Compare A Match Vector for ISR; leave other vectors unchanged
  TCCR1A = B01000000;// Set OC1A to toggle.
  TCCR1B = B00001010;// Set WGM12 for CTC to OCR1A. Set clock source to F_CPU/8 (2Mhz).
  sei();//allow interrupts
  //DDRB |= B00000010; //Set OC1A as an Output.
  pinMode(CalibrationPin, OUTPUT);
  pinMode(PrintTimeButtonPin, INPUT_PULLUP);//mode INPUT_PULLUP to use the internal pullup resisitor

  Serial.begin(9600);
}
void loop() {
  int PrintTimeButtonState = digitalRead(PrintTimeButtonPin);
  if (PrintTimeButtonState != lastPrintTimeButtonState && PrintTimeButtonState == LOW) {// looks for button to go from HIGH to LOW
    unsigned long timeInMilliseconds;
    if (whatTimeIsIt(timeInMilliseconds) - serialOutTimestamp >= 1000UL) {// Prevents button pressed faster than 1 second, also debounces
      serialOutTimestamp = timeInMilliseconds;
      lastPrintTimeButtonState = PrintTimeButtonState;
      Serial.println(timeInMilliseconds);
    }
  }
  else lastPrintTimeButtonState = PrintTimeButtonState;
}

ISR(TIMER1_COMPA_vect) { // Interrupt Service Routine to increment count each time timer1 rolls over
  thousandthsOfSeconds++;
}

unsigned long whatTimeIsIt(unsigned long &milliseconds) { // function to read the current time; avoids rollover between reading 4 bytes of 32-bit variable
  cli();//stop interrupts while we read thousandthsOfSeconds
  milliseconds = thousandthsOfSeconds;
  sei();//allow interrupts
  return milliseconds;
}

I figured out what it was…

TCCR1B = B00000000;// Stop Timer/Counter1 clock by setting the clock source to none.
TCCR1A = B00000000;// Set Timer/Counter1 to normal mode.

If I remove these lines, assuming they aren’t necessary, it doesn’t work.
So, maybe it’s necessary to put the timer in a known state prior to…

TCNT1  = 0;// Set Timer/Counter1 to 0
OCR1A = 1999;// Set the Output Compare A for Timer/Counter1, 1 MHz
TIMSK1 |= B00000010;// Set to enable Compare A Match Vector for ISR; leave other vectors unchanged

maybe it’s necessary to put the timer in a known state

Yes. The Arduino IDE sets up the timers with default values, for analogWrite() pwm.

Explicitly setting the registers to 0 before setting custom values is important.

Its easy enough to see the presets

void setup() {

  byte a;
  byte b;

  Serial.begin(9600);
  Serial.print("Register");
  Serial.print("\t");
  Serial.println("Bit Values");
  Serial.println();

  a = TCCR0A;
  Serial.print("TCCR0A");
  printRegister(a);

  b = TCCR0B;
  Serial.print("TCCR0B");
  printRegister(b);

  a = TCCR1A;
  Serial.print("TCCR1A");
  printRegister(a);

  b = TCCR1B;
  Serial.print("TCCR1B");
  printRegister(b);

  a = TCCR2A;
  Serial.print("TCCR2A");
  printRegister(a);

  b = TCCR2B;
  Serial.print("TCCR2B");
  printRegister(b);


}

void loop() {}

void printRegister(byte v)
{
  Serial.print("\t");
  Serial.print("\t");
  for (int i = 7; i > -1; i-- )
  {
    Serial.print((v >> i) & 0X01);//shift and select first bit, no speed advantage
  }

  Serial.println();
}
Register	Bit Values

TCCR0A		00000011
TCCR0B		00000011
TCCR1A		00000001
TCCR1B		00000011
TCCR2A		00000001
TCCR2B		00000100