I am trying to use one of the hardware timers on the ATmega 328/p (arduino uno) to generate a short pulse some number of microseconds after receiving a pulse on an input.
Currently my code looks like this:
uint16_t pulse_delay = 12000; //half-microseconds
uint16_t pulse_length = 20;
void setup(){
pinMode(8, INPUT);
pinMode(9, OUTPUT);
TCCR1A = 0;
TCCR1B = _BV(ICNC1) //input capture noise cancel
| _BV(ICES1) //positive edge
| _BV(CS11); // /8 prescaler
TIMSK1 = _BV(ICIE1); //enable input capture interrupt
}
void loop(){}
ISR(TIMER1_CAPT_vect){
TCCR1A = _BV(COM1A0) | _BV(COM1A1); //set OC1A on match
TIMSK1 |= _BV(OCIE1A); //enable match interrupt
OCR1A = pulse_delay; //pulse begin time
TCNT1 = TCNT1 - ICR1; //TCNT1 now contains time since input pulse, even if
//the interrupt isn't run immediately
}
ISR(TIMER1_COMPA_vect){
TIMSK1 &=~ _BV(OCIE1A); //disable match interrupt
TCCR1A = _BV(COM1A1); //clear OC1A on match
OCR1A = pulse_delay + pulse_length;
}
This code should theoretically do the task, but it doesn't produce any output at all - to my oscilloscope it looks like the output pin just stays low.
However, if I replace the last line (OCR1A = pulse_delay + pulse_length;
) of the compare match interrupt with the following two lines, it outputs a pulse just fine. The issue with this is that it uses significantly more CPU time, and it can only count time from when the interrupt starts so if the interrupt is executed late the pulse will be longer.
delayMicroseconds(pulse_length);
TCCR1C = _BV(FOC1A); //manually trigger match event
All that the first version is doing differently is triggering the match event via an 'alarm' set on the timer, rather than waiting to trigger the match manually.
Why does the first version not work, and how can I make it work??