Uno, Timer 1 falls over

Hi all,

I've been debugging an issue for a couple of days, and narrowed it down to issues with timer1 interrupt. I've written the simplest code to illustrate the issue.

I want basically to change the duration of timer 1 with random intervals. In my application, this is using inputs from a button, but for illustration purposes, I just use random numbers. It captures the issue fine.

Here is the code:

void setup() {
  // Disable interupts
  noInterrupts();

  // Configure the seed for random numbers
  randomSeed(analogRead(0));

  //Configure serial
  Serial.begin(9600);

  // Configure timer1 
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialize counter value to 0
  // set compare match register for 1hz increments
  OCR1A = 3000; // loads a starting value
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS10 and CS12 bits for 1024 prescaler
  TCCR1B |= (1 << CS12) | (1 << CS10);
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);
  
  //Enable interupts
  interrupts();

  // Config done
  // DEBUG:
  Serial.print("\n-----------\ndone init\n");
}

void loop() {
  // The problem is loading new values into OCR1A register, so I lead some random numbers with a random interval
  delay(random(300,800));
  int rand_val = random(500, 5000);
  Serial.print("\n");
  Serial.print(rand_val);
  OCR1A = rand_val;
}



/*
 * ISR: Timer 1
 * 
 */
ISR(TIMER1_COMPA_vect)
{
  Serial.print("#\n");
}

Output from the terminal is:


1751#
#
#
#
#
#
#

4451#

1271
4487
3291
3021
2456
1878
902
2940#
#
#

4169#

3367#

As you can see the interrupt prints "#", and the main function prints what ever random number I write to the OCR1A register (countdown register of the timer)

Problem is that sometimes the timer falls over. Like this output there are several random numbers being written, while no interrupts happen. Then suddenly it springs into life again. I can find no commonality between the numbers written to the OCR1A reg and the timer falling over...

The code only requires an UNO board and a terminal. No extra HW needed...

Any ideas?
I checked the timer config several times, but see no issues there, but checking your own mistakes is not always fruitfull :slight_smile:

You are loading a new value of OCR1A unsynchronized with the actual count of the timer and when the new value set is less than the current count you will get this behavior.

For example if the value of OCR1A is 4000, and you change it to 1000 when TCNT is 3000, the timer will not stop at 4000 but will carry on to the 16 bit top value 0xFFFF.

See the data sheet for the AT328 for CTC mode of timer1 where this is explained.

If the new value written to OCR1A is lower than
the current value of TCNT1, the counter will miss the compare match. The counter will then count to its
maximum value (0xFF for a 8-bit counter, 0xFFFF for a 16-bit counter) and wrap around starting at 0x00
before the compare match will occur.
In many cases this feature is not desirable. An alternative will then be to use the Fast PWM mode using
OCR1A for defining TOP (WGM1[3:0]=0xF), since the OCR1A then will be double buffered.

Thanks a lot, that did the trick, I configure the timer as such:

  //Turn on Fast PWM mode
  TCCR1A |= (1 << WGM10) | (1 << WGM11);
  TCCR1B |= (1 << WGM12) | (1 << WGM13);

and voila, works totally as expected.

I guess reading and understanding the documentation is benneficial :smiley: thanks for helping out.