timer 2 and millis()

Hi All,

I’m confused about the relationship between timer 2 and millis() in Arduino-0021. I am trying to use timer 2 for an overflow interrupt but as soon as I enable the timer, the millis() function stops working. I thought that millis() just used timer0… at least this is what it looks like from reading wiring.c
I am using an Atmega 328p.
The code is below. Any advice is greatly appreciated.

/* First disable the timer overflow interrupt while we're configuring */
      TIMSK2 &= ~(1<<TOIE2);

      /* Configure timer2 in normal mode (pure counting, no PWM etc.) */
      TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
      TCCR2B &= ~(1<<WGM22);

      /* Select clock source: internal I/O clock */
      ASSR &= ~(1<<AS2);
      
      /* Disable Compare Match A interrupt enable (only want overflow) */
      TIMSK2 &= ~(1<<OCIE2A);

      /* Now configure the prescaler to none */
      TCCR2B |=  (1<<CS20); // Set bit
      TCCR2B &= ~(1<<CS21); // Clear bit
      TCCR2B &= ~(1<<CS22); // Clear bit

      /* Finally load end enable the timer */
      TIMSK2 |= (1<<TOIE2);

ISR(TIMER2_OVF_vect) {
      /* Reload the timer */
      TCNT2 = 255;
      digitalWrite(8, toggle == 0 ? HIGH : LOW); //test output
      toggle = ~toggle; //test output
      timer_clicks = (timer_clicks + 1) & 0x1F; //circular to 32
      post_frames();
}


void post_frames(void)
{
      for(char row = 0 ; row < 8; row++)shift_out_line(row);      //Send all 8 rows of colors to the Matrix
}

void shift_out_line(volatile uint8_t row_num)
{
      cbi(PORTC, LATCH);      //Disable the shift registers

      //Send Red Values
      for(uint8_t LED = row_num*8 ; LED < (row_num*8)+8 ; LED++) //Step through bits
      {
            cbi(PORTC, CLK);      //Lower the shift register clock so we can configure the data

            //Compare the current color value to timer_clicks to Pulse Width Modulate the LED to create the designated brightness
            if(timer_clicks < red_frame[LED])
                  sbi(PORTC, DATA);
            else
                  cbi(PORTC, DATA);

            sbi(PORTC, CLK);      //Raise the shift register clock to lock in the data
      }
      //Send Blue Values
      for(uint8_t LED = row_num*8 ; LED < (row_num*8)+8 ; LED++) //Step through bits
      {
            cbi(PORTC, CLK);      //Lower the shift register clock so we can configure the data

            //Compare the current color value to timer_clicks to Pulse Width Modulate the LED to create the designated brightness
            if(timer_clicks < blue_frame[LED])
                  sbi(PORTC, DATA);
            else
                  cbi(PORTC, DATA);

            sbi(PORTC, CLK);      //Raise the shift register clock to lock in the data
      }
      //Send Green Values
      for(uint8_t i = row_num*8 ; i < (row_num*8)+8 ; i++) //Step through bits
      {
            cbi(PORTC, CLK);      //Lower the shift register clock so we can configure the data

            //Compare the current color value to timer_clicks to Pulse Width Modulate the LED to create the designated brightness
            if(timer_clicks < green_frame[i])
                  sbi(PORTC, DATA);
            else
                  cbi(PORTC, DATA);

            sbi(PORTC, CLK);      //Raise the shift register clock to lock in the data
      }

      sbi(PORTC, EN);            //Disable the Shift Register Outputs
      sbi(PORTC, LATCH);      //Put the new data onto the outputs of the shift register

      PORTD = (1<<row_num); //Sink current through row (Turns colors 'ON' for the given row. Keep in mind that we can only display to 1 row at a time.)

      cbi(PORTC, EN);            //Enable the Shift Register Outputs
}

The last line of this breaks millis(). What is going on?

Thanks!

Are you declaring an interrupt service routine (ISR) for your Timer 2 overflow? If not, when the overflow occurs then random code executes and you will see strange behavior.


The Gadget Shield: accelerometer, RGB LED, IR transmit/receive, light sensor, potentiometers, pushbuttons

I think the compiler provides a default ISR that "reboots" the controller.

Yes, I have an ISR that I didn't include. At the moment it does nothing because I'm stuck trying to figure out the millis() issue.

There is no reason I can see why messing with Timer 2 should affect millis(). It would be helpful if we could see all the code related to Timer 2, including your ISR.

-- The Quick Shield: breakout all 28 pins to quick-connect terminals

OK. I've posted the ISR and related code above. The problem seems to be with the post_frames() function in ISR. Maybe it takes too long for the speed of the ISR? This is a hacked version of an RGB matrix display. I'm not sure how to calculate how much time the ISR needs to execute but I suspect this is the problem. If I comment out post_frames() from ISR then delay() and millis() are OK.

Thanks!

Yes, there is a lot going on in the ISR but my main concern is why you set Timer 2 to 255 in the ISR? This timer counts up, not down, so you will get an overflow just about immediately as it goes from 255-->0. This means your code will spend its entire life in this ISR. I would just take out that line altogether and let the timer count up normally from 0 to 255.

-- The Quick Shield: breakout all 28 pins to quick-connect terminals

Thanks, that makes sense. I took out that line but delay() still doesn't work correctly. A delay(100) in my main code takes about 4 seconds. What happens if my ISR takes longer to execute than the time between overflows?

If your ISR takes longer to execute than the time between ISR's then your code will be always "stuck" in the ISR. If it takes 99.9% of the inter-ISR time then you will observe what you see: code that should take a very small amount of time to execute actually takes a very long time. There's nothing wrong with millis(), it's just that the code that inspects millis() and implements a delay doesn't run often enough to be accurate.

-- The Gadget Shield: accelerometer, RGB LED, IR transmit/receive, light sensor, potentiometers, pushbuttons