After way more time than I want to admit, I'm ready to admit defeat on an apparent timer bug in the ATmega32u4 (Leonardo). I'm trying to setup two timers (1 & 3) to work together, and for some reason timer3 seems to call the compare ISR almost immediately in some cases.
The program is expected to produce a 1kHz pulse of minimum duration on pin 9, and a 500e-6s duration pulse on pin 4 for every 100 pulses of pin 9. The result is as expected, except that the pulse on pin 4 only has 10e-6s duration MOST of the time, and occasionally 15 to 20e-6s duration. Maybe there's some other interrupt interfering?
This is an excerpted function from a larger program which was exhibiting this weird behavior, so I cut it down to the simplest demo of the problem and haven't been able to sort it out still. It needs to use the timers because timing is critical and doing this in software with the other requirements does not seem possible.
Code to reproduce the problem is:
const int tmr1Pin = 9;
const int tmr3Pin = 4;
volatile int tcntx = 0;
// the setup routine runs once when you press reset:
void setup() {
pinMode(tmr1Pin, OUTPUT); digitalWrite(tmr1Pin,LOW);
pinMode(tmr3Pin, OUTPUT); digitalWrite(tmr3Pin,LOW);
cli(); // disable global interrupts
GTCCR = 0; // clear Timer Sync Mode to restart all timers and prescalers
GTCCR = (1 << TSM); // set Timer Sync Mode to pause all timers
TCCR1A = 0;
TCCR1B = (1 << CS10); // prescaler=1 -> use system clock speed
TCCR1B|= (1 << WGM12); // turn on CTC mode, TOP=OCR1A (ie resets at OCR1A)
OCR1A = 16000; // set compare match register to desired timer count (16000/16MHz=1ms)
TIMSK1 = (1 << OCIE1A); // enable timer compare interrupt
TCCR3A = 0; // leave OC3A to software control
TCCR3B = (1 << CS30); // prescaler=1 -> use system clock speed
TCCR3B|= (1 << WGM32); // turn on CTC mode, TOP=OCR3A
OCR3A = 8000;
// turn off other interrupts
// TIMSK0 = 0; // timer 0
// USBCON = 0; // USB interrupts (now you need to press the reset button to program...)
// at least one more is still on but I can't find it...
GTCCR = 0; // clear Timer Sync Mode to restart all timers and prescalers
sei(); // enable global interrupts
}
ISR(TIMER1_COMPA_vect) { // called after gate time has expired
digitalWrite(tmr1Pin,HIGH); digitalWrite(tmr1Pin,LOW);
if (tcntx > 100) {
tcntx=0;
TCNT3=0;
digitalWrite(tmr3Pin,HIGH);
TIMSK3 = (1 << OCIE3A); // enable timer compare interrupt
} else {
tcntx++;
}
}
ISR(TIMER3_COMPA_vect) { // called after gate time has expired
digitalWrite(tmr3Pin,LOW);
TIMSK3 = 0;
}
// the loop routine runs over and over again forever:
void loop() {
} // end loop()
Strangely enough, if the three lines for setting up timer3 in the timer1 ISR are moved outside of the conditional statement so that they are called every pulse, timer3 behaves as expected for the first couple of pulses but then reverts to the above problematic operation.
const int tmr1Pin = 9;
const int tmr3Pin = 4;
volatile int tcntx = 0;
// the setup routine runs once when you press reset:
void setup() {
pinMode(tmr1Pin, OUTPUT); digitalWrite(tmr1Pin,LOW);
pinMode(tmr3Pin, OUTPUT); digitalWrite(tmr3Pin,LOW);
cli(); // disable global interrupts
GTCCR = 0; // clear Timer Sync Mode to restart all timers and prescalers
GTCCR = (1 << TSM); // set Timer Sync Mode to pause all timers
TCCR1A = 0;
TCCR1B = (1 << CS10); // prescaler=1 -> use system clock speed
TCCR1B|= (1 << WGM12); // turn on CTC mode, TOP=OCR1A (ie resets at OCR1A)
OCR1A = 16000; // set compare match register to desired timer count (16000/16MHz=1ms)
TIMSK1 = (1 << OCIE1A); // enable timer compare interrupt
TCCR3A = 0; // leave OC3A to software control
TCCR3B = (1 << CS30); // prescaler=1 -> use system clock speed
TCCR3B|= (1 << WGM32); // turn on CTC mode, TOP=OCR3A
OCR3A = 8000;
// turn off other interrupts
// TIMSK0 = 0; // timer 0
// USBCON = 0; // USB interrupts (now you need to press the reset button to program...)
// at least one more is still on but I can't find it...
GTCCR = 0; // clear Timer Sync Mode to restart all timers and prescalers
sei(); // enable global interrupts
}
ISR(TIMER1_COMPA_vect) { // called after gate time has expired
digitalWrite(tmr1Pin,HIGH); digitalWrite(tmr1Pin,LOW);
if (tcntx > 100) {
tcntx=0;
} else {
tcntx++;
}
TCNT3=0;
digitalWrite(tmr3Pin,HIGH);
TIMSK3 = (1 << OCIE3A); // enable timer compare interrupt
}
ISR(TIMER3_COMPA_vect) { // called after gate time has expired
digitalWrite(tmr3Pin,LOW);
TIMSK3 = 0;
}
// the loop routine runs over and over again forever:
void loop() {
} // end loop()
Any ideas?