[SOLVED]Timer2 is slightly less accurate

Hi everyone, I have been doing some sketches on timer interrupts in CTC(clear timer on compare match) mode,since I needed my project to work on real time and, I resorted for interrupts. But doing so, I found out that the timer interrupts can be triggered more accurately with timer1 than timer2 of the atmega328. Do anyone know the reason?

All interrupts have a priority - timer0 interrupts have priority over timer1 which have priority over timer2 - so if all timers are firing interrupts then timer2 ISR may be delayed by the total time it takes to handle timer0 and timer1 ISRs, whereas timer0 ISR will always run immediately with predictable timing I believe.

[ actually its a little more subtle than that, timer0 cannot interrupt other ISRs but when timer0 ISR returns any pending interrupts are handled in priority order (ie timer1 before timer2). This will also be the case if two timers triggle simultaneously, the higher priority one will get handled first. ]

Thanks for that speed reply :).But I am not running any other timers when I run timer2. I am toggling the state of a digital pin and viewing it on a CRO to know the period of interrupt.

Here is my code:

For timer 1:

#include <avr/io.h>
#include <avr/interrupt.h>

volatile int x=0; 
// initialize timer, interrupt and variable
void timer1_init()
{
    // set up timer with prescaler = 64 and CTC mode
    TCCR1B |= (1 << WGM12)|(1 << CS11)|(1 << CS10);
 
    // initialize counter
    TCNT1 = 0;
 
    // initialize compare value
    OCR1A = 49;
 
    // enable compare interrupt
    TIMSK1 |= (1 << OCIE1A);
 
    // enable global interrupts
    sei();
}
 
// this ISR is fired whenever a match occurs
// hence, toggle led here itself..
ISR (TIMER1_COMPA_vect)
{
    if(x<10)
    {
    //toggle led here
    bitSet(PINB,4);
    }
    x=x+1;
}
 
int main(void)
{
    // connect led to pin PC0
    //DDRC |= (1 << 0);
    bitSet(DDRB,4);
    // initialize timer
    timer1_init();
 
    // loop forever
    while(1)
    {
        // do nothing
        // whenever a match occurs, ISR is fired
        // toggle the led in the ISR itself
        // no need to keep track of any flag bits here
        // done!
    }
    return 0;
}


********************************************************
#include <avr/io.h>
#include <avr/interrupt.h>

volatile int x=0; 
// initialize timer, interrupt and variable
void timer2_init()
{
    // set up timer with prescaler = 64 and CTC mode
    TCCR2B |= (1 << WGM12)|(1 << CS11)|(1 << CS10);
 
    // initialize counter
    TCNT2 = 0;
 
    // initialize compare value
    OCR2A = 249;
 
    // enable compare interrupt
    TIMSK2 |= (1 << OCIE2A);
 
    // enable global interrupts
    sei();
}
 
// this ISR is fired whenever a match occurs
// hence, toggle led here itself..
ISR (TIMER2_COMPA_vect)
{
    //if(x<10)
    //{
    //toggle led here
    bitSet(PINB,4);
    //}
    //x=x+1;
}
 
int main(void)
{
    // connect led to pin PC0
    //DDRC |= (1 << 0);
    bitSet(DDRB,4);
    // initialize timer
    timer2_init();
 
    // loop forever
    while(1)
    {
        // do nothing
        // whenever a match occurs, ISR is fired
        // toggle the led in the ISR itself
        // no need to keep track of any flag bits here
        // done!
    }
    return 0;
}

for Timer 2:

#include <avr/io.h>
#include <avr/interrupt.h>

volatile int x=0; 
// initialize timer, interrupt and variable
void timer2_init()
{
    // set up timer with prescaler = 128 and CTC mode
    TCCR2B |= (1 << WGM22)|(1 << CS22)|(1 << CS20);
 
    // initialize counter
    TCNT2 = 0;
 
    // initialize compare value
    OCR2A = 124;
 
    // enable compare interrupt
    TIMSK2 |= (1 << OCIE2A);
 
    // enable global interrupts
    sei();
}
 
// this ISR is fired whenever a match occurs
// hence, toggle led here itself..
ISR (TIMER2_COMPA_vect)
{
    //toggle led here
    bitSet(PINB,4);
}
 
int main(void)
{
    // connect led to pin PC0
    DDRC |= (1 << 0);
    bitSet(DDRB,4);
    // initialize timer
    timer2_init();
 
    // loop forever
    while(1)
    {
        // do nothing
        // whenever a match occurs, ISR is fired
        // toggle the led in the ISR itself
        // no need to keep track of any flag bits here
        // done!
    }
    return 0;
}

The Arduino system is using Timer0 all the time.

...R

How to turn off Timer0?Should I do that explicitly? I suppose this is the timer which arduino uses for delay functions.

I think it is time to describe your overall project.

It must be something very interesting if the variability you are talking about matters.

...R

saravananm92: How to turn off Timer0?Should I do that explicitly? I suppose this is the timer which arduino uses for delay functions.

  TIMSK0 = 0x00 ;

Robin2: I think it is time to describe your overall project.

It must be something very interesting if the variability you are talking about matters.

Agree. Specifically, in what way is it inaccurate, and by how much? What exactly are you seeing on the scope?

Consider the differences between the two sketches.

