Timer 3 overflows not working

I've been trying to use this code to generate an interrupt every 1 milliseconds:

ISR(TIMER3_OVF_vect)
{
    Serial.println("0");
    TCNT3 = 65504;
    TIFR3 |= bit(TOV3);
}
void setup()
{
    
    cli();
    Serial.begin(9600);
    TCCR3A = 0;
    TCCR3B = 4;
    TCNT3 = 65504;
    TIMSK3 |= bit(TOIE3);
    sei();
}
void loop()
{
}

but the interrupts seem to be generated at random and they seem to trigger one after the other. Any idea on why this is happening?

Which Arduino, and what is your theory about the settings chosen for TCCR3A and B?

This is an arduino mega2560
TCCR3A is set to 0 to run the timer in normal mode (page 158 of the datasheet)
TCCR3B is set to 4 to use a prescaler of 256 (page 162 of the datasheet)

the datasheet I'm referencing is the ATmega640/1280/1281/2560/2561 datasheet

How should all those settings result in an interrupt every millisecond?

By the way, NEVER print in an interrupt service routine. Take out that serial.print and try again.

initializing TNCT3 to 65504 will cause the timer to overflow exactly every 1 milliseconds.
Calculated using the formula:
INIT_VAL = TOP - (F_CPU * T ) / 2*PRESCALER
with T being the desired period in seconds

Not what I get. But that Serial.print will sure create havoc.

I did try without the print, even used an oscilloscope to check the period. For my purposes I want the ISR to update a PID controller, in order to achieve a constant time period and for the PID equations to make sense I have to use interrupts.
Otherwise, I dont see how Serial print will cause issue especially with an empty main loop

No, you don't. Millis() works great for timing PID loops. Most people choose the PID loop time to be about 1/10 of the system response time. Rarely is anything gained by faster loop timing.

I dont see how Serial print will cause issue especially with an empty main loop

The Serial.println() IN THE ISR is a serious mistake and will crash anything other than an AVR Arduino. Take it out and try again.

62500 timer ticks per second = 62.5 ticks per millisecond.

The code still doesnt work, I ran a test on an arduino uno (which is all I have in hand at the moment) and it's showing wrong results. Here's the test code:

uint8_t FLAG = 0;
ISR(TIMER2_OVF_vect)
{
    FLAG = !FLAG;
    TCNT2 = 34286;
    TIFR2 |= bit(TOV2);
}
void setup() {
  // put your setup code here, to run once:
  TCCR2A = 0;
  TCCR2B = 4;
  //1 second period
  TCNT2 = 34286;
  TIMSK2 = bit(TOIE2);
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println(FLAG);
}

here's the output

01:51:19.411 -> 1
01:51:19.411 -> 1
01:51:19.411 -> 0
01:51:19.443 -> 0
01:51:19.443 -> 0
01:51:19.443 -> 1
01:51:19.443 -> 1
01:51:19.443 -> 1
01:51:19.443 -> 0
01:51:19.443 -> 0
01:51:19.443 -> 0
01:51:19.443 -> 1
01:51:19.443 -> 1
01:51:19.443 -> 1

On the Uno, Timer2 is an 8 bit timer.

okay I modified TCNT2 to initialize at 225 which should result in a 1 ms period but it didn't seem to result in the intended period. Here's the serial output

02:09:29.096 -> 1
02:09:29.096 -> 1
02:09:29.096 -> 0
02:09:29.096 -> 1
02:09:29.096 -> 1
02:09:29.096 -> 0
02:09:29.096 -> 0
02:09:29.096 -> 1
02:09:29.096 -> 0
02:09:29.128 -> 0
02:09:29.128 -> 1

Variables shared with interrupt routines (like FLAG) must be declared volatile, or changes in those variable may be ignored.

Timer2 on an Uno is an 8 bit timer, so this probably won't do what you expect.

  TCNT2 = 34286;

Do you realize that it takes 3 milliseconds to print three characters (a digit, CR and LF) at 9600 Baud?

  Serial.println(FLAG);

Similar to your attempt, for Timer1.

volatile unsigned long ms_count = 0;
ISR(TIMER1_OVF_vect)
{
  TCNT1 = 65536 - 250;
  ms_count++;  //millisecond timer
}
void setup()
{
  Serial.begin(115200);
  cli();
  TCCR1A = 0;
  TCCR1B = (1 << CS11) | (1 << CS10); //prescaler 64
  TCNT1 = 65536 - 250;
  TIMSK1 |= (1 << TOIE1);
  sei();
}
unsigned long print_time = 0;
void loop()
{
  if (millis() - print_time > 10000UL) { //compare millis() and ms_count every 10 s
    print_time = millis();
    noInterrupts();
    unsigned long ms_copy = ms_count;  //make a copy with interrupts off
    interrupts();
    Serial.print(print_time);  //print time and compare ms_count
    Serial.write(' ');
    Serial.println(ms_copy);
  }
}
1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.