AVR timer overflow interrupt not working
Asked Answered
E

1

5

Hello good people of stack overflow. My problem is an interrupt service routine (ISR) that seemingly never executes! Here's some info on my set up: I am flashing an avr attiny85. I have the bare bones of a project set up so far with simply a main.c and two modules: timer and hardwareInit. In the timer module, I have a timer0_init function that I am using to set up timer0 for CTC mode to overflow ever 1 ms. Here is the function:

void timer0_init( void )
{
    cli();
    TCCR0B |= 3;    //clock select is divided by 64.
    TCCR0A |= 2;    //sets mode to CTC
    OCR0A = 0x7C;   //sets TOP to 124 so the timer will overflow every 1 ms.    
    TIMSK |= 2;     //Enable overflow interrupt
    sei();          //enable global interrupts
}

with the timer set up, I added an ISR to increment ticks every time the counter overflows, so I can keep track of how much time has elapsed, etc.

ISR(TIMER0_OVF_vect)
{
    cli();
    //ticks ++;
    PORTB |= ( 1 << PORTB0 );   
    sei();
}

as you can see, I commented out the ticks++ because it wasn't working, and replaced it with PORTB |= ( 1 << PORTB0 ); which simply turns on an LED, so if the interrupt is ever executed, I will know by proof of the LED being on.
Unfortunately, I can't get it to turn on and can't see what I'm missing. (to prove that I 1. have the LED set up on the right pin, and 2. am manipulating the correct bit in the correct register, I put just this statement PORTB |= ( 1 << PORTB0 ); in my infinite loop and confirmed the LED came on)

For further explanation, here is my main.c:

/*================================= main.c =================================*/

#define F_CPU   8000000UL

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

#include "timer.h"
#include "hardwareInit.h"


int main(){

    //Initialize hardware HERE  
    DDRB |= ( 1 << PORTB0 );    //set this pin as an output for an LED

    SetClockPrescale(1);    //internal clock divided by 1 = 8 MHz, from hardwareInit

    timer0_init();          //set up timer0 for 1 ms overflow


    while(1)
    {
        /* if( getTicks() > 0 )
        {
            PORTB |= ( 1 << PORTB0 );
            _delay_ms(1000);
            PORTB &= ~( 1 << PORTB0 );
            _delay_ms(1000);
        } */

    }
    return 0;
}

So, what you see in the infinite loop is what I tried first, but after that didn't work, I tried something simpler, just having an empty loop (commented out previous stuff), and waiting for the interrupt to get triggered which would turn on the LED.

Any help you could give would be really appreciated. I'm quite puzzled why this hasn't been working.

Emotionalize answered 20/11, 2016 at 3:51 Comment(2)
Try changing TIMSK |= 2; to TIMSK |= (1<<4); and TIMER0_OVF_vect to TIM0_COMPB_vect. No guarantees though.Haddad
Alternatively, leave the timer initialization the same and just try changing the vector to TIM0_OVF_vectHaddad
H
9

You are using the wrong ISR as @andars has pointed out correctly. In CTC "Clear Timer on Compare" mode the timer will never overflow as it will be cleared on compare match.

So you enabled the wrong interrupt of the timer as well. Bit 1 of TIMSK register enables timer overflow interrupt on timer0. That won't be triggered because of the previous reason. Taken from datasheet.

enter image description here

As you are using OCR0A to set the compare value, you have to enable Bit 4 – OCIE0A: Timer/Counter0 Output Compare Match A Interrupt Enable.

Back to the ISR, you need the ISR(TIMER1_COMPA_vect) or ISR(TIMER1_COMPB_vect) depending on which bit you set in TIMSK. Note that the compare value should be written into the matching registers as well, OCR0A or OCR0B.


Note that, you can use the bit names in your code just like the register names, in my opinion it makes the code more transparent.

Your code should be changed as follows to enable the corresponding interrupt:

void timer0_init( void )
{
    cli();          
    TCCR0B |= (1<<CS01) | (1<<CS00);   //clock select is divided by 64.
    TCCR0A |= (1<<WGM01);              //sets mode to CTC
    OCR0A = 0x7C;                      //sets TOP to 124 so the timer will overflow every 1 ms.    
    TIMSK |= (1<<OCIE0A);              //Output Compare Match A Interrupt Enable
    sei();                             //enable global interrupts
}

The ISR:

ISR(TIMER0_COMPA_vect)
{
    cli();
    //ticks ++;
    PORTB |= ( 1 << PORTB0 );   
    sei();
}
Howlond answered 20/11, 2016 at 19:43 Comment(5)
Great! I was missing the point of CTC mode. When I set OCR0A to 124, I thought that since the TOP was changed to 124, the timer would overflow. It's now clear to me that overflow is only when the timer reaches the "true" top, in this case 255. Regarding the other things you said were wrong, let me clear that up. You said "You also enabled the wrong interrupt of the wrong timer," but I really didn't. I ORed the TIMSK register with the value 2, which in binary is 00000010, effectively setting the TOIE0 bit to 1. The following lines are equivalent: TIMSK |= 2; TIMSK |= (1<<TOIE0);Emotionalize
Same goes for the second half of your answer where you list several corrections. "Bit 3 of the register has nothing to do with clock division." I wasn't setting bit 3, I was ORing the whole register with the value 3, or 00000011 to set its first 2 bits (CS00 and CS01) to get the clock division of 64. Same for correction 2. I know this is my faulty for being lazy and mixing my notation between ORing with a value, and ORing with a bit shifted to the bit name. Sorry for the confusion. Does that make sense?Emotionalize
If you revise your answer to correct that, I will upvote and accept your answer. Thanks for your help!Emotionalize
@Emotionalize Yes, yes you are right. I do not know why I thought that you were bitshifting those values. Probably because I always use bitshift, I will correct itHowlond
Yes, I changed my code now to use the bit shifting method everywhere and it is more readable. I also changed to the output compare interrupt instead of overflow and it's working perfectly! So thank you! Thanks for the revisions to your answer as well.Emotionalize

© 2022 - 2024 — McMap. All rights reserved.