diff --git a/Contributors.md b/Contributors.md index 1bed7b6..821c8da 100644 --- a/Contributors.md +++ b/Contributors.md @@ -18,5 +18,7 @@ These are the active contributors of this project that you may contact if there - [philipphenkel](https://github.com/philipphenkel): Active Contributor - [MCUdude](https://github.com/MCUdude): Contributor - [marcmerlin](https://github.com/marcmerlin): Contributor (ESP32 port) +- [bengtmartensson](https://github.com/bengtmartensson): Active Contributor +- [MrBryonMiller](https://github.com/MrBryonMiller): Contributor Note: This list is being updated constantly so please let [z3t0](https://github.com/z3t0) know if you have been missed. diff --git a/IRremote.cpp b/IRremote.cpp index e811cfc..f41f818 100644 --- a/IRremote.cpp +++ b/IRremote.cpp @@ -24,7 +24,7 @@ # include "IRremoteInt.h" #undef IR_GLOBAL -#ifndef IR_TIMER_USE_ESP32 +#ifdef HAS_AVR_INTERRUPT_H #include #endif @@ -123,11 +123,7 @@ int MATCH_SPACE (int measured_ticks, int desired_us) // As soon as first MARK arrives: // Gap width is recorded; Ready is cleared; New logging starts // -#ifdef IR_TIMER_USE_ESP32 -void IRTimer() -#else ISR (TIMER_INTR_NAME) -#endif { TIMER_RESET; @@ -189,6 +185,7 @@ ISR (TIMER_INTR_NAME) break; } +#ifdef BLINKLED // If requested, flash LED while receiving IR data if (irparams.blinkflag) { if (irdata == MARK) @@ -197,4 +194,5 @@ ISR (TIMER_INTR_NAME) else if (irparams.blinkpin) digitalWrite(irparams.blinkpin, LOW); // Turn user defined pin LED on else BLINKLED_OFF() ; // if no user defined LED pin, turn default LED pin for the hardware on } +#endif // BLINKLED } diff --git a/IRremote.h b/IRremote.h index fe1a870..9282843 100644 --- a/IRremote.h +++ b/IRremote.h @@ -259,7 +259,18 @@ class IRrecv class IRsend { public: - IRsend () { } +#ifdef USE_SOFT_CARRIER + + IRsend(int pin = SEND_PIN) + { + sendPin = pin; + } +#else + + IRsend() + { + } +#endif void custom_delay_usec (unsigned long uSecs); void enableIROut (int khz) ; @@ -339,6 +350,20 @@ class IRsend # if SEND_LEGO_PF void sendLegoPowerFunctions (uint16_t data, bool repeat = true) ; # endif + +#ifdef USE_SOFT_CARRIER + private: + int sendPin; + + unsigned int periodTime; + unsigned int periodOnTime; + + void sleepMicros(unsigned long us); + void sleepUntilMicros(unsigned long targetTime); + +#else + const int sendPin = SEND_PIN; +#endif } ; #endif diff --git a/boarddefs.h b/boarddefs.h index 17e2551..5c49465 100644 --- a/boarddefs.h +++ b/boarddefs.h @@ -20,6 +20,32 @@ #ifndef boarddefs_h #define boarddefs_h +// Define some defaults, that some boards may like to override +// (This is to avoid negative logic, ! DONT_... is just awkward.) + +// This board has/needs the avr/interrupt.h +#define HAS_AVR_INTERRUPT_H + +// Define if sending is supported +#define SENDING_SUPPORTED + +// If defined, a standard enableIRIn function will be define. +// Undefine for boards supplying their own. +#define USE_DEFAULT_ENABLE_IR_IN + +// Duty cycle in percent for sent signals. Presently takes effect only with USE_SOFT_CARRIER +#define DUTY_CYCLE 50 + +// If USE_SOFT_CARRIER, this amount (in micro seconds) is subtracted from the +// on-time of the pulses. +#define PULSE_CORRECTION 3 + +// digitalWrite is supposed to be slow. If this is an issue, define faster, +// board-dependent versions of these macros SENDPIN_ON(pin) and SENDPIN_OFF(pin). +// Portable, possibly slow, default definitions are given at the end of this file. +// If defining new versions, feel free to ignore the pin argument if it +// is not configurable on the current board. + //------------------------------------------------------------------------------ // Defines for blinking the LED // @@ -39,11 +65,31 @@ # define BLINKLED_ON() (PORTD |= B00000001) # define BLINKLED_OFF() (PORTD &= B11111110) -// No system LED on ESP32, disable blinking +#elif defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD) +# define BLINKLED LED_BUILTIN +# define BLINKLED_ON() (digitalWrite(LED_BUILTIN, HIGH)) +# define BLINKLED_OFF() (digitalWrite(LED_BUILTIN, LOW)) + +# define USE_SOFT_CARRIER + // Define to use spin wait instead of delayMicros() +//# define USE_SPIN_WAIT +# undef USE_DEFAULT_ENABLE_IR_IN + + // The default pin used used for sending. +# define SEND_PIN 9 + #elif defined(ESP32) -# define BLINKLED 255 -# define BLINKLED_ON() 1 -# define BLINKLED_OFF() 1 + // No system LED on ESP32, disable blinking by NOT defining BLINKLED + + // avr/interrupt.h is not present +# undef HAS_AVR_INTERRUPT_H + + // Sending not implemented +# undef SENDING_SUPPORTED# + + // Supply own enbleIRIn +# undef USE_DEFAULT_ENABLE_IR_IN + #else # define BLINKLED 13 # define BLINKLED_ON() (PORTB |= B00100000) @@ -138,6 +184,10 @@ #elif defined(ESP32) #define IR_TIMER_USE_ESP32 + +#elif defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD) + #define TIMER_PRESCALER_DIV 64 + #else // Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, Nano, etc // ATmega48, ATmega88, ATmega168, ATmega328 @@ -190,17 +240,17 @@ //----------------- #if defined(CORE_OC2B_PIN) -# define TIMER_PWM_PIN CORE_OC2B_PIN // Teensy +# define SEND_PIN CORE_OC2B_PIN // Teensy #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) -# define TIMER_PWM_PIN 9 // Arduino Mega +# define SEND_PIN 9 // Arduino Mega #elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) \ || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) \ || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) \ || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega164A__) \ || defined(__AVR_ATmega164P__) -# define TIMER_PWM_PIN 14 // MightyCore +# define SEND_PIN 14 // MightyCore #else -# define TIMER_PWM_PIN 3 // Arduino Duemilanove, Diecimila, LilyPad, etc +# define SEND_PIN 3 // Arduino Duemilanove, Diecimila, LilyPad, etc #endif // ATmega48, ATmega88, ATmega168, ATmega328 //--------------------------------------------------------- @@ -243,22 +293,22 @@ //----------------- #if defined(CORE_OC1A_PIN) -# define TIMER_PWM_PIN CORE_OC1A_PIN // Teensy +# define SEND_PIN CORE_OC1A_PIN // Teensy #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) -# define TIMER_PWM_PIN 11 // Arduino Mega +# define SEND_PIN 11 // Arduino Mega #elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) -# define TIMER_PWM_PIN 13 // MegaCore +# define SEND_PIN 13 // MegaCore #elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) \ || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) \ || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) \ || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega164A__) \ || defined(__AVR_ATmega164P__) || defined(__AVR_ATmega32__) \ || defined(__AVR_ATmega16__) || defined(__AVR_ATmega8535__) -# define TIMER_PWM_PIN 13 // MightyCore +# define SEND_PIN 13 // MightyCore #elif defined(__AVR_ATtiny84__) -# define TIMER_PWM_PIN 6 +# define SEND_PIN 6 #else -# define TIMER_PWM_PIN 9 // Arduino Duemilanove, Diecimila, LilyPad, etc +# define SEND_PIN 9 // Arduino Duemilanove, Diecimila, LilyPad, etc #endif // ATmega48, ATmega88, ATmega168, ATmega328 //--------------------------------------------------------- @@ -290,11 +340,11 @@ //----------------- #if defined(CORE_OC3A_PIN) -# define TIMER_PWM_PIN CORE_OC3A_PIN // Teensy +# define SEND_PIN CORE_OC3A_PIN // Teensy #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) -# define TIMER_PWM_PIN 5 // Arduino Mega +# define SEND_PIN 5 // Arduino Mega #elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) -# define TIMER_PWM_PIN 6 // MightyCore +# define SEND_PIN 6 // MightyCore #else # error "Please add OC3A pin number here\n" #endif @@ -338,9 +388,9 @@ //----------------- #if defined(CORE_OC4A_PIN) -# define TIMER_PWM_PIN CORE_OC4A_PIN // Teensy +# define SEND_PIN CORE_OC4A_PIN // Teensy #elif defined(__AVR_ATmega32U4__) -# define TIMER_PWM_PIN 13 // Leonardo +# define SEND_PIN 13 // Leonardo #else # error "Please add OC4A pin number here\n" #endif @@ -374,9 +424,9 @@ //----------------- #if defined(CORE_OC4A_PIN) -# define TIMER_PWM_PIN CORE_OC4A_PIN +# define SEND_PIN CORE_OC4A_PIN #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) -# define TIMER_PWM_PIN 6 // Arduino Mega +# define SEND_PIN 6 // Arduino Mega #else # error "Please add OC4A pin number here\n" #endif @@ -410,9 +460,9 @@ //----------------- #if defined(CORE_OC5A_PIN) -# define TIMER_PWM_PIN CORE_OC5A_PIN +# define SEND_PIN CORE_OC5A_PIN #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) -# define TIMER_PWM_PIN 46 // Arduino Mega +# define SEND_PIN 46 // Arduino Mega #else # error "Please add OC5A pin number here\n" #endif @@ -479,7 +529,7 @@ CMT_MSC = 0x03; \ }) -#define TIMER_PWM_PIN 5 +#define SEND_PIN 5 // defines for TPM1 timer on Teensy-LC #elif defined(IR_USE_TIMER_TPM1) @@ -509,7 +559,7 @@ FTM1_C0V = 0; \ FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0) | FTM_SC_TOF | FTM_SC_TOIE; \ }) -#define TIMER_PWM_PIN 16 +#define SEND_PIN 16 // defines for timer_tiny0 (8 bits) #elif defined(IR_USE_TIMER_TINY0) @@ -543,7 +593,7 @@ }) #endif -#define TIMER_PWM_PIN 1 /* ATtiny85 */ +#define SEND_PIN 1 /* ATtiny85 */ //--------------------------------------------------------- // ESP32 (ESP8266 should likely be added here too) @@ -560,12 +610,29 @@ // way to do this on ESP32 is using the RMT built in driver like in this incomplete library below // https://github.com/ExploreEmbedded/ESP32_RMT #elif defined(IR_TIMER_USE_ESP32) -#define TIMER_RESET -#define TIMER_ENABLE_PWM -#define TIMER_DISABLE_PWM Serial.println("IRsend not implemented for ESP32 yet"); -#define TIMER_ENABLE_INTR -#define TIMER_DISABLE_INTR -#define TIMER_INTR_NAME + +#define TIMER_RESET + +#ifdef ISR +# undef ISR +#endif +#define ISR(f) void IRTimer() + +#elif defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD) +// use timer 3 hardcoded at this time + +#define TIMER_RESET +#define TIMER_ENABLE_PWM // Not presently used +#define TIMER_DISABLE_PWM +#define TIMER_ENABLE_INTR NVIC_EnableIRQ(TC3_IRQn) // Not presently used +#define TIMER_DISABLE_INTR NVIC_DisableIRQ(TC3_IRQn) +#define TIMER_INTR_NAME TC3_Handler // Not presently used +#define TIMER_CONFIG_KHZ(f) + +#ifdef ISR +# undef ISR +#endif +#define ISR(f) void irs() //--------------------------------------------------------- // Unknown Timer @@ -574,4 +641,13 @@ # error "Internal code configuration error, no known IR_USE_TIMER# defined\n" #endif +// Provide default definitions, portable but possibly slower than necessary. +#ifndef SENDPIN_ON +#define SENDPIN_ON(pin) digitalWrite(pin, HIGH) +#endif + +#ifndef SENDPIN_OFF +#define SENDPIN_OFF(pin) digitalWrite(pin, LOW) +#endif + #endif // ! boarddefs_h diff --git a/esp32.cpp b/esp32.cpp new file mode 100644 index 0000000..ef4d794 --- /dev/null +++ b/esp32.cpp @@ -0,0 +1,39 @@ +#ifdef ESP32 + +// This file contains functions specific to the ESP32. + +#include "IRremote.h" +#include "IRremoteInt.h" + +// "Idiot check" +#ifdef USE_DEFAULT_ENABLE_IR_IN +#error Must undef USE_DEFAULT_ENABLE_IR_IN +#endif + +hw_timer_t *timer; +void IRTimer(); // defined in IRremote.cpp, masqueraded as ISR(TIMER_INTR_NAME) + +//+============================================================================= +// initialization +// +void IRrecv::enableIRIn ( ) +{ +// Interrupt Service Routine - Fires every 50uS + // ESP32 has a proper API to setup timers, no weird chip macros needed + // simply call the readable API versions :) + // 3 timers, choose #1, 80 divider nanosecond precision, 1 to count up + timer = timerBegin(1, 80, 1); + timerAttachInterrupt(timer, &IRTimer, 1); + // every 50ns, autoreload = true + timerAlarmWrite(timer, 50, true); + timerAlarmEnable(timer); + + // Initialize state machine variables + irparams.rcvstate = STATE_IDLE; + irparams.rawlen = 0; + + // Set pin modes + pinMode(irparams.recvpin, INPUT); +} + +#endif // ESP32 diff --git a/examples/IRremoteInfo/IRremoteInfo.ino b/examples/IRremoteInfo/IRremoteInfo.ino index 2a269d9..c3f3297 100644 --- a/examples/IRremoteInfo/IRremoteInfo.ino +++ b/examples/IRremoteInfo/IRremoteInfo.ino @@ -79,7 +79,7 @@ void dumpTIMER() { void dumpTimerPin() { Serial.print(F("IR Tx Pin: ")); - Serial.println(TIMER_PWM_PIN); + Serial.println(SEND_PIN); } void dumpClock() { diff --git a/irRecv.cpp b/irRecv.cpp index 12b0806..b549dac 100644 --- a/irRecv.cpp +++ b/irRecv.cpp @@ -1,10 +1,5 @@ #include "IRremote.h" #include "IRremoteInt.h" - -#ifdef IR_TIMER_USE_ESP32 -hw_timer_t *timer; -void IRTimer(); // defined in IRremote.cpp -#endif //+============================================================================= // Decodes the received IR message @@ -120,19 +115,10 @@ IRrecv::IRrecv (int recvpin, int blinkpin) //+============================================================================= // initialization // +#ifdef USE_DEFAULT_ENABLE_IR_IN void IRrecv::enableIRIn ( ) { -// Interrupt Service Routine - Fires every 50uS -#ifdef ESP32 - // ESP32 has a proper API to setup timers, no weird chip macros needed - // simply call the readable API versions :) - // 3 timers, choose #1, 80 divider nanosecond precision, 1 to count up - timer = timerBegin(1, 80, 1); - timerAttachInterrupt(timer, &IRTimer, 1); - // every 50ns, autoreload = true - timerAlarmWrite(timer, 50, true); - timerAlarmEnable(timer); -#else +// Interrupt Service Routine - Fires every 50uS cli(); // Setup pulse clock timer interrupt // Prescale /8 (16M/8 = 0.5 microseconds per tick) @@ -146,7 +132,6 @@ void IRrecv::enableIRIn ( ) TIMER_RESET; sei(); // enable interrupts -#endif // Initialize state machine variables irparams.rcvstate = STATE_IDLE; @@ -155,14 +140,17 @@ void IRrecv::enableIRIn ( ) // Set pin modes pinMode(irparams.recvpin, INPUT); } +#endif // USE_DEFAULT_ENABLE_IR_IN //+============================================================================= // Enable/disable blinking of pin 13 on IR processing // void IRrecv::blink13 (int blinkflag) { +#ifdef BLINKLED irparams.blinkflag = blinkflag; if (blinkflag) pinMode(BLINKLED, OUTPUT) ; +#endif } //+============================================================================= diff --git a/irSend.cpp b/irSend.cpp index c3ef3ff..a01b5a0 100644 --- a/irSend.cpp +++ b/irSend.cpp @@ -1,6 +1,7 @@ #include "IRremote.h" #include "IRremoteInt.h" +#ifdef SENDING_SUPPORTED //+============================================================================= void IRsend::sendRaw (const unsigned int buf[], unsigned int len, unsigned int hz) { @@ -15,14 +16,59 @@ void IRsend::sendRaw (const unsigned int buf[], unsigned int len, unsigned in space(0); // Always end with the LED off } +#ifdef USE_SOFT_CARRIER +void inline IRsend::sleepMicros(unsigned long us) +{ +#ifdef USE_SPIN_WAIT + sleepUntilMicros(micros() + us); +#else + if (us > 0U) // Is this necessary? (Official docu https://www.arduino.cc/en/Reference/DelayMicroseconds does not tell.) + delayMicroseconds((unsigned int) us); +#endif +} + +void inline IRsend::sleepUntilMicros(unsigned long targetTime) +{ +#ifdef USE_SPIN_WAIT + while (micros() < targetTime) + ; +#else + unsigned long now = micros(); + if (now < targetTime) + sleepMicros(targetTime - now); +#endif +} +#endif // USE_SOFT_CARRIER + //+============================================================================= // Sends an IR mark for the specified number of microseconds. // The mark output is modulated at the PWM frequency. // -void IRsend::mark (unsigned int time) + +void IRsend::mark(unsigned int time) { +#ifdef USE_SOFT_CARRIER + unsigned long start = micros(); + unsigned long stop = start + time; + if (stop + periodTime < start) + // Counter wrap-around, happens very seldomly, but CAN happen. + // Just give up instead of possibly damaging the hardware. + return; + + unsigned long nextPeriodEnding = start; + unsigned long now = micros(); + while (now < stop) { + SENDPIN_ON(sendPin); + sleepMicros(periodOnTime); + SENDPIN_OFF(sendPin); + nextPeriodEnding += periodTime; + sleepUntilMicros(nextPeriodEnding); + now = micros(); + } +#else TIMER_ENABLE_PWM; // Enable pin 3 PWM output if (time > 0) custom_delay_usec(time); +#endif } //+============================================================================= @@ -54,13 +100,16 @@ void IRsend::space (unsigned int time) // void IRsend::enableIROut (int khz) { -// FIXME: implement ESP32 support, see IR_TIMER_USE_ESP32 in boarddefs.h -#ifndef ESP32 +#ifdef USE_SOFT_CARRIER + periodTime = (1000U + khz/2) / khz; // = 1000/khz + 1/2 = round(1000.0/khz) + periodOnTime = periodTime * DUTY_CYCLE / 100U - PULSE_CORRECTION; +#endif + // Disable the Timer2 Interrupt (which is used for receiving IR) TIMER_DISABLE_INTR; //Timer2 Overflow Interrupt - pinMode(TIMER_PWM_PIN, OUTPUT); - digitalWrite(TIMER_PWM_PIN, LOW); // When not sending PWM, we want it low + pinMode(sendPin, OUTPUT); + SENDPIN_OFF(sendPin); // When not sending, we want it low // COM2A = 00: disconnect OC2A // COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted @@ -68,7 +117,6 @@ void IRsend::enableIROut (int khz) // CS2 = 000: no prescaling // The top value for the timer. The modulation frequency will be SYSCLOCK / 2 / OCR2A. TIMER_CONFIG_KHZ(khz); -#endif } //+============================================================================= @@ -88,3 +136,4 @@ void IRsend::custom_delay_usec(unsigned long uSecs) { //} } +#endif // SENDING_SUPPORTED \ No newline at end of file diff --git a/sam.cpp b/sam.cpp new file mode 100644 index 0000000..0657589 --- /dev/null +++ b/sam.cpp @@ -0,0 +1,102 @@ +// Support routines for SAM processor boards + +#include "IRremote.h" +#include "IRremoteInt.h" + +#if defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD) + +// "Idiot check" +#ifdef USE_DEFAULT_ENABLE_IR_IN +#error Must undef USE_DEFAULT_ENABLE_IR_IN +#endif + +//+============================================================================= +// ATSAMD Timer setup & IRQ functions +// + +// following based on setup from GitHub jdneo/timerInterrupt.ino + +static void setTimerFrequency(int frequencyHz) +{ + int compareValue = (SYSCLOCK / (TIMER_PRESCALER_DIV * frequencyHz)) - 1; + //Serial.println(compareValue); + TcCount16* TC = (TcCount16*) TC3; + // Make sure the count is in a proportional position to where it was + // to prevent any jitter or disconnect when changing the compare value. + TC->COUNT.reg = map(TC->COUNT.reg, 0, TC->CC[0].reg, 0, compareValue); + TC->CC[0].reg = compareValue; + //Serial.print("COUNT.reg "); + //Serial.println(TC->COUNT.reg); + //Serial.print("CC[0].reg "); + //Serial.println(TC->CC[0].reg); + while (TC->STATUS.bit.SYNCBUSY == 1); +} + +static void startTimer() +{ + REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID_TCC2_TC3); + while (GCLK->STATUS.bit.SYNCBUSY == 1); // wait for sync + + TcCount16* TC = (TcCount16*) TC3; + + TC->CTRLA.reg &= ~TC_CTRLA_ENABLE; + while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync + + // Use the 16-bit timer + TC->CTRLA.reg |= TC_CTRLA_MODE_COUNT16; + while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync + + // Use match mode so that the timer counter resets when the count matches the compare register + TC->CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ; + while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync + + // Set prescaler to 1024 + //TC->CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1024; + TC->CTRLA.reg |= TC_CTRLA_PRESCALER_DIV64; + while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync + + setTimerFrequency(1000000 / USECPERTICK); + + // Enable the compare interrupt + TC->INTENSET.reg = 0; + TC->INTENSET.bit.MC0 = 1; + + NVIC_EnableIRQ(TC3_IRQn); + + TC->CTRLA.reg |= TC_CTRLA_ENABLE; + while (TC->STATUS.bit.SYNCBUSY == 1); // wait for sync +} + +//+============================================================================= +// initialization +// + +void IRrecv::enableIRIn() +{ + // Interrupt Service Routine - Fires every 50uS + //Serial.println("Starting timer"); + startTimer(); + //Serial.println("Started timer"); + + // Initialize state machine variables + irparams.rcvstate = STATE_IDLE; + irparams.rawlen = 0; + + // Set pin modes + pinMode(irparams.recvpin, INPUT); +} + +void irs(); // Defined in IRRemote as ISR(TIMER_INTR_NAME) + +void TC3_Handler(void) +{ + TcCount16* TC = (TcCount16*) TC3; + // If this interrupt is due to the compare register matching the timer count + // we toggle the LED. + if (TC->INTFLAG.bit.MC0 == 1) { + TC->INTFLAG.bit.MC0 = 1; + irs(); + } +} + +#endif // defined(ARDUINO_ARCH_SAM) || defined(ARDUINO_ARCH_SAMD) \ No newline at end of file