I'm trying to use timer 1 for both input capture and output compare simultaneously but can't get it to work. In a test program input capture only works, output compare only works but not both at the same time.
Using an UNO, pin 8 has a square wave input at 1khz to 2.5khz (from a different board not the same one I'm asking about here).
The test program uses the input capture of the UNO to measure the average time between edges.
Next, the test program is using output compare to generate a different square wave. I'm able to use the internal ability to automatically toggle D9 on compare and can also manually toggle D10 from the ISR.
However, I can't get both Input Capture (IC) and Output Compare (OC) at the same time.
I'm using an oscilloscope and can see when the outputs on D9 and D10 are running, and see the serial output using the serial monitor.
In the test program, at the bottom of setup() there are 3 lines. (A) The first enables OC interrupt only. (B) Second enables IC interrupt only. (C) Third enables both.
If (A) OC only, D9 and D10 toggle, no serial output -- (expected)
If (B) IC only, serial output is there and no D9 or D10 -- (expected)
If (C) both IC and OC, no D9 or D10 toggle, (but do see serial output) -- (NOT expected)
I've checked the datasheet but don't see why both shouldn't work, and don't see what is wrong.
Any ideas are greatly appreciated.
Thanks -
#include "Arduino.h"
#include <avr/interrupt.h>
#define SERIAL_BAUD 9600
// Digital pin 9 for OCR automatic output
// Digital pin 10 for OCR manual output
// Digital pin 8 for square wave input from other UNO at around 1khz to 2khz
const int OCPin = 9;
const int ICPin = 8;
#define OUT_PIN 10
const int Prescale = 8; // prescaler factor, 0.5 uS @16Mhz
const byte PrescaleBits = B010;
bool enabled = false;
const int numResults = 64;
volatile byte index = 0;
volatile unsigned int results[numResults];
volatile unsigned char tog=0;
// Output Compare ISR
ISR(TIMER1_COMPA_vect)
{
OCR1A += 1000; // set next interrupt compare time
// manually toggle D10 in addition to D9
if(tog & 1)
bitClear(PORTB, 2);
else
bitSet(PORTB, 2);
tog++;
}
// Input capture ISR
ISR(TIMER1_CAPT_vect)
{
TCNT1 = 0; // reset counter
if(enabled && (index < numResults))
{
results[index] = ICR1;
index++;
}
// stop collection until loop() prints result
if(index == numResults)
enabled = false;
// look for other edge
TCCR1B ^= _BV(ICES1);
}
//
// Setup timers Arduino UNO
// BIT 7 6 5 4 3 2 1 0
// TCCR1A has COM1A1 COM1A0 COM1B1 COM1B0 – – WGM11 WGM10
// TCCR1B has ICNC1 ICES1 – WGM13 WGM12 CS12 CS11 CS10
// TIMSK1 has – – ICIE1 – – OCIE1B OCIE1A TOIE1
void setup(void)
{
// Set up the I/O direction
pinMode(ICPin, INPUT_PULLUP);
pinMode(OCPin, OUTPUT);
pinMode(OUT_PIN, OUTPUT); // Make Port D10 output
Serial.begin(SERIAL_BAUD);
// Input Capture, Output Compare setup
TCCR1A = 0x01 << 6; // COM1A1, COM1A0 = 01 => D9 toggle compare match
TCCR1B = PrescaleBits; // divide by 8 from prescaler
//
// Note: A and B work as expected, C does not:
//
//TIMSK1 = TIMSK1 | 0x02; // (A) enable OCIE1A only
//TIMSK1 = TIMSK1 | 0x20; // (B) enable ICIE1 only
TIMSK1 = TIMSK1 | 0x22; // (C) enable both OCIE1A and ICIE1
index = 0;
enabled = true; // enable time collection
}
///////////////////////////////////////////////////////////////////////////////
void loop(void)
{
unsigned avg = 0;
unsigned min = 65535;
unsigned max = 0;
unsigned long sum=0;
int i;
// wait for IC ISR to collect some edges
while (index < numResults)
{
delay(5);
}
// print the results of square wave timing
for(i=0; i<numResults; i++)
{
if(results[i] > max) max = results[i];
if(results[i] < min) min = results[i];
sum = sum + results[i];
}
avg = sum / numResults;
Serial.print(avg); Serial.print(" ");
Serial.print(min); Serial.print(" ");
Serial.print(max);
Serial.println("");
// re-enable Input Capture ISR to start recording time again
index = 0;
enabled = true;
}