The first sets Timer1 to interrupt at a 5000Hz rate. The second sets Timer2 to interrupt at a 1000Hz rate.

The ISR in the second sketch simply toggles the pin. But in the first sketch it only toggles the pin if x<10. This would seem to give the same frequency on the output pin, but the variable x is never zeroed. So the output is probably five cycles, but then x continues to be incremented and will overflow and go negative after about 32K interrupts. At that point the toggle will happen at every interrupt until x counts back to zero, then the whole cycle repeats.

If the goal is for the two sketches to output the same frequency, then it seems like there would be more than a slight difference between the two.

saravananm92: Here is my code:

That isn't an Arduino sketch, is it? You've provided your own main() and don't initialise or make any calls to the Arduino runtime.

PeterH:
That isn’t an Arduino sketch, is it?

It is! Just saw this recently in another thread.

You’ve provided your own main() and don’t initialise or make any calls to the Arduino runtime.

Maybe that’s the point :wink:

[quote author=Jack Christensen link=topic=232287.msg1675962#msg1675962 date=1397234075] It is! Just saw this recently in another thread. [/quote]

If it isn't using the Arduino runtime then I don't see how you could consider it an Arduino sketch - it is just a bit of firmware running on the Arduino hardware.

PeterH: [quote author=Jack Christensen link=topic=232287.msg1675962#msg1675962 date=1397234075] It is! Just saw this recently in another thread.

If it isn't using the Arduino runtime then I don't see how you could consider it an Arduino sketch - it is just a bit of firmware running on the Arduino hardware. [/quote]

Guess I'd have to look up the definition of an Arduino sketch. IMHO, if the Arduino IDE compiles it, and the Arduino hardware runs it, then I don't have any issue with calling it a sketch. Funny because I hate the word sketch anyways. Whatever. YMMV, a rose by any other name ... :D

saravananm92:
Here is my code:
for Timer 2:

    // set up timer with prescaler = 128 and CTC mode

TCCR2B |= (1 << WGM22)|(1 << CS22)|(1 << CS20);

That is not CTC mode, it’s a “reserved” mode!

This would be CTC mode:

    TCCR2B |= (1 << CS22)|(1 << CS20);
    TCCR2A = (1 << WGM21);

Assuming the aim is to output 500Hz from both timers, this should do the trick. I combined both into one sketch and also changed the output pins to PC1 and PC2:

#include <avr/io.h>
#include <avr/interrupt.h>

volatile int x = 0; 

void timer1_init()
{
    TCCR1B = _BV(WGM12) | _BV(CS11) | _BV(CS10);    //prescaler = 64 and CTC mode
    TCNT1 = 0;                 //initialize counter
    OCR1A = 49;                //initialize compare value
    TIMSK1 = _BV(OCIE1A);      //enable compare interrupt
}

void timer2_init()
{
    TCCR2B = _BV(CS22) | _BV(CS20);    //prescaler = 128 and CTC mode
    TCCR2A = _BV(WGM21);
    TCNT2 = 0;                 //initialize counter
    OCR2A = 124;               //initialize compare value
    TIMSK2 = _BV(OCIE2A);      //enable compare interrupt
}

//Timer1 compare match
ISR (TIMER1_COMPA_vect)
{
    if (++x >= 5) {
        PINC |= _BV(PINC1);    //toggle output pin
        x = 0;
    }
}

//Timer2 compare match
ISR (TIMER2_COMPA_vect)
{
    PINC |= _BV(PINC2);        //toggle output pin
}

int main(void)
{
    DDRC = _BV(DDC2) | _BV(DDC1);    //timer1 ISR output on PC1, timer2 ISR output on PC2
    timer1_init();                   //initialize timers
    timer2_init();
    sei();                           //enable global interrupts

    while(1) {}                      //loop forever and do nothing here, the ISRs do all the work
    return 0;
}

If we’re not real picky about which are the output pins, we can use the timers’ output compare match facility to dispense with the interrupts (timer1 output on PB1, timer2 on PB3):

#include <avr/io.h>

void timer1_init()
{
    TCCR1B = _BV(WGM12) | _BV(CS11) | _BV(CS10);    //prescaler = 64 and CTC mode
    TCCR1A = _BV(COM1A0);                //toggle OC1A (PB1) on compare match
    OCR1A = 249;                         //initialize compare value
}

void timer2_init()
{
    TCCR2B = _BV(CS22) | _BV(CS20);      //prescaler = 128 and CTC mode,
    TCCR2A = _BV(COM2A0) | _BV(WGM21);   //toggle OC2A (PB3) on compare match 
    OCR2A = 124;                         //initialize compare value
}

int main(void)
{
    DDRC = _BV(DDC2) | _BV(DDC1);    //timer1 ISR output on PB1, timer2 ISR output on PB3
    DDRB = _BV(DDB1) | _BV(DDB3);    //timer1 compare match output on PB1 (OC1A), timer2 on PB3 (OC2A)
    timer1_init();                   //initialize timers
    timer2_init();
    sei();                           //enable global interrupts

    while(1) {}                      //loop forever and do nothing here, the timers do all the work
    return 0;
}

Thanks everyone. I have to blame myself for not looking at the Datasheet properly :~. Thank you Jack for a detailed explanation. :)