Electronic – Use AVR Timer1 for Compare Interrupt AND PWM at same time

atmegaavrinterruptspwm

Is it possible to use Timer1 on an ATMega to generate a compare interrupt on OCR1A and PWM output on OCR1B? I've tried with similar to the following, but neither work with everything I've tried.

TCCR1A = _BV(COM1B1) | _BV(WGM11) | _BV(WGM10);
TCCR1B = PRESCALE1_8;
OCR1B = 0;


// set compare match register for 1000Hz 
OCR1A = 2000;
// turn on CTC mode
TCCR1B |= _BV(WGM12);

Side note: I know this is extremely similar to another question of my own, but that was regarding PWM on one timer and interrupts on another. This time I'm having trouble getting both out of the SAME timer.

Best Answer

Your code sets the counter for phase correct PWM operation with top value 0x3FF so the first problem you'll face is that the compare match interrupts will not be triggered in equal intervals because of the way that this mode works which is count to the top and then change direction and count backwards.

The other problem is that the counter counts up to 1023 (0x3ff) and back to 0 so there is no way to ever get a match interrupt for a value of 2000 (OCR1A = 2000)

phase correct PWM operation:

enter image description here


This is a minimum code for mega328 running @16MHz that sets Timer 1 to generate a fast PWM with a frequency of about 1KHz (frequency set by ICR1 and duty set by OCR1B) and also gives a timer 1 overflow interrupt with a 1KHz rate

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

// Timer1 overflow interrupt service routine
ISR(TIMER1_OVF_vect)
{
    PORTB ^= 1; // invert PORTB.0
}

int main(void)
{

    // Port B initialization
    // Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=Out Bit1=In Bit0=Out
    DDRB = 0x05;

    // Timer/Counter 1 initialization
    // Clock source: System Clock
    // Clock value: 2000,000 kHz
    // Mode: Fast PWM top=ICR1
    // OC1A output: Disconnected
    // OC1B output: Non-Inverted PWM
    // Noise Canceler: Off
    // Input Capture on Falling Edge
    // Timer Period: 1,0245 ms
    // Output Pulse(s):
    // OC1B Period: 1,0245 ms Width: 0,12806 ms
    // Timer1 Overflow Interrupt: On
    // Input Capture Interrupt: Off
    // Compare A Match Interrupt: Off
    // Compare B Match Interrupt: Off
    TCCR1A = (0 << COM1A1) | (0 << COM1A0) | (1 << COM1B1) | (0 << COM1B0) | (1 << WGM11) | (0 << WGM10);
    TCCR1B = (0 << ICNC1) | (0 << ICES1) | (1 << WGM13) | (1 << WGM12) | (0 << CS12) | (1 << CS11) | (0 << CS10);
    TCNT1 = 0;
    ICR1 = 2048;
    OCR1A = 0;
    OCR1B = 256;

    // Timer/Counter 1 Interrupt(s) initialization
    TIMSK1 = (0 << ICIE1) | (0 << OCIE1B) | (0 << OCIE1A) | (1 << TOIE1);

    // Global enable interrupts
    sei();

    while(1)
    {
        // Place your code here

    }
}