Electronic – Overflow interrupt firing only once

avravr-gccinterrupts

I've run into an issue where, it appears, my interrupt only fires once, then simply refuses to fire again on my ATMega32U2. I have the following (stripped down) code:

void init(void) {
    DDRB = 0xff;
    PORTB = 0x00;

    TCCR0A = (1 << WGM01);
    // 1024 prescaler
    TCCR0B = ((1 << CS02) | (1 << CS00));
    // Interrupt every 4096 clocks
    OCR0A = 3;
    // Enable timer compare match interrupt
    TIMSK0 != (1 << OCIE0A);
}

ISR(TIMER0_COMPA_vect) {
    PORTB++;
}

int main(void) {
    init();

    sei();

    while(1);

    return 0;
}

When I plug an LED into each pin of PORTB, the first pin is high, while the rest are low. The most I can deduce from this is PORTB is incremented to 0x01 by the interrupt firing once, then left alone as the interrupt never fires again using the TIMER0_COMPA_vect vector.

However, if I replace the compare interrupt with an overflow interrupt (TIMER0_OVF_vect) and configure the registers differently, it works fine; PORTB cycles through 0 – 255 very quickly as I'd expect. This is my working code with the type of interrupt I don't want:

// Different timer config
void init(void) {
    DDRB = 0xff;
    PORTB = 0x00;

    TCCR0B |= (1 << CS01);

    // Enable timer 0 interrupt
    TIMSK0 |= (1 << TOIE0); 
}

// This time, it's an OVERFLOW vector, not a compare vector
ISR(TIMER0_OVF_vect) {
    PORTB++;
}

int main(void) {
    init();

    sei();

    while(1);

    return 0;
}

I've read what there is to read on Google, however the only fixes posted are logical errors that I don't think I have. I've read this forum post and had a look at the timer configuration registers, and they're exactly the same as my first example. I've also read this question, but that didn't help.

I've been following the tutorial on this page (PDF) for the TLC5940 LED driver chip and am on Chapter 4 (refactoring code to use interrupts). Please note that I don't want to use the ready built library; I'm using this as a learning experience.

Best Answer

This may just be a typo in your post, but the line where you enable the Timer Compare interrupt says:

TIMSK0 != (1 << OCIE0A);

... when it should say ...

TIMSK0 |= (1 << OCIE0A);

It's subtle, but if that's what your code actually was, then you were comparing TIMSK0 to a constant rather than assigning to it (and therefore never actually enabling the interrupt).

On a sidenote, you can more concisely write:

TIMSK0 |= _BV(OCIE0A);

... instead of ..

TIMSK0 |= (1 << OCIE0A);

in avr-libc, if you're into that sort of thing :-).