Different timing on Timer0 and Timer2

Hi!
I try to run Timer0 and Timer2 at different speeds on an Arduino Uno, but no matter what I set the bits to they count exactly at the same speed :frowning:

My code:

volatile uint32_t cnt0, cnt2, c0, c2 = 0;

void setup() {
  cli();                      //stop interrupts while we setup the timers

  /*1. First we reset the control register to make sure we start with everything disabled.*/
  TCCR0A = 0;                 // Reset entire TCCR0A to 0 
  TCCR0B = 0;                 // Reset entire TCCR0B to 0
  TCCR2A = 0;                 // Reset entire TCCR2A to 0 
  TCCR2B = 0;                 // Reset entire TCCR2B to 0
 
  /*2. We set the prescalar to the desired value */  
  TCCR0B |= B00000001;        //Set CS00 to 1 so we get no prescalar
  TCCR2B |= B00000001;        //Set CS01 to 1 so we get no prescalar
  
  /*3. We enable compare match mode on register A */
  TIMSK0 |= B00000010;        //Set OCIE0A to 1 so we enable compare match A
  TIMSK2 |= B00000010;        //Set OCF2A to 1 so we enable compare match A
  
  /*4. Set the value of register A */
  OCR0A = 50; 
  OCR2A = 100;
  sei();                     //Enable back the interrupts

  Serial.begin(115200);
}

ISR(TIMER0_COMPA_vect){
  TCNT0  = 0;                  //First, set the timer back to 0 so it resets for next interrupt
  cnt0++;
}

ISR(TIMER2_COMPA_vect){
  TCNT2  = 0;                  //First, set the timer back to 0 so it resets for next interrupt
  cnt2++;
}


void loop() {
  noInterrupts();
  c0 = cnt0;
  c2 = cnt2;
  interrupts();
  Serial.print(c0);
  Serial.print(" ");
  Serial.println(c2);
}

What am I doing wrong? Thanx for helping me out!

Division factor 1 (prescaler 1) is not a good choice; operate TC0 and TC2 with division factor 1024 to see results.

Try the following sketch and observe that the compare match time changes as the contents of OCR0A and OCR2A registers are are changed.

volatile bool flag0 = false, flag2 = false;
volatile byte myCount0 = 0, myCount2 = 0;

void setup()
{
  Serial.begin(9600);
  cli();

  TCCR0A = 0;                 // Reset entire TCCR0A to 0
  TCCR0B = 0;                 // Reset entire TCCR0B to 0
  TCCR2A = 0;                 // Reset entire TCCR2A to 0
  TCCR2B = 0;                 // Reset entire TCCR2B to 0

  OCR0A = 50;   //3.2 ms
  OCR2A = 100;  //6.4 ms

  bitSet(TIMSK0, OCIE0A);
  bitSet(TIMSK2, OCIE2A);

  TCCR0B = 0x05;       //DVF = 1024
  TCCR2B = 0x07;       //DVF  = 1024
  sei();
}

void loop()
{
  if (flag0 == true)
  {
    Serial.print("OCF0A occured at: ");
    Serial.print(myCount0 * 0.064); Serial.println(" ms");
    flag0 = false;
    myCount0 = 0;
    TCCR0B = 0x05;
  }
  if (flag2 == true)
  {
    Serial.print("OCF2A occured at: ");
    Serial.print(myCount2 * 0.064); Serial.println(" ms");
    Serial.println("=============================");
    flag2 = false;
    myCount2 = 0;
    TCCR2B = 0x07;  //DVF 1024
  }

}

ISR(TIMER0_COMPA_vect)
{
  TCCR0B = 0x00;
  myCount0 = TCNT0;
  flag0 = true;
}

ISR(TIMER2_COMPA_vect)
{
  TCCR2B = 0x00;
  myCount2 = TCNT2;
  flag2 = true;
}

Output:

=============================
OCF0A occured at: 3.3 ms
OCF2A occured at: 6.5 ms
=============================
OCF0A occured at: 3.3 ms at clkTC0 = 16 MHz/1024
OCF2A occured at: 6.5 ms at clkTC2 = 16 MHz/1024
==========================================
1 Like

