Timer2 OCR2A OCR2B Interrupts - Atmega328

Hi!
I’m trying to use the Timer2 on the Atmega328 (actually on Arduino Duemilanove) and I need the timer to generate 3 interrupts (on OCRA and OCRB compares and on overflow). Besides, OC2A and OC2B outputs should toggle on compare match.

The thing is that it really generates the interrupts, but only at timer maximum value, i.e. all the output compare waveforms toggle just when TCNT2 reaches TOP (every 16.4 ms) and so do the toggle of the pins defined on ISR. Inside ISR I’ll need to put some functions but the pin toggle is just fine for experimentation purposes.

I tried the CTC (clear time on compare match) before but without results because in that mode I believe just OCR2A is used (to define the timer range).

I’ve searched on many forum and sites but all I can find is COMPA interrupts not both COMPA and COMPB. Does the normal mode support the OCR2A and OCR2B as well as overflow interrupts?

And I don’t really know what FOC2A and FOC2B bits in TCCR2B register are used for. The datasheet says “The FOC2A bit is only active when the WGM bits specify a non-PWM mode”. But either with them set to 1 or clear to 0 the result I get is the same.

Thanks

void setup() {
  cli();  // disable global interrupts

  DDRB |= (1 << DDB3) | (1 << DDB0);  // PB3(OC2A) and PB0 as output
  PORTB |= (1 << DDB3) | (1 << DDB0);
  DDRD |= (1 << DDD7) | (1 << DDD6) | (1 << DDD3);  // PD7 PD7 and PD3 (OC2A) as output
  PORTD |= (1 << DDD7) | (1 << DDD6) | (1 << DDD3);
  
  TCCR2A = 0x00;   // clear timer registers
  TCCR2B = 0x00;
  TIMSK2 = 0x00;
  
  TIMSK2 |= (1 << OCIE2B) | (1 << OCIE2A) | (1 << TOIE2);  // OCRA OCRB OVF Interrupts enableded
  TCCR2A |=  (1 << COM2A0) | (1 << COM2B0);   // Normal mode & toogle on OC2A & OC2B

  OCR2A = 0x64;
  OCR2B = 0x80;
  
  TCCR2B |=  (1 << CS22) | (1 << CS21) | (1 << CS20);  //Set prescaller 1024 and start timer

  sei();  // enable interrupts
}

ISR(TIMER2_COMPA_vect) {
  PORTD ^= (1 << PORTD6);    // toggle PD6
}

ISR(TIMER2_COMPB_vect) {
  PORTB ^= (1 << PORTB0);    // toggle PB0
}

ISR(TIMER2_OVF_vect) {
  PORTD ^= (1 << PORTD7);    // toggle PD7
}

void loop() {
  // main code goes here
}

jaquelino: Does the normal mode support the OCR2A and OCR2B as well as overflow interrupts?

From the datasheet...

17.7.1 Normal Mode ...The Output Compare unit can be used to generate interrupts at some given time...

Yes, Normal Mode generates output compare interrupts.

What do you have connected to D6 and B0?

[quote author=Coding Badly link=topic=107339.msg806085#msg806085 date=1337969013]

What do you have connected to D6 and B0? [/quote]

For now just oscilloscope probes to see the pin output changes.

That's really got that little timer cookin' on all burners, but I don't see any reason it shouldn't work. Code looks ok, just from visual inspection.

There's a statement I don't understand in the datasheet, section 18.7.1:

The Output Compare unit can be used to generate interrupts at some given time. Using the Output Compare to generate waveforms in Normal mode is not recommended, since this will occupy too much of the CPU time.

Not sure why it would use CPU time.

Have you tried disabling the two output compare interrupts, just leaving the overflow interrupt, then looking at the waveforms on PB3 (OC2A), PD3 (OC2B) and PD7? Seems to me the compare ISRs just do the same thing that the timer output compare does, just on different pins. Not that that should be an issue, just sort of grasping at straws here.

It's working now!!! I don't really know what I did because the code seems pretty much the same I posted here. But it's perfect for me xD

[quote author=Jack Christensen link=topic=107339.msg806099#msg806099 date=1337969903] Seems to me the compare ISRs just do the same thing that the timer output compare does, just on different pins. [/quote]

Yes they do, but that was the easiest thing I tried to know if the interrupts were working. In the future I'll place some functions there.

[quote author=Jack Christensen link=topic=107339.msg806099#msg806099 date=1337969903] There's a statement I don't understand in the datasheet, section 18.7.1:

The Output Compare unit can be used to generate interrupts at some given time. Using the Output Compare to generate waveforms in Normal mode is not recommended, since this will occupy too much of the CPU time.

[/quote]

I also did read that and didn't understand why... Does anyone know why? I tried to do the same with fast PWM mode and manage to do the thing. Is it better to use this mode? Because there's nothing about too much CPU time written on datasheet for PWM mode.

jaquelino: It's working now!!!

Good deal! 8)

jaquelino: Using the Output Compare to generate waveforms in Normal mode is not recommended, since this will occupy too much of the CPU time ... I also did read that and didn't understand why... Does anyone know why?

My guess is they are referring to code that adjusts TCNT in the interrupt service routine to simulate a hardware PWM mode. Or, it was included to appease a fellow employee: "Maybe if we include that warning he'll quit yammering-on."

In any case, the guidance is always the same: keep your interrupt service routines short.

[quote author=Coding Badly link=topic=107339.msg806197#msg806197 date=1337976541] My guess is they are referring to code that adjusts TCNT in the interrupt service routine to simulate a hardware PWM mode. Or, it was included to appease a fellow employee: "Maybe if we include that warning he'll quit yammering-on." [/quote]

Gotta be one of the two. It sure seems like the way jaquelino has it set up could be interpreted as "generating waveforms in Normal mode" but there sure to heck ain't any CPU involved, else I'm seriously missing something! XD

jaquelino:
I also did read that and didn’t understand why… Does anyone know why?

I think I do …

From my page on timers here:

http://www.gammon.com.au/forum/?id=11504

I experimented with different modes. This is the one for “normal” mode:

#include <TimerHelpers.h>

// Timer 0

// input     T0     pin  6  (D4)
// output    OC0A   pin 12  (D6)
// output    OC0B   pin 11  (D5)

const byte timer0Input = 4;
const byte timer0OutputA = 6;
const byte timer0OutputB = 5;
  
void setup() {
   pinMode (timer0OutputA, OUTPUT); 
   pinMode (timer0OutputB, OUTPUT); 
   TIMSK0 = 0;  // no interrupts
   Timer0::setMode (0, Timer0::PRESCALE_1, Timer0::TOGGLE_A_ON_COMPARE | Timer0::TOGGLE_B_ON_COMPARE);
   OCR0A = 150;
   OCR0B = 200;
}  // end of setup

void loop() {}

Produces:

Now in this example the period is only 32 uS, and the “compare match” interrupts (if you had both set up) would have to fire every 32 uS. And since an interrupt takes close to 3 uS to set up and tear down, and you would have two of them, that is 6 uS out of the 32 uS used, plus whatever the interrupt itself actually does that is useful.

So say you spent 8 uS on the interrupts, then that is 25% of your CPU time dedicated to handling the compare matches. I suppose that is what they are getting at.