diff --git a/IRremote.cpp b/IRremote.cpp index 0c3974a..c292098 100644 --- a/IRremote.cpp +++ b/IRremote.cpp @@ -4,6 +4,8 @@ * Copyright 2009 Ken Shirriff * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html * + * Modified by Paul Stoffregen to support other boards and timers + * * Interrupt code based on NECIRrcv by Joe Knapp * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ @@ -169,7 +171,7 @@ void IRsend::sendRC6(unsigned long data, int nbits) void IRsend::mark(int time) { // Sends an IR mark for the specified number of microseconds. // The mark output is modulated at the PWM frequency. - TCCR2A |= _BV(COM2B1); // Enable pin 3 PWM output + TIMER_ENABLE_PWM; // Enable pin 3 PWM output delayMicroseconds(time); } @@ -177,7 +179,7 @@ void IRsend::mark(int time) { void IRsend::space(int time) { // Sends an IR space for the specified number of microseconds. // A space is no output, so the PWM output is disabled. - TCCR2A &= ~(_BV(COM2B1)); // Disable pin 3 PWM output + TIMER_DISABLE_PWM; // Disable pin 3 PWM output delayMicroseconds(time); } @@ -195,21 +197,17 @@ void IRsend::enableIROut(int khz) { // Disable the Timer2 Interrupt (which is used for receiving IR) - TIMSK2 &= ~_BV(TOIE2); //Timer2 Overflow Interrupt + TIMER_DISABLE_INTR; //Timer2 Overflow Interrupt - pinMode(3, OUTPUT); - digitalWrite(3, LOW); // When not sending PWM, we want it low + pinMode(TIMER_PWM_PIN, OUTPUT); + digitalWrite(TIMER_PWM_PIN, LOW); // When not sending PWM, we want it low // COM2A = 00: disconnect OC2A // COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted // WGM2 = 101: phase-correct PWM with OCRA as top // CS2 = 000: no prescaling - TCCR2A = _BV(WGM20); - TCCR2B = _BV(WGM22) | _BV(CS20); - // The top value for the timer. The modulation frequency will be SYSCLOCK / 2 / OCR2A. - OCR2A = SYSCLOCK / 2 / khz / 1000; - OCR2B = OCR2A / 3; // 33% duty cycle + TIMER_CONFIG_KHZ(khz); } IRrecv::IRrecv(int recvpin) @@ -220,20 +218,17 @@ IRrecv::IRrecv(int recvpin) // initialization void IRrecv::enableIRIn() { + cli(); // setup pulse clock timer interrupt - TCCR2A = 0; // normal mode - //Prescale /8 (16M/8 = 0.5 microseconds per tick) // Therefore, the timer interval can range from 0.5 to 128 microseconds // depending on the reset value (255 to 0) - cbi(TCCR2B,CS22); - sbi(TCCR2B,CS21); - cbi(TCCR2B,CS20); + TIMER_CONFIG_NORMAL(); //Timer2 Overflow Interrupt Enable - sbi(TIMSK2,TOIE2); + TIMER_ENABLE_INTR; - RESET_TIMER2; + TIMER_RESET; sei(); // enable interrupts @@ -241,7 +236,6 @@ void IRrecv::enableIRIn() { irparams.rcvstate = STATE_IDLE; irparams.rawlen = 0; - // set pin modes pinMode(irparams.recvpin, INPUT); } @@ -261,9 +255,9 @@ void IRrecv::blink13(int blinkflag) // First entry is the SPACE between transmissions. // As soon as a SPACE gets long, ready is set, state switches to IDLE, timing of SPACE continues. // As soon as first MARK arrives, gap width is recorded, ready is cleared, and new logging starts -ISR(TIMER2_OVF_vect) +ISR(TIMER_INTR_NAME) { - RESET_TIMER2; + TIMER_RESET; uint8_t irdata = (uint8_t)digitalRead(irparams.recvpin); @@ -320,10 +314,10 @@ ISR(TIMER2_OVF_vect) if (irparams.blinkflag) { if (irdata == MARK) { - PORTB |= B00100000; // turn pin 13 LED on + BLINKLED_ON(); // turn pin 13 LED on } else { - PORTB &= B11011111; // turn pin 13 LED off + BLINKLED_OFF(); // turn pin 13 LED off } } } diff --git a/IRremoteInt.h b/IRremoteInt.h index 74491b8..751a888 100644 --- a/IRremoteInt.h +++ b/IRremoteInt.h @@ -4,6 +4,8 @@ * Copyright 2009 Ken Shirriff * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html * + * Modified by Paul Stoffregen to support other boards and timers + * * Interrupt code based on NECIRrcv by Joe Knapp * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556 * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/ @@ -14,16 +16,58 @@ #include -#define CLKFUDGE 5 // fudge factor for clock interrupt overhead -#define CLK 256 // max value for clock (timer 2) -#define PRESCALE 8 // timer2 clock prescale +// define which timer to use +// +// Uncomment the timer you wish to use on your board. If you +// are using another library which uses timer2, you have options +// to switch IRremote to use a different timer. + +// Arduino Mega +#if defined(__AVR_ATmega1280__) + //#define IR_USE_TIMER1 // tx = pin 11 + #define IR_USE_TIMER2 // tx = pin 9 + //#define IR_USE_TIMER3 // tx = pin 5 + //#define IR_USE_TIMER4 // tx = pin 6 + //#define IR_USE_TIMER5 // tx = pin 46 + +// Teensy 1.0 +#elif defined(__AVR_AT90USB162__) + #define IR_USE_TIMER1 // tx = pin 17 + +// Teensy 2.0 +#elif defined(__AVR_ATmega32U4__) + //#define IR_USE_TIMER1 // tx = pin 14 + //#define IR_USE_TIMER3 // tx = pin 9 + #define IR_USE_TIMER4_HS // tx = pin 10 + +// Teensy++ 1.0 & 2.0 +#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) + //#define IR_USE_TIMER1 // tx = pin 25 + #define IR_USE_TIMER2 // tx = pin 1 + //#define IR_USE_TIMER3 // tx = pin 16 + +// Sanguino +#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) + //#define IR_USE_TIMER1 // tx = pin 13 + #define IR_USE_TIMER2 // tx = pin 14 + +// Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, etc +#else + //#define IR_USE_TIMER1 // tx = pin 9 + #define IR_USE_TIMER2 // tx = pin 3 +#endif + + + +#ifdef F_CPU +#define SYSCLOCK F_CPU // main Arduino clock +#else #define SYSCLOCK 16000000 // main Arduino clock -#define CLKSPERUSEC (SYSCLOCK/PRESCALE/1000000) // timer clocks per microsecond +#endif #define ERR 0 #define DECODED 1 -#define BLINKLED 13 // defines for setting and clearing register bits #ifndef cbi @@ -33,9 +77,6 @@ #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif -// clock timer reset value -#define INIT_TIMER_COUNT2 (CLK - USECPERTICK*CLKSPERUSEC + CLKFUDGE) -#define RESET_TIMER2 TCNT2 = INIT_TIMER_COUNT2 // pulse parameters in usec #define NEC_HDR_MARK 9000 @@ -125,5 +166,233 @@ extern volatile irparams_t irparams; #define MIN_RC5_SAMPLES 11 #define MIN_RC6_SAMPLES 1 + + + +// defines for timer2 (8 bits) +#if defined(IR_USE_TIMER2) +#define TIMER_RESET +#define TIMER_ENABLE_PWM (TCCR2A |= _BV(COM2B1)) +#define TIMER_DISABLE_PWM (TCCR2A &= ~(_BV(COM2B1))) +#define TIMER_ENABLE_INTR (TIMSK2 = _BV(OCIE2A)) +#define TIMER_DISABLE_INTR (TIMSK2 - 0) +#define TIMER_INTR_NAME TIMER2_COMPA_vect +#define TIMER_CONFIG_KHZ(val) ({ \ + const uint8_t pwmval = SYSCLOCK / 2000 / (val); \ + TCCR2A = _BV(WGM20); \ + TCCR2B = _BV(WGM22) | _BV(CS20); \ + OCR2A = pwmval; \ + OCR2B = pwmval / 3; \ +}) +#define TIMER_COUNT_TOP (SYSCLOCK * USECPERTICK / 1000000) +#if (TIMER_COUNT_TOP < 256) +#define TIMER_CONFIG_NORMAL() ({ \ + TCCR2A = _BV(WGM21); \ + TCCR2B = _BV(CS20); \ + OCR2A = TIMER_COUNT_TOP; \ + TCNT2 = 0; \ +}) +#else +#define TIMER_CONFIG_NORMAL() ({ \ + TCCR2A = _BV(WGM21); \ + TCCR2B = _BV(CS21); \ + OCR2A = TIMER_COUNT_TOP / 8; \ + TCNT2 = 0; \ +}) +#endif +#if defined(CORE_OC2B_PIN) +#define TIMER_PWM_PIN CORE_OC2B_PIN /* Teensy */ +#elif defined(__AVR_ATmega1280__) +#define TIMER_PWM_PIN 9 /* Arduino Mega */ +#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) +#define TIMER_PWM_PIN 14 /* Sanguino */ +#else +#define TIMER_PWM_PIN 3 /* Arduino Duemilanove, Diecimila, LilyPad, etc */ #endif + +// defines for timer1 (16 bits) +#elif defined(IR_USE_TIMER1) +#define TIMER_RESET +#define TIMER_ENABLE_PWM (TCCR1A |= _BV(COM1A1)) +#define TIMER_DISABLE_PWM (TCCR1A &= ~(_BV(COM1A1))) +#define TIMER_ENABLE_INTR (TIMSK1 = _BV(OCIE1A)) +#define TIMER_DISABLE_INTR (TIMSK1 = 0) +#define TIMER_INTR_NAME TIMER1_COMPA_vect +#define TIMER_CONFIG_KHZ(val) ({ \ + const uint16_t pwmval = SYSCLOCK / 2000 / (val); \ + TCCR1A = _BV(WGM11); \ + TCCR1B = _BV(WGM13) | _BV(CS10); \ + ICR1 = pwmval; \ + OCR1A = pwmval / 3; \ +}) +#define TIMER_CONFIG_NORMAL() ({ \ + TCCR1A = 0; \ + TCCR1B = _BV(WGM12) | _BV(CS10); \ + OCR1A = SYSCLOCK * USECPERTICK / 1000000; \ + TCNT1 = 0; \ +}) +#if defined(CORE_OC1A_PIN) +#define TIMER_PWM_PIN CORE_OC1A_PIN /* Teensy */ +#elif defined(__AVR_ATmega1280__) +#define TIMER_PWM_PIN 11 /* Arduino Mega */ +#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) +#define TIMER_PWM_PIN 13 /* Sanguino */ +#else +#define TIMER_PWM_PIN 9 /* Arduino Duemilanove, Diecimila, LilyPad, etc */ +#endif + + +// defines for timer3 (16 bits) +#elif defined(IR_USE_TIMER3) +#define TIMER_RESET +#define TIMER_ENABLE_PWM (TCCR3A |= _BV(COM3A1)) +#define TIMER_DISABLE_PWM (TCCR3A &= ~(_BV(COM3A1))) +#define TIMER_ENABLE_INTR (TIMSK3 = _BV(OCIE3A)) +#define TIMER_DISABLE_INTR (TIMSK3 = 0) +#define TIMER_INTR_NAME TIMER3_COMPA_vect +#define TIMER_CONFIG_KHZ(val) ({ \ + const uint16_t pwmval = SYSCLOCK / 2000 / (val); \ + TCCR3A = _BV(WGM31); \ + TCCR3B = _BV(WGM33) | _BV(CS30); \ + ICR3 = pwmval; \ + OCR3A = pwmval / 3; \ +}) +#define TIMER_CONFIG_NORMAL() ({ \ + TCCR3A = 0; \ + TCCR3B = _BV(WGM32) | _BV(CS30); \ + OCR3A = SYSCLOCK * USECPERTICK / 1000000; \ + TCNT3 = 0; \ +}) +#if defined(CORE_OC3A_PIN) +#define TIMER_PWM_PIN CORE_OC3A_PIN /* Teensy */ +#elif defined(__AVR_ATmega1280__) +#define TIMER_PWM_PIN 5 /* Arduino Mega */ +#else +#error "Please add OC3A pin number here\n" +#endif + + +// defines for timer4 (10 bits, high speed option) +#elif defined(IR_USE_TIMER4_HS) +#define TIMER_RESET +#define TIMER_ENABLE_PWM (TCCR4A |= _BV(COM4A1)) +#define TIMER_DISABLE_PWM (TCCR4A &= ~(_BV(COM4A1))) +#define TIMER_ENABLE_INTR (TIMSK4 = _BV(TOIE4)) +#define TIMER_DISABLE_INTR (TIMSK4 = 0) +#define TIMER_INTR_NAME TIMER4_OVF_vect +#define TIMER_CONFIG_KHZ(val) ({ \ + const uint16_t pwmval = SYSCLOCK / 2000 / (val); \ + TCCR4A = (1<> 8; \ + OCR4C = pwmval; \ + TC4H = (pwmval / 3) >> 8; \ + OCR4A = (pwmval / 3) & 255; \ +}) +#define TIMER_CONFIG_NORMAL() ({ \ + TCCR4A = 0; \ + TCCR4B = _BV(CS40); \ + TCCR4C = 0; \ + TCCR4D = 0; \ + TCCR4E = 0; \ + TC4H = (SYSCLOCK * USECPERTICK / 1000000) >> 8; \ + OCR4C = (SYSCLOCK * USECPERTICK / 1000000) & 255; \ + TC4H = 0; \ + TCNT4 = 0; \ +}) +#if defined(CORE_OC4A_PIN) +#define TIMER_PWM_PIN CORE_OC4A_PIN /* Teensy */ +#else +#error "Please add OC4A pin number here\n" +#endif + + +// defines for timer4 (16 bits) +#elif defined(IR_USE_TIMER4) +#define TIMER_RESET +#define TIMER_ENABLE_PWM (TCCR4A |= _BV(COM4A1)) +#define TIMER_DISABLE_PWM (TCCR4A &= ~(_BV(COM4A1))) +#define TIMER_ENABLE_INTR (TIMSK4 = _BV(OCIE4A)) +#define TIMER_DISABLE_INTR (TIMSK4 = 0) +#define TIMER_INTR_NAME TIMER4_COMPA_vect +#define TIMER_CONFIG_KHZ(val) ({ \ + const uint16_t pwmval = SYSCLOCK / 2000 / (val); \ + TCCR4A = _BV(WGM41); \ + TCCR4B = _BV(WGM43) | _BV(CS40); \ + ICR4 = pwmval; \ + OCR4A = pwmval / 3; \ +}) +#define TIMER_CONFIG_NORMAL() ({ \ + TCCR4A = 0; \ + TCCR4B = _BV(WGM42) | _BV(CS40); \ + OCR4A = SYSCLOCK * USECPERTICK / 1000000; \ + TCNT4 = 0; \ +}) +#if defined(CORE_OC4A_PIN) +#define TIMER_PWM_PIN CORE_OC4A_PIN +#elif defined(__AVR_ATmega1280__) +#define TIMER_PWM_PIN 6 /* Arduino Mega */ +#else +#error "Please add OC4A pin number here\n" +#endif + + +// defines for timer5 (16 bits) +#elif defined(IR_USE_TIMER5) +#define TIMER_RESET +#define TIMER_ENABLE_PWM (TCCR5A |= _BV(COM5A1)) +#define TIMER_DISABLE_PWM (TCCR5A &= ~(_BV(COM5A1))) +#define TIMER_ENABLE_INTR (TIMSK5 = _BV(OCIE5A)) +#define TIMER_DISABLE_INTR (TIMSK5 = 0) +#define TIMER_INTR_NAME TIMER5_COMPA_vect +#define TIMER_CONFIG_KHZ(val) ({ \ + const uint16_t pwmval = SYSCLOCK / 2000 / (val); \ + TCCR5A = _BV(WGM51); \ + TCCR5B = _BV(WGM53) | _BV(CS50); \ + ICR5 = pwmval; \ + OCR5A = pwmval / 3; \ +}) +#define TIMER_CONFIG_NORMAL() ({ \ + TCCR5A = 0; \ + TCCR5B = _BV(WGM52) | _BV(CS50); \ + OCR5A = SYSCLOCK * USECPERTICK / 1000000; \ + TCNT5 = 0; \ +}) +#if defined(CORE_OC5A_PIN) +#define TIMER_PWM_PIN CORE_OC5A_PIN +#elif defined(__AVR_ATmega1280__) +#define TIMER_PWM_PIN 46 /* Arduino Mega */ +#else +#error "Please add OC5A pin number here\n" +#endif + + +#else // unknown timer +#error "Internal code configuration error, no known IR_USE_TIMER# defined\n" +#endif + + +// defines for blinking the LED +#if defined(CORE_LED0_PIN) +#define BLINKLED CORE_LED0_PIN +#define BLINKLED_ON() (digitalWrite(CORE_LED0_PIN, HIGH)) +#define BLINKLED_OFF() (digitalWrite(CORE_LED0_PIN, LOW)) +#elif defined(__AVR_ATmega1280__) +#define BLINKLED 13 +#define BLINKLED_ON() (PORTB |= B10000000) +#define BLINKLED_OFF() (PORTB &= B01111111) +#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) +#define BLINKLED 0 +#define BLINKLED_ON() (PORTD |= B00000001) +#define BLINKLED_OFF() (PORTD &= B11111110) +#else +#define BLINKLED 13 +#define BLINKLED_ON() (PORTB |= B00100000) +#define BLINKLED_OFF() (PORTB &= B11011111) +#endif + +#endif