Gnarflord
Gnarflord

Reputation: 230

Weird behaviour of timer2 on ATmega328

I'm currently working on a piece of code, which should wait for a comparator interrupt and execute some other code after a set amount of time. Now, I thought using Timer2 in CTC mode would be a good idea to make sure that the program waits for the right amount of time and came up with this:

void setup(){
  ...
  // Set up the timer
  TCCR2A = 0;
  TCCR2B = 0;
  TCNT2  = 0;
  OCR2A  = 255;                         // compare match register
  TCCR2A = (1 << WGM21);                // CTC mode
  TCCR2B = ((1 << CS22) | (1 << CS21)); // 256 prescaler
  TIMSK2 &= ~(1 << OCIE2A);             // disable interrupt
}

ISR(ANALOG_COMP_vect) {
  // switchTime is in µs, usual value: around 500µs
  // with a 16 Mhz crystal and a 256 prescale we need to devide
  // the switchTime by 16 (2^4)
  OCR2A = switchTime >> 4;
  TCNT2 = 0;                   // reset counter
  TIMSK2 |= (1 << OCIE2A);     // enable timer compare interrupt
}

ISR(TIMER2_COMPA_vect) {
  TIMSK2 &= ~(1 << OCIE2A);    // disable interrupt
  // do stuff
}

The awkward thing is, it doesn't work. The ISR timer is immediately called after we leave the ISR comparator (I checked this by toggling a pin in both routines and measuring with an oscilloscope). After a few hours of reading datasheets and randomly changing the code I came up with a line of code that fixed it:

 ISR(TIMER2_COMPA_vect) {
  TIMSK2 &= ~(1 << OCIE2A);    // disable interrupt
  OCR2A = 255;                 // <- apparently fixes all my problems
  // do stuff
}

I'm quite confused about this because the frequency of the timer shouldn't be a matter after we call the routine and deactivate the interrupt.

Now I'm quite glad that I've found the solution but I want to know why it works. Something about knowing how to fish and accidentally catching a fish by randomly inserting code.

Upvotes: 1

Views: 530

Answers (1)

fisehara
fisehara

Reputation: 176

I think you missed the clearing of pending timer interrupts.

ISR(TIMER2_COMPA_vect) {
   TIMSK2 &= ~(1 << OCIE2A);    // disable interrupt
   /* Clear pending interrupts */ 
   TIFR2 = (1 << TOV2) | (1 << OCF2A) | (1 << OCF2B);
   // do stuff
} 

Upvotes: 1

Related Questions