Please check the data sheet again. The prescalers for Timer2 are unique and the settings will actually give

TCCR0B = 0x05;       //DVF = 1024
TCCR2B = 0x05;       //DVF  = 128

Here's your original sketch with the prescalers of both timers set to 1024. The counts are 2x

volatile uint32_t cnt0, cnt2, c0, c2 = 0;

void setup() {
  cli();                      //stop interrupts while we setup the timers

  /*1. First we reset the control register to make sure we start with everything disabled.*/
  TCCR0A = 0;                 // Reset entire TCCR0A to 0 
  TCCR0B = 0;                 // Reset entire TCCR0B to 0
  TCCR2A = 0;                 // Reset entire TCCR2A to 0 
  TCCR2B = 0;                 // Reset entire TCCR2B to 0
 
  /*2. We set the prescalar to the desired value */  
  //TCCR0B |= B00000001;        //Set CS00 to 1 so we get no prescalar
  //TCCR2B |= B00000001;        //Set CS01 to 1 so we get no prescalar
  
  TCCR0B |= B00000101;        //Set CS00 to 5 so we get prescalar 1024
  TCCR2B |= B00000111;        //Set CS01 to 5 so we get prescalar 1024
  
  /*3. We enable compare match mode on register A */
  TIMSK0 |= B00000010;        //Set OCIE0A to 1 so we enable compare match A
  TIMSK2 |= B00000010;        //Set OCF2A to 1 so we enable compare match A
  
  /*4. Set the value of register A */
  OCR0A = 50; 
  OCR2A = 100;
  sei();                     //Enable back the interrupts

  Serial.begin(115200);
}

ISR(TIMER0_COMPA_vect){
  TCNT0  = 0;                  //First, set the timer back to 0 so it resets for next interrupt
  cnt0++;
}

ISR(TIMER2_COMPA_vect){
  TCNT2  = 0;                  //First, set the timer back to 0 so it resets for next interrupt
  cnt2++;
}


void loop() {
  noInterrupts();
  c0 = cnt0;
  c2 = cnt2;
  interrupts();
  Serial.print(c0);
  Serial.print(" ");
  Serial.println(c2);
}

The prescaler bits work different on the two Uno timers:

TCCR0B:
image

TCCR2B:
image

1 Like

Thank you for your replies! I should have mentioned this in my original question but In the end I wish to do audio manipulation. Specifically a very subtle audio pitch shift using one timer to read the ADC and the second to output to a DAC at a slightly slower speed. So one timer would ideally run at 44100 Hz or something in that ballpark and the other at 98,2% of this speed. A prescaler of 1024 gives too slow results. Even a prescaler of 8 gives too slow results I believe although I have a bit of trouble doing the math :roll_eyes:. So should I be using different chip all together?

Of course you should. The Uno processor is very old, and very under powered for real world audio applications. Also some processors have a built in DAC, which the Uno lacks.

1 Like

Yeah I guessed as much, but I'm new to the whole port manipulation thing and I find it kinda interesting so I thought I start at the UNO. Also it is kind of cheap and I have them laying around. So I guess an ESP32 or Pico might be the way to go... I'm really sorry if I wasted anybody's time but your feedback was not lost on me!

You are right! The data sheets says that it is 0x07 and it is found indeed correct by experiment.

In the past, while creating complementary waveforms for both channels of TC1 in Mode-14, I found due to @cattledog's courtesy that the TC1 should had been STARTED (connection of clkTC1) once all the necessary initializations are done! The same thing could be followed for TC0 and TC2.

For Audio you may want to look at the Teensy boards

1 Like

PJRC and Paul are big supporters of the Arduino ecosystem, and purchasing something from them is likely to work out well.

My experience with a Teensy 3.2 and the support available from PJRC has been nothing but positive.

Thank you for your feedback! I have been considering Teensies if the Arduino route would not work out, but since Iā€™m developing a product to be sold, Iā€™m looking for a board that is less expensive. Perhaps I could release a premium version w/ flac like audio quality at a higher price point and use Teensies for that!

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