I'm trying to gain an understanding of the Arduino timer and interrupts, particularly the CTC-modes 4 and 12. I wrote a small example in which I generate interrupts while the mainloop sleeps for 1 second and the display how many interrupts occured. It can toggle between mode 4 and 12 with the #if 1.
This works fine for mode 12 ( 50 interrupts/sec ) but in mode 4 it gives -12k interrupts / seconds... unless when I set OCR1A to 39999 again inside the ISR then it does give the expected 50 interrupts/sec, but I'd like to know why.
I think my confusion might be related to not understanding the table-header explaining the modes where it says "Update of OCR1x at". What is meant with that ( who updates it, and to what value? or do I need to update it in the ISR ) ? Why would OCR1x be updated in mode 12 ( the table seems to state that it is) ? And it seems to work, even if I don't update it...?
Also, the only difference between mode 4 and 12 seems to be the register used for comparing to the timervalue (OCR1A vs ICR1)... but what is so fundamentally different between those? Why are there 2 options and what is the argument to choose for either mode 4 or 12 ?
Update: The issue seems to be related to initialization-order. If OCR1A is set to 39999 at the current location it gets reset to 0 a few lines further. When moving it after TCCR1A = TCCR1B = 0; then OCR1A keeps the value. So it's not necessary to set it on every interrupt. This also explains why we get -12k counts on mode 4 (because we are comparing OCR1A in that mode, comparing to 0 and generating loads of interrupts)...
Any insight into why the initialization-order matters in this case would be appreciated.
volatile int isr1 = 0;
ISR(TIMER1_COMPA_vect)
{
// this is called every time our timer-compare matches to ICR1 or OCR1A
isr1++;
// when using the #if part below, we need to do this, or we end up with weird values for isr1 ( around -12.000 )
// If we set it to the original value then we get 50 interrupts per second...
OCR1A= 39999;
}
void setup() {
Serial.begin(115200);
delay(50);
ICR1 = 39999; // 50Hz signal @ 16MHz clock
OCR1A= 39999;
//TIMSK1 |= 1 << ICIE; // bit 5: Input Capture Interrupt Enable (execute interrupt when TIFR1.ICF flag is set)
TIMSK1 |= 1 << OCIE1A; // bit 4 : Enable the Timer-Output-CompareA-Match Interrupt
TCCR1A = TCCR1B = 0; // reset timer-config flags
// An interrupt can be generated at each time the counter value reaches the TOP value by either using the OCF1A or ICF1 Flag,
// depending on the actual CTC mode. If the interrupt is enabled, the interrupt handler routine can be used for updating the TOP value.
#if 1
// Arduino Datasheet 20.12.2. : The counter value (TCNT1) increases until a compare match occurs with OCR1A, and then TCNT1 is cleared.
TCCR1B |= 1<<WGM12; // code 4 (CTC, compare with OCR1A, Immediate update of OCR1x, overflow on MAX)
#else
// Arduino Datasheet 20.12.2. : The counter value (TCNT1) increases until a compare match occurs with ICR1, and then TCNT1 is cleared.
TCCR1B |= 1<<WGM13 | 1<<WGM12; // code 12 (CTC, compare with ICR1, Immediate update of OCR1x(?), overflow on MAX)
#endif
// using a prescaler of 8, which "slows down" the clockticks by factor 8.
// 1 clocktick takes 0.5 microseconds, so 39999 clockticks need 19999,5 microseconds
// 1 second = 1.000.000 microseconds, so we get 50 interrupts per second
TCCR1B |= 1<<CS11; // timer CS11 = clki/o/8, 1 tick per 0.5 microseconds
}
void loop()
{
delay(1000); // wait 1 second
Serial.println(isr1); // print how many interrupts we had in that second
isr1 = 0; // and reset for the next second.
}