You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
377 lines
15 KiB
377 lines
15 KiB
/* IRLibHardware.h
|
|
* Part of IRLib Library for Arduino receiving, decoding, and sending
|
|
* infrared signals. See COPYRIGHT.txt and LICENSE.txt for more information.
|
|
*
|
|
* This file was formally called IRLibTimer.h but we have renamed it because it more
|
|
* accurately reflects the fact that it contains all of the hardware specific defines.
|
|
* It contains mostly definitions for 8-bit AVR processors. More advanced processors such as
|
|
* SAMD21 definitions will now be defined in a separate processor specific header file.
|
|
* NOTE: IRLibHardware.cpp is not related to hardware. See the comments in that file
|
|
* to explain why it was created and what purpose it serves.
|
|
*/
|
|
|
|
/* This file has been significantly reconfigured for version 1.5 and greater. It now
|
|
* allows you use a different timer for input versus output. This also allows you to
|
|
* use no timers whatsoever by using the IRrecvPCI or IRrecvLoop for input and
|
|
* bit-bang routines for output. Note the various "Teensy" sections have not been tested.
|
|
*/
|
|
#ifndef IRLibHardware_h
|
|
#define IRLibHardware_h
|
|
|
|
#include "Arduino.h"
|
|
|
|
//This is a default for AVRs. SAMD21 will override it.
|
|
#define IR_CLEAR_INTERRUPT {} //clear interrupt flag
|
|
|
|
// defines for setting and clearing register bits
|
|
#ifndef cbi
|
|
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
|
|
#endif
|
|
#ifndef sbi
|
|
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
|
|
#endif
|
|
|
|
/* In this section we attempt to detect your hardware type and give you the choice of
|
|
* various hardware timers to change the PWM frequency for output. In each hardware
|
|
* section below you should un-comment only one of the choices. The defines also
|
|
* specify the output pin number. DO NOT change the pin number unless you're using
|
|
* non-standard hardware that would require you to do so. If you wish to use the
|
|
* bit-bang PWM output, you will specify that AFTER this section as an override.
|
|
*/
|
|
|
|
/* Arduino Mega */
|
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
|
//#define IR_SEND_TIMER1 11
|
|
#define IR_SEND_TIMER2 9
|
|
//#define IR_SEND_TIMER3 5
|
|
//#define IR_SEND_TIMER4 6
|
|
//#define IR_SEND_TIMER5 46
|
|
|
|
/* Teensy 1.0 */
|
|
#elif defined(__AVR_AT90USB162__)
|
|
#define IR_SEND_TIMER1 17
|
|
|
|
/* Teensy 2.0 versus Leonardo These boards use the same chip but the
|
|
* pinouts are different.*/
|
|
#elif defined(__AVR_ATmega32U4__)
|
|
#ifdef CORE_TEENSY
|
|
// it's Teensy 2.0
|
|
//#define IR_SEND_TIMER1 14
|
|
//#define IR_SEND_TIMER3 9
|
|
#define IR_SEND_TIMER4_HS 10
|
|
#else
|
|
/* it's probably Leonardo */
|
|
#define IR_SEND_TIMER1 9
|
|
//#define IR_SEND_TIMER3 5
|
|
//#define IR_SEND_TIMER4_HS 13
|
|
#endif
|
|
|
|
/* Teensy++ 1.0 & 2.0 */
|
|
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
|
//#define IR_SEND_TIMER1 25
|
|
#define IR_SEND_TIMER2 1
|
|
//#define IR_SEND_TIMER3 16
|
|
|
|
/* Sanguino */
|
|
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
|
|
//#define IR_SEND_TIMER1 13
|
|
#define IR_SEND_TIMER2 14
|
|
|
|
/* Arduino Zero, M0, M0 Pro, Feather M0 etc. */
|
|
#elif defined (__SAMD21G18A__)
|
|
// All of the settings can be found in IRLibSAMD21.h
|
|
#include "IRLibSAMD21.h"
|
|
/* Pinoccio Scout */
|
|
#elif defined(__AVR_ATmega256RFR2__)
|
|
#define IR_SEND_TIMER3 3
|
|
|
|
/* Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, etc */
|
|
#else
|
|
//#define IR_SEND_TIMER1 9
|
|
#define IR_SEND_TIMER2 3
|
|
#endif //end of setting IR_SEND_TIMER based on hardware detection
|
|
|
|
/* If you want to use bit-bang PWM output, you should un-comment the line below.
|
|
* The definition must include the pin number for bit-bang output. This could be any
|
|
* available digital output pin. It need not be a designated PWM pin.
|
|
* NOTE: By un-commenting this line, you are forcing the library to ignore
|
|
* hardware detection and timer specifications above. The bit-bang frequency
|
|
* code is not as accurate as using a hardware timer but it is more flexible and
|
|
* less hardware platform dependent.
|
|
*/
|
|
//#define IR_SEND_BIT_BANG 3 //Be sure to set this pin number if you un-comment
|
|
|
|
/* This is a fudge factor that adjusts bit-bang timing. Feel free to experiment
|
|
* for best results.*/
|
|
#define IR_BIT_BANG_OVERHEAD 10
|
|
|
|
/* We are going to presume that you want to use the same hardware timer to control
|
|
* the 50 microsecond interrupt used by the IRrecv receiver class as was specified
|
|
* above in the hardware detection section for sending. Even if you specified bit-bang
|
|
* for sending, the definitions above have selected a default sending timer for you based
|
|
* on hardware detection. If that is correct, then do nothing below. However if you do
|
|
* wish to specify an IR_RECV_TIMER different than the IR_SEND_TIMER selected by the code
|
|
* above, then you should un-comment the IR_RECV_TIMER_OVERRIDE and also un-comment one
|
|
* and only one of the following IR_RECV_TIMERx lines below that.
|
|
* NOTE: You are responsible for ensuring that the timer you are specifying is
|
|
* available on your hardware. You should only choose timers which are shown as available
|
|
* for your hardware platform as shown in the defines in the IR_SEND_TIMER section above.
|
|
* NOTE: This discussion does not apply to SAMD 21 processors.
|
|
*/
|
|
//#define IR_RECV_TIMER_OVERRIDE
|
|
//#define IR_RECV_TIMER1
|
|
//#define IR_RECV_TIMER2
|
|
//#define IR_RECV_TIMER3
|
|
//#define IR_RECV_TIMER4
|
|
//#define IR_RECV_TIMER4_HS
|
|
//#define IR_RECV_TIMER5
|
|
|
|
// Miscellaneous defines needed for computations below
|
|
#ifdef F_CPU
|
|
#define SYSCLOCK F_CPU // main Arduino clock
|
|
#else
|
|
#define SYSCLOCK 16000000 // main Arduino clock
|
|
#endif
|
|
|
|
/* Everything below this point is a computation based on user settings above.
|
|
* In all likelihood you would never need to modify anything below this point
|
|
* unless you are adding some completely new feature or seriously modifying
|
|
* the behavior of existing features. In other words don't try this at home.
|
|
*/
|
|
#if !defined(IR_RECV_TIMER_OVERRIDE)
|
|
#if defined(IR_SEND_TIMER1)
|
|
#define IR_RECV_TIMER1
|
|
#elif defined(IR_SEND_TIMER2)
|
|
#define IR_RECV_TIMER2
|
|
#elif defined(IR_SEND_TIMER3)
|
|
#define IR_RECV_TIMER3
|
|
#elif defined(IR_SEND_TIMER4)
|
|
#define IR_RECV_TIMER4
|
|
#elif defined(IR_SEND_TIMER4_HS)
|
|
#define IR_RECV_TIMER4_HS
|
|
#elif defined(IR_SEND_TIMER5)
|
|
#define IR_RECV_TIMER5
|
|
#elif defined(__SAMD21G18A__)//handle this one a little differently
|
|
#define IR_RECV_TC3
|
|
#else
|
|
#error "Unable to set IR_RECV_TIMER"
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(IR_SEND_BIT_BANG) //defines for bit-bang output
|
|
#define IR_SEND_PWM_PIN IR_SEND_BIT_BANG
|
|
#define IR_SEND_PWM_START unsigned int jmax=time/iLength;\
|
|
for(unsigned int j=0;j<jmax;j++) {\
|
|
digitalWrite(IR_SEND_BIT_BANG, HIGH); delayMicroseconds(onTime);\
|
|
digitalWrite(IR_SEND_BIT_BANG, LOW); delayMicroseconds(offTime);}
|
|
#define IR_SEND_MARK_TIME(time)
|
|
#define IR_SEND_PWM_STOP
|
|
#define IR_SEND_CONFIG_KHZ(val) float Length=1000.0/(float)khz;\
|
|
iLength=int(Length+0.5); onTime=int(Length/3.0); \
|
|
offTime=iLength-onTime-IR_BIT_BANG_OVERHEAD-(val<40);
|
|
|
|
#elif defined(IR_SEND_TIMER1) // defines for timer1 (16 bits)
|
|
#define IR_SEND_PWM_START (TCCR1A |= _BV(COM1A1))
|
|
#define IR_SEND_MARK_TIME(time) IRLibDelayUSecs(time)
|
|
#define IR_SEND_PWM_STOP (TCCR1A &= ~(_BV(COM1A1)))
|
|
#define IR_SEND_CONFIG_KHZ(val) ({ \
|
|
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
|
|
TCCR1A = _BV(WGM11); TCCR1B = _BV(WGM13) | _BV(CS10); \
|
|
ICR1 = pwmval; OCR1A = pwmval / 3; })
|
|
#if defined(CORE_OC1A_PIN)
|
|
#define IR_SEND_PWM_PIN CORE_OC1A_PIN /* Teensy */
|
|
#else
|
|
#define IR_SEND_PWM_PIN IR_SEND_TIMER1
|
|
#endif
|
|
|
|
#elif defined(IR_SEND_TIMER2) // defines for timer2 (8 bits)
|
|
#define IR_SEND_PWM_START (TCCR2A |= _BV(COM2B1))
|
|
#define IR_SEND_MARK_TIME(time) IRLibDelayUSecs(time)
|
|
#define IR_SEND_PWM_STOP (TCCR2A &= ~(_BV(COM2B1)))
|
|
#define IR_SEND_CONFIG_KHZ(val) ({ \
|
|
const uint8_t pwmval = SYSCLOCK / 2000 / (val); \
|
|
TCCR2A = _BV(WGM20); TCCR2B = _BV(WGM22) | _BV(CS20); \
|
|
OCR2A = pwmval; OCR2B = pwmval / 3; })
|
|
#if defined(CORE_OC2B_PIN)
|
|
#define IR_SEND_PWM_PIN CORE_OC2B_PIN /* Teensy */
|
|
#else
|
|
#define IR_SEND_PWM_PIN IR_SEND_TIMER2
|
|
#endif
|
|
|
|
#elif defined(IR_SEND_TIMER3) // defines for timer3 (16 bits)
|
|
#define IR_SEND_PWM_START (TCCR3A |= _BV(COM3A1))
|
|
#define IR_SEND_MARK_TIME(time) IRLibDelayUSecs(time)
|
|
#define IR_SEND_PWM_STOP (TCCR3A &= ~(_BV(COM3A1)))
|
|
#define IR_SEND_CONFIG_KHZ(val) ({ \
|
|
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
|
|
TCCR3A = _BV(WGM31); TCCR3B = _BV(WGM33) | _BV(CS30); \
|
|
ICR3 = pwmval; OCR3A = pwmval / 3; })
|
|
#if defined(CORE_OC3A_PIN)
|
|
#define IR_SEND_PWM_PIN CORE_OC3A_PIN /* Teensy */
|
|
#else
|
|
#define IR_SEND_PWM_PIN IR_SEND_TIMER3
|
|
#endif
|
|
|
|
#elif defined(IR_SEND_TIMER4_HS) // defines for timer4 (10 bits, high speed option)
|
|
#define IR_SEND_PWM_START (TCCR4A |= _BV(COM4A1))
|
|
#define IR_SEND_MARK_TIME(time) IRLibDelayUSecs(time)
|
|
#define IR_SEND_PWM_STOP (TCCR4A &= ~(_BV(COM4A1)))
|
|
#define IR_SEND_CONFIG_KHZ(val) ({ \
|
|
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
|
|
TCCR4A = (1<<PWM4A); TCCR4B = _BV(CS40); \
|
|
TCCR4C = 0; TCCR4D = (1<<WGM40); \
|
|
TCCR4E = 0; TC4H = pwmval >> 8; \
|
|
OCR4C = pwmval; TC4H = (pwmval / 3) >> 8; OCR4A = (pwmval / 3) & 255; })
|
|
#if defined(CORE_OC4A_PIN)
|
|
#define IR_SEND_PWM_PIN CORE_OC4A_PIN /* Teensy */
|
|
#else
|
|
#define IR_SEND_PWM_PIN IR_SEND_TIMER4_HS
|
|
#endif
|
|
|
|
#elif defined(IR_SEND_TIMER4) // defines for timer4 (16 bits)
|
|
#define IR_SEND_PWM_START (TCCR4A |= _BV(COM4A1))
|
|
#define IR_SEND_MARK_TIME(time) IRLibDelayUSecs(time)
|
|
#define IR_SEND_PWM_STOP (TCCR4A &= ~(_BV(COM4A1)))
|
|
#define IR_SEND_CONFIG_KHZ(val) ({ \
|
|
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
|
|
TCCR4A = _BV(WGM41); TCCR4B = _BV(WGM43) | _BV(CS40); \
|
|
ICR4 = pwmval; OCR4A = pwmval / 3; })
|
|
#if defined(CORE_OC4A_PIN)
|
|
#define IR_SEND_PWM_PIN CORE_OC4A_PIN
|
|
#else
|
|
#define IR_SEND_PWM_PIN IR_SEND_TIMER4
|
|
#endif
|
|
|
|
#elif defined(IR_SEND_TIMER5) // defines for timer5 (16 bits)
|
|
#define IR_SEND_PWM_START (TCCR5A |= _BV(COM5A1))
|
|
#define IR_SEND_MARK_TIME(time) IRLibDelayUSecs(time)
|
|
#define IR_SEND_PWM_STOP (TCCR5A &= ~(_BV(COM5A1)))
|
|
#define IR_SEND_CONFIG_KHZ(val) ({ \
|
|
const uint16_t pwmval = SYSCLOCK / 2000 / (val); \
|
|
TCCR5A = _BV(WGM51); TCCR5B = _BV(WGM53) | _BV(CS50); \
|
|
ICR5 = pwmval; OCR5A = pwmval / 3; })
|
|
#if defined(CORE_OC5A_PIN)
|
|
#define IR_SEND_PWM_PIN CORE_OC5A_PIN
|
|
#else
|
|
#define IR_SEND_PWM_PIN IR_SEND_TIMER5
|
|
#endif
|
|
#elif defined(IRLibSAMD21_h) // Used for SAMD 21
|
|
/* All of these definitions have been moved to IRLibSAMD21.h
|
|
#define IR_SEND_PWM_START
|
|
#define IR_SEND_MARK_TIME(time)
|
|
#define IR_SEND_PWM_STOP
|
|
#define IR_SEND_PWM_PIN
|
|
#define IR_SEND_CONFIG_KHZ(val)
|
|
*/
|
|
#else // unknown timer
|
|
#error "Internal code configuration error, no known IR_SEND_TIMER# defined\n"
|
|
#endif
|
|
|
|
/* This section sets up the 50 microsecond interval timer used by the
|
|
* IRrecv receiver class. The various timers have already been selected
|
|
* earlier in this file. Theoretically you could change the 50 but it has not been tested.
|
|
*/
|
|
#define USEC_PER_TICK 50 // microseconds per clock interrupt tick
|
|
|
|
#if defined(IR_RECV_TIMER1) // defines for timer1 (16 bits)
|
|
#define IR_RECV_ENABLE_INTR (TIMSK1 = _BV(OCIE1A))
|
|
#define IR_RECV_DISABLE_INTR (TIMSK1 = 0)
|
|
#define IR_RECV_INTR_NAME ISR(TIMER1_COMPA_vect,ISR_NOBLOCK)
|
|
#define IR_RECV_CONFIG_TICKS() ({ \
|
|
TCCR1A = 0; TCCR1B = _BV(WGM12) | _BV(CS10); \
|
|
OCR1A = SYSCLOCK * USEC_PER_TICK / 1000000; TCNT1 = 0; })
|
|
|
|
#elif defined(IR_RECV_TIMER2) // defines for timer2 (8 bits)
|
|
#define IR_RECV_ENABLE_INTR (TIMSK2 = _BV(OCIE2A))
|
|
#define IR_RECV_DISABLE_INTR (TIMSK2 = 0)
|
|
#define IR_RECV_INTR_NAME ISR(TIMER2_COMPA_vect,ISR_NOBLOCK)
|
|
#define IR_RECV_COUNT_TOP (SYSCLOCK * USEC_PER_TICK / 1000000)
|
|
#if (IR_RECV_COUNT_TOP < 256)
|
|
#define IR_RECV_CONFIG_TICKS() ({ \
|
|
TCCR2A = _BV(WGM21); TCCR2B = _BV(CS20); \
|
|
OCR2A = IR_RECV_COUNT_TOP; TCNT2 = 0; })
|
|
#else
|
|
#define IR_RECV_CONFIG_TICKS() ({ \
|
|
TCCR2A = _BV(WGM21); TCCR2B = _BV(CS21); \
|
|
OCR2A = IR_RECV_COUNT_TOP / 8; TCNT2 = 0; })
|
|
#endif
|
|
|
|
#elif defined(IR_RECV_TIMER3) // defines for timer3 (16 bits)
|
|
#define IR_RECV_ENABLE_INTR (TIMSK3 = _BV(OCIE3A))
|
|
#define IR_RECV_DISABLE_INTR (TIMSK3 = 0)
|
|
#define IR_RECV_INTR_NAME ISR(TIMER3_COMPA_vect,ISR_NOBLOCK)
|
|
#define IR_RECV_CONFIG_TICKS() ({ \
|
|
TCCR3A = 0; TCCR3B = _BV(WGM32) | _BV(CS30); \
|
|
OCR3A = SYSCLOCK * USEC_PER_TICK / 1000000; TCNT3 = 0; })
|
|
|
|
#elif defined(IR_RECV_TIMER4_HS) // defines for timer4 (10 bits, high speed option)
|
|
#define IR_RECV_ENABLE_INTR (TIMSK4 = _BV(TOIE4))
|
|
#define IR_RECV_DISABLE_INTR (TIMSK4 = 0)
|
|
#define IR_RECV_INTR_NAME ISR(TIMER4_OVF_vect,ISR_NOBLOCK)
|
|
#define IR_RECV_CONFIG_TICKS() ({ \
|
|
TCCR4A = 0; TCCR4B = _BV(CS40); \
|
|
TCCR4C = 0; TCCR4D = 0; TCCR4E = 0; \
|
|
TC4H = (SYSCLOCK * USEC_PER_TICK / 1000000) >> 8; \
|
|
OCR4C = (SYSCLOCK * USEC_PER_TICK / 1000000) & 255; \
|
|
TC4H = 0; TCNT4 = 0; })
|
|
|
|
#elif defined(IR_RECV_TIMER4) // defines for timer4 (16 bits)
|
|
#define IR_RECV_ENABLE_INTR (TIMSK4 = _BV(OCIE4A))
|
|
#define IR_RECV_DISABLE_INTR (TIMSK4 = 0)
|
|
#define IR_RECV_INTR_NAME ISR(TIMER4_COMPA_vect,ISR_NOBLOCK)
|
|
#define IR_RECV_CONFIG_TICKS() ({ \
|
|
TCCR4A = 0; TCCR4B = _BV(WGM42) | _BV(CS40); \
|
|
OCR4A = SYSCLOCK * USEC_PER_TICK / 1000000; TCNT4 = 0; })
|
|
|
|
#elif defined(IR_RECV_TIMER5) // defines for timer5 (16 bits)
|
|
#define IR_RECV_ENABLE_INTR (TIMSK5 = _BV(OCIE5A))
|
|
#define IR_RECV_DISABLE_INTR (TIMSK5 = 0)
|
|
#define IR_RECV_INTR_NAME ISR(TIMER5_COMPA_vect,ISR_NOBLOCK)
|
|
#define IR_RECV_CONFIG_TICKS() ({ \
|
|
TCCR5A = 0; TCCR5B = _BV(WGM52) | _BV(CS50); \
|
|
OCR5A = SYSCLOCK * USEC_PER_TICK / 1000000; TCNT5 = 0; })
|
|
#elif defined(IRLibSAMD21_h) //for SAMD 21
|
|
/* All of these definitions have been moved to IRLibSAMD21.h
|
|
#define IR_RECV_ENABLE_INTR
|
|
#define IR_RECV_DISABLE_INTR
|
|
#define IR_RECV_INTR_NAME
|
|
#define IR_RECV_CONFIG_TICKS()
|
|
*/
|
|
#else // unknown timer
|
|
#error "Internal code configuration error, no known IR_RECV_TIMER# defined\n"
|
|
#endif
|
|
|
|
//Cannot use blinking LED on 13 if that's the output pin.
|
|
#if (IR_SEND_PWM_PIN==13)
|
|
#define BLINKLED -1
|
|
#define BLINKLED_ON()
|
|
#define BLINKLED_OFF()
|
|
#endif
|
|
// defines for blinking the LED
|
|
#ifndef BLINKLED
|
|
#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__) || defined(__AVR_ATmega2560__)
|
|
#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)
|
|
#elif defined(__AVR_ATmega32u4__) || defined(__AVR_ATmega328__)
|
|
#define BLINKLED 13
|
|
#define BLINKLED_ON() (PORTB |= B00100000)
|
|
#define BLINKLED_OFF() (PORTB &= B11011111)
|
|
#else
|
|
#define BLINKLED 13
|
|
#define BLINKLED_ON() (digitalWrite(13, HIGH))
|
|
#define BLINKLED_OFF() (digitalWrite(13, LOW))
|
|
#endif
|
|
#endif
|
|
|
|
extern uint8_t IRLib_didIROut;//See the explanation in IRLibHardware.cpp
|
|
#endif //IRLibHardware_h
|