IRremote
IRTimer.hpp
Go to the documentation of this file.
1 
35 #ifndef _IR_TIMER_HPP
36 #define _IR_TIMER_HPP
37 
44 /*
45  * Functions declared here
46  */
47 void timerConfigForReceive(); // Initialization of 50 us timer, interrupts are still disabled
48 void timerEnableReceiveInterrupt(); // Enable interrupts of an initialized timer
49 void timerDisableReceiveInterrupt(); // Disable interrupts of an initialized timer
50 void timerResetInterruptPending(); // ISR helper function for some architectures, which require a manual reset
51 // of the pending interrupt (TIMER_REQUIRES_RESET_INTR_PENDING is defined). Otherwise empty.
52 
53 void timerConfigForSend(uint16_t aFrequencyKHz); // Initialization of timer hardware generated PWM, if defined(SEND_PWM_BY_TIMER)
54 void enableSendPWMByTimer(); // Switch on PWM generation
55 void disableSendPWMByTimer(); // Switch off PWM generation
56 
57 // SEND_PWM_BY_TIMER for different architectures is enabled / defined at IRremote.hpp line 195.
58 #if defined(SEND_PWM_BY_TIMER) && ( (defined(ESP32) || defined(ARDUINO_ARCH_RP2040) || defined(PARTICLE)) || defined(ARDUINO_ARCH_MBED) )
59 #define SEND_PWM_DOES_NOT_USE_RECEIVE_TIMER // Receive timer and send generation timer are independent here.
60 #endif
61 
62 #if defined(IR_SEND_PIN) && defined(SEND_PWM_BY_TIMER) && !defined(SEND_PWM_DOES_NOT_USE_RECEIVE_TIMER) // For ESP32 etc. IR_SEND_PIN definition is useful
63 #undef IR_SEND_PIN // To avoid "warning: "IR_SEND_PIN" redefined". The user warning is done at IRremote.hpp line 202.
64 #endif
65 
66 #if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
67 // Use the inverse value, so same code should work for active Low output
68 #define IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH (100 - IR_SEND_DUTY_CYCLE_PERCENT)
69 #else
70 #define IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH IR_SEND_DUTY_CYCLE_PERCENT
71 #endif
72 
73 // Macros for enabling timers for development
74 //#define SEND_PWM_BY_TIMER
75 //#define IR_USE_AVR_TIMER1
76 //#define IR_USE_AVR_TIMER2
77 //#define IR_USE_AVR_TIMER3
78 //#define IR_USE_AVR_TIMER4
79 //#define IR_USE_AVR_TIMER4_HS
80 //#define IR_USE_AVR_TIMER5
81 //#define IR_USE_AVR_TIMER_TINY0
82 //#define IR_USE_AVR_TIMER_TINY1
83 //#define IR_USE_AVR_TIMER_A
84 //#define IR_USE_AVR_TIMER_B
85 //#define IR_USE_AVR_TIMER_D
86 //#define __MK20DX128__
87 //#define __MKL26Z64__
88 //#define __IMXRT1062__
89 //#define ESP8266
90 //#define ESP32
91 //#define ARDUINO_ARCH_SAMD
92 //#define ARDUINO_ARCH_MBED
93 //#define ARDUINO_ARCH_RP2040
94 //#define NRF5
95 //#define __STM32F1__
96 //#define STM32F1xx
97 //#define PARTICLE
98 //#define ARDUINO_ARCH_RENESAS
99 
100 #if defined (DOXYGEN)
101 
104 #define IR_SEND_PIN
105 
113 }
118 }
119 
125 }
126 
136 void timerConfigForSend(uint16_t aFrequencyKHz) {
137 }
138 
143 }
148 }
149 
150 #elif defined(__AVR__)
151 /**********************************************************************************************************************
152  * Mapping of AVR boards to AVR timers
153  * For some CPU's you have the option to switch the timer and the hardware send pin
154  **********************************************************************************************************************/
155 /***************************************
156  * Plain AVR CPU's, no boards
157  ***************************************/
158 // Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, Nano, etc
159 #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) || defined(__AVR_ATmega168__) \
160  || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega88PB__)
161 # if !defined(IR_USE_AVR_TIMER1) && !defined(IR_USE_AVR_TIMER2)
162 //#define IR_USE_AVR_TIMER1 // send pin = pin 9
163 #define IR_USE_AVR_TIMER2 // send pin = pin 3
164 # endif
165 
166 // Arduino Mega
167 #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
168 # if !defined(IR_USE_AVR_TIMER1) && !defined(IR_USE_AVR_TIMER2) && !defined(IR_USE_AVR_TIMER3) && !defined(IR_USE_AVR_TIMER4) && !defined(IR_USE_AVR_TIMER5)
169 //#define IR_USE_AVR_TIMER1 // send pin = pin 11
170 #define IR_USE_AVR_TIMER2 // send pin = pin 9
171 //#define IR_USE_AVR_TIMER3 // send pin = pin 5
172 //#define IR_USE_AVR_TIMER4 // send pin = pin 6
173 //#define IR_USE_AVR_TIMER5 // send pin = pin 46
174 # endif
175 
176 // Leonardo
177 #elif defined(__AVR_ATmega32U4__) && ! defined(TEENSYDUINO) && ! defined(ARDUINO_AVR_PROMICRO)
178 # if !defined(IR_USE_AVR_TIMER1) && !defined(IR_USE_AVR_TIMER3) && !defined(IR_USE_AVR_TIMER4_HS)
179 //#define IR_USE_AVR_TIMER1 // send pin = pin 9
180 #define IR_USE_AVR_TIMER3 // send pin = pin 5
181 //#define IR_USE_AVR_TIMER4_HS // send pin = pin 13
182 # endif
183 
184 // Nano Every, Uno WiFi Rev2 and similar
185 #elif defined(__AVR_ATmega808__) || defined(__AVR_ATmega809__) || defined(__AVR_ATmega3208__) || defined(__AVR_ATmega3209__) \
186  || defined(__AVR_ATmega1608__) || defined(__AVR_ATmega1609__) || defined(__AVR_ATmega4808__) || defined(__AVR_ATmega4809__)
187 # if !defined(IR_USE_AVR_TIMER_B)
188 #define IR_USE_AVR_TIMER_B // send pin = pin 6 on ATmega4809 1 on ATmega4809
189 # endif
190 
191 #elif defined(__AVR_ATtiny816__) || defined(__AVR_ATtiny1604__) || defined(__AVR_ATtiny1614__) || defined(__AVR_ATtiny1624__) \
192  || defined(__AVR_ATtiny1616__) || defined(__AVR_ATtiny3216__) || defined(__AVR_ATtiny3217__) // e.g. TinyCore boards
193 # if !defined(IR_USE_AVR_TIMER_A) && !defined(IR_USE_AVR_TIMER_D)
194 #define IR_USE_AVR_TIMER_A // use this if you use megaTinyCore, Tone is on TCB and millis() on TCD
195 //#define IR_USE_AVR_TIMER_D // use this if you use TinyCore
196 # endif
197 
198 // ATmega8u2, ATmega16U2, ATmega32U2, ATmega8 - Timer 2 does not work with existing code below
199 #elif defined(__AVR_ATmega8U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega8__)
200 # if !defined(IR_USE_AVR_TIMER1)
201 #define IR_USE_AVR_TIMER1 // send pin = pin C6
202 # endif
203 
204 // ATtiny84
205 #elif defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny88__)
206 # if !defined(IR_USE_AVR_TIMER1)
207 #define IR_USE_AVR_TIMER1 // send pin = pin 6, no tone() available when using ATTinyCore
208 # endif
209 
210 #elif defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
211 # if !defined(IR_USE_AVR_TIMER1)
212 #define IR_USE_AVR_TIMER1 // send pin = pin PB1 / 8
213 # endif
214 #define USE_TIMER_CHANNEL_B
215 
216 //ATtiny85, 45, 25
217 #elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
218 # if !defined(IR_USE_AVR_TIMER_TINY0) && !defined(IR_USE_AVR_TIMER_TINY1)
219 # if defined(ARDUINO_AVR_DIGISPARK) // tested with 16 and 8 MHz
220 #define IR_USE_AVR_TIMER_TINY0 // send pin = pin 1
221 // standard Digispark settings use timer 1 for millis() and micros()
222 # else
223 // standard ATTinyCore settings use timer 0 for millis() and micros()
224 #define IR_USE_AVR_TIMER_TINY1 // send pin = pin 4
225 # endif
226 # endif
227 
228 /***************************************
229  * SPARKFUN Pro Micro board
230  ***************************************/
231 #elif defined(ARDUINO_AVR_PROMICRO)
232 # if !defined(IR_USE_AVR_TIMER1) && !defined(IR_USE_AVR_TIMER3) && !defined(IR_USE_AVR_TIMER4_HS)
233 //#define IR_USE_AVR_TIMER1 // send pin = pin 9
234 #define IR_USE_AVR_TIMER3 // send pin = pin 5
235 //#define IR_USE_AVR_TIMER4_HS // send pin = pin 13
236 # endif
237 
238 /***************************************
239  * TEENSY Boards
240  ***************************************/
241 // Teensy 1.0
242 #elif defined(__AVR_AT90USB162__)
243 # if !defined(IR_USE_AVR_TIMER1)
244 #define IR_USE_AVR_TIMER1 // send pin = pin 17
245 # endif
246 
247 // Teensy++ 1.0 & 2.0
248 #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
249 # if !defined(IR_USE_AVR_TIMER1) && !defined(IR_USE_AVR_TIMER2) && !defined(IR_USE_AVR_TIMER3)
250 //#define IR_USE_AVR_TIMER1 // send pin = pin 25
251 #define IR_USE_AVR_TIMER2 // send pin = pin 1
252 //#define IR_USE_AVR_TIMER3 // send pin = pin 16
253 # endif
254 
255 // Teensy 2.0
256 #elif defined(__AVR_ATmega32U4__) && defined(TEENSYDUINO)
257 # if !defined(IR_USE_AVR_TIMER1) && !defined(IR_USE_AVR_TIMER3) && !defined(IR_USE_AVR_TIMER4_HS)
258 //#define IR_USE_AVR_TIMER1 // send pin = pin 14 (Teensy 2.0 - physical pin: B5)
259 //#define IR_USE_AVR_TIMER3 // send pin = pin 9 (Teensy 2.0 - physical pin: C6)
260 #define IR_USE_AVR_TIMER4_HS // send pin = pin 10 (Teensy 2.0 - physical pin: C7)
261 # endif
262 
263 /***************************************
264  * CPU's with MegaCore
265  ***************************************/
266 // MegaCore - ATmega64, ATmega128
267 #elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2560__)
268 # if !defined(IR_USE_AVR_TIMER1)
269 #define IR_USE_AVR_TIMER1 // send pin = pin 13
270 # endif
271 
272 /***************************************
273  * CPU's with MajorCore
274  ***************************************/
275 #elif defined(__AVR_ATmega8515__) || defined(__AVR_ATmega162__)
276 # if !defined(IR_USE_AVR_TIMER1) && !defined(IR_USE_AVR_TIMER3)
277 #define IR_USE_AVR_TIMER1 // send pin = pin 13
278 //#define IR_USE_AVR_TIMER3 // send pin = pin 12 - ATmega162 only
279 # endif
280 
281 /***************************************
282  * CPU's with MightyCore
283  ***************************************/
284 // MightyCore - ATmega1284
285 #elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
286 # if !defined(IR_USE_AVR_TIMER1) && !defined(IR_USE_AVR_TIMER2) && !defined(IR_USE_AVR_TIMER3)
287 //#define IR_USE_AVR_TIMER1 // send pin = pin 13
288 #define IR_USE_AVR_TIMER2 // send pin = pin 14
289 //#define IR_USE_AVR_TIMER3 // send pin = pin 6
290 # endif
291 
292 // MightyCore - ATmega164, ATmega324, ATmega644
293 #elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) \
294 || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) \
295 || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega164A__) \
296 || defined(__AVR_ATmega164P__)
297 # if !defined(IR_USE_AVR_TIMER1) && !defined(IR_USE_AVR_TIMER2)
298 //#define IR_USE_AVR_TIMER1 // send pin = pin 13
299 #define IR_USE_AVR_TIMER2 // send pin = pin 14
300 # endif
301 
302 // MightyCore - ATmega8535, ATmega16, ATmega32
303 #elif defined(__AVR_ATmega8535__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__)
304 # if !defined(IR_USE_AVR_TIMER1)
305 #define IR_USE_AVR_TIMER1 // send pin = pin 13
306 # endif
307 
308 #endif // AVR CPU's
309 /**********************************************************************************************************************
310  * End of AVR mapping, start of AVR timers
311  **********************************************************************************************************************/
312 /*
313  * AVR Timer1 (16 bits)
314  */
315 #if defined(IR_USE_AVR_TIMER1)
316 
317 # if defined(TIMSK1)
318 #define TIMSK TIMSK1 // use the value of TIMSK1 for the statements below
319 # endif
320 
322  TIMSK |= _BV(OCIE1A);
323 }
325  TIMSK &= ~_BV(OCIE1A);
326 }
327 
328 # if defined(USE_TIMER_CHANNEL_B)
329 # if defined(TIMER1_COMPB_vect)
330 #define TIMER_INTR_NAME TIMER1_COMPB_vect
331 # elif defined(TIM1_COMPB_vect)
332 #define TIMER_INTR_NAME TIM1_COMPB_vect
333 # endif
334 #else
335 # if defined(TIMER1_COMPA_vect)
336 #define TIMER_INTR_NAME TIMER1_COMPA_vect
337 # elif defined(TIM1_COMPA_vect)
338 #define TIMER_INTR_NAME TIM1_COMPA_vect
339 # endif
340 # endif
341 
342 void timerConfigForReceive() {
343  TCCR1A = 0;
344  TCCR1B = _BV(WGM12) | _BV(CS10); // CTC mode, no prescaling
345  OCR1A = (F_CPU * MICROS_PER_TICK) / MICROS_IN_ONE_SECOND; // 16 * 50 = 800
346  TCNT1 = 0;
347 }
348 
349 # if defined(SEND_PWM_BY_TIMER)
350 // Set IR_SEND_PIN depending on CPU
351 # if defined(CORE_OC1A_PIN)
352 #define IR_SEND_PIN CORE_OC1A_PIN // Teensy
353 
354 # elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
355 #define IR_SEND_PIN 11 // Arduino Mega
356 
357 // MightyCore, MegaCore, MajorCore
358 # elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) \
359 || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) \
360 || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) \
361 || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega164A__) \
362 || defined(__AVR_ATmega164P__) || defined(__AVR_ATmega32__) \
363 || defined(__AVR_ATmega16__) || defined(__AVR_ATmega8535__) \
364 || defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) \
365 || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__) \
366 || defined(__AVR_ATmega8515__) || defined(__AVR_ATmega162__)
367 #define IR_SEND_PIN 13
368 
369 # elif defined(__AVR_ATtiny84__)
370 #define IR_SEND_PIN 6
371 
372 # elif defined(__AVR_ATtiny88__)
373 #define IR_SEND_PIN 8
374 
375 # elif defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
376 /*
377  * !!! IR_SEND_PIN value must correspond to ENABLE_SEND_PWM_BY_TIMER below !!!
378  */
379 # if defined(USE_TIMER_CHANNEL_B)
380 #define IR_SEND_PIN PIN_PB1 // OC1BU / PB1 / Pin9 at ATTinyCore
381 //#define IR_SEND_PIN PIN_PB3 // OC1BV / PB3 / Pin11 at ATTinyCore
382 //#define IR_SEND_PIN PIN_PB5 // OC1BW / PB5 / Pin13 at ATTinyCore
383 //#define IR_SEND_PIN PIN_PB7 // OC1BX / PB7 / Pin15 at ATTinyCore
384 # else
385 #define IR_SEND_PIN PIN_PB0 // OC1AU / PB1 / Pin8 at ATTinyCore
386 //#define IR_SEND_PIN PIN_PB2 // OC1AV / PB3 / Pin10 at ATTinyCore
387 //#define IR_SEND_PIN PIN_PB4 // OC1AW / PB5 / Pin12 at ATTinyCore
388 //#define IR_SEND_PIN PIN_PB6 // OC1AX / PB6 / Pin14 at ATTinyCore
389 # endif
390 
391 # else // defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
392 #define IR_SEND_PIN 9 // OC1A Arduino Duemilanove, Diecimila, LilyPad, Sparkfun Pro Micro, Leonardo, MH-ET Tiny88 etc.
393 # endif // Set IR_SEND_PIN depending on CPU
394 
395 # if defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
396 // Clear OC1A/OC1B on Compare Match when up-counting. Set OC1A/OC1B on Compare Match when down counting.
397 # if defined(USE_TIMER_CHANNEL_B)
398 void enableSendPWMByTimer() {
399  TCNT1 = 0;
400  TCCR1A |= _BV(COM1B1);
401  TCCR1D |= _BV(OC1BU); // + enable OC1BU as output
402  //TCNT1 = 0; TCCR1A |= _BV(COM1B1); TCCR1D |= _BV(OC1BV); // + enable OC1BV as output
403  //TCNT1 = 0; TCCR1A |= _BV(COM1B1); TCCR1D |= _BV(OC1BW); // + enable OC1BW as output
404  //TCNT1 = 0; TCCR1A |= _BV(COM1B1); TCCR1D |= _BV(OC1BX); // + enable OC1BX as output
405 }
406 # else
407 void enableSendPWMByTimer() {
408  TCNT1 = 0;
409  TCCR1A |= _BV(COM1A1);
410  TCCR1D |= _BV(OC1AU); // + enable OC1AU as output
411  //TCNT1 = 0; TCCR1A |= _BV(COM1A1); TCCR1D |= _BV(OC1AV); // + enable OC1BV as output
412  //TCNT1 = 0; TCCR1A |= _BV(COM1A1); TCCR1D |= _BV(OC1AW); // + enable OC1BW as output
413  //TCNT1 = 0; TCCR1A |= _BV(COM1A1); TCCR1D |= _BV(OC1AX); // + enable OC1BX as output
414 }
415 # endif // defined(USE_TIMER_CHANNEL_B)
416 
417 void disableSendPWMByTimer() {
418  TCCR1D = 0;
419 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
420 # if defined(IR_SEND_PIN)
422 # else
423  if (__builtin_constant_p(sendPin)) {
424  digitalWriteFast(sendPin, HIGH);
425  } else {
426  digitalWrite(sendPin, HIGH);
427  }
428 # endif // defined(IR_SEND_PIN)
429 # endif // defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
430 }
431 # else // defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
432 # if defined(USE_TIMER_CHANNEL_B)
433 void enableSendPWMByTimer() {
434  TCNT1 = 0;
435  TCCR1A |= _BV(COM1B1); // Clear OC1A/OC1B on Compare Match when up-counting. Set OC1A/OC1B on Compare Match when counting down.
436 }
437 void disableSendPWMByTimer() {
438  TCCR1A &= ~(_BV(COM1B1));
439 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
440 # if defined(IR_SEND_PIN)
442 # else
443  if (__builtin_constant_p(sendPin)) {
444  digitalWriteFast(sendPin, HIGH);
445  } else {
446  digitalWrite(sendPin, HIGH);
447  }
448 # endif // defined(IR_SEND_PIN)
449 # endif // defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
450 }
451 # else // defined(USE_TIMER_CHANNEL_B)
452 void enableSendPWMByTimer() {
453  TCNT1 = 0;
454  TCCR1A |= _BV(COM1A1); // Clear OC1A/OC1B on Compare Match when up-counting. Set OC1A/OC1B on Compare Match when downcounting.
455 }
456 void disableSendPWMByTimer() {
457  TCCR1A &= ~(_BV(COM1A1));
458 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
459 # if defined(IR_SEND_PIN)
461 # else
462  if (__builtin_constant_p(sendPin)) {
463  digitalWriteFast(sendPin, HIGH);
464  } else {
465  digitalWrite(sendPin, HIGH);
466  }
467 # endif // defined(IR_SEND_PIN)
468 # endif // defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
469 }
470 # endif // defined(USE_TIMER_CHANNEL_B)
471 
472 # endif // defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
473 
474 /*
475  * timerConfigForSend() is used exclusively by IRsend::enableIROut()
476  * Set output pin mode and disable receive interrupt if it uses the same resource
477  */
478 void timerConfigForSend(uint16_t aFrequencyKHz) {
480 
481 # if (((F_CPU / 2000) / 38) < 256)
482  const uint16_t tPWMWrapValue = (F_CPU / 2000) / (aFrequencyKHz); // 210,52 for 38 kHz @16 MHz clock, 2000 instead of 1000 because of Phase Correct PWM
483  TCCR1A = _BV(WGM11); // PWM, Phase Correct, Top is ICR1
484  TCCR1B = _BV(WGM13) | _BV(CS10); // CS10 -> no prescaling
485  ICR1 = tPWMWrapValue - 1;
486 # if defined(USE_TIMER_CHANNEL_B)
487  OCR1B = ((tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH) / 100) - 1;
488 # else
489  OCR1A = ((tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH) / 100) - 1;
490 # endif
491  TCNT1 = 0; // not really required, since we have an 8 bit counter, but makes the signal more reproducible
492 # else
493  const uint16_t tPWMWrapValue = ((F_CPU / 8) / 2000) / (aFrequencyKHz); // 2000 instead of 1000 because of Phase Correct PWM
494  TCCR1A = _BV(WGM11);// PWM, Phase Correct, Top is ICR1
495  TCCR1B = _BV(WGM13) | _BV(CS11);// CS11 -> Prescaling by 8
496  ICR1 = tPWMWrapValue - 1;
497 # if defined(USE_TIMER_CHANNEL_B)
498  OCR1A = ((tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH) / 100) - 1;
499 # else
500  OCR1A = ((tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH) / 100) - 1;
501 # endif
502  TCNT1 = 0; // not really required, since we have an 8 bit counter, but makes the signal more reproducible
503 # endif // if (((F_CPU / 2000) / 38) < 256)
504 }
505 # endif // defined(SEND_PWM_BY_TIMER) - Timer1
506 
507 /*
508  * AVR Timer2 (8 bits) // Tone timer on Uno
509  */
510 #elif defined(IR_USE_AVR_TIMER2)
511 
513  TIMSK2 = _BV(OCIE2B); // Output Compare Match A Interrupt Enable
514 }
516  TIMSK2 = 0;
517 }
518 #define TIMER_INTR_NAME TIMER2_COMPB_vect // We use TIMER2_COMPB_vect to be compatible with tone() library
519 #define TIMER_COUNT_TOP (F_CPU * MICROS_PER_TICK / MICROS_IN_ONE_SECOND)
520 
521 void timerConfigForReceive() {
522 # if (TIMER_COUNT_TOP < 256)
523  TCCR2A = _BV(WGM21);
524  TCCR2B = _BV(CS20);
525  OCR2A = TIMER_COUNT_TOP;
526  OCR2B = TIMER_COUNT_TOP;
527  TCNT2 = 0;
528 # else
529  TCCR2A = _BV(WGM21);
530  TCCR2B = _BV(CS21);
531  OCR2A = TIMER_COUNT_TOP / 8;
532  OCR2B = TIMER_COUNT_TOP / 8;
533  TCNT2 = 0;
534 # endif
535 }
536 
537 # if defined(SEND_PWM_BY_TIMER)
538 // Set IR_SEND_PIN depending on CPU
539 # if defined(CORE_OC2B_PIN)
540 #define IR_SEND_PIN CORE_OC2B_PIN // Teensy
541 
542 # elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
543 #define IR_SEND_PIN 9 // Arduino Mega
544 
545 # elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) \
546 || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) \
547 || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) \
548 || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega164A__) \
549 || defined(__AVR_ATmega164P__)
550 #define IR_SEND_PIN 14 // MightyCore, MegaCore
551 
552 # else
553 /*
554  * Using pin 11 / PB3 / OC2A for this purpose is NOT possible, since we need a PWM with a selectable frequency.
555  * This is only possible by using Phase Correct with Top as OCR2A.
556  * Thus the OCR2A register cannot be used for comparing for channel A and TOP with OCR2B is not supported by Hardware :-(.
557  */
558 #define IR_SEND_PIN 3 // Arduino Uno Pin PD3, Duemilanove, Diecimila, LilyPad, etc
559 # endif // Set IR_SEND_PIN depending on CPU
560 
561 void enableSendPWMByTimer() {
562  TCNT2 = 0;
563  TCCR2A |= _BV(COM2B1); // Clear OC2B on Compare Match
564 }
565 void disableSendPWMByTimer() {
566  TCCR2A &= ~(_BV(COM2B1)); // Normal port operation, OC2B disconnected.
567 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
568 # if defined(IR_SEND_PIN)
570 # else
571  if (__builtin_constant_p(sendPin)) {
572  digitalWriteFast(sendPin, HIGH);
573  } else {
574  digitalWrite(sendPin, HIGH);
575  }
576 # endif // defined(IR_SEND_PIN)
577 # endif // defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
578 }
579 
580 /*
581  * timerConfigForSend() is used exclusively by IRsend::enableIROut()
582  * Set output pin mode and disable receive interrupt if it uses the same resource
583  */
584 void timerConfigForSend(uint16_t aFrequencyKHz) {
586 
587 # if (((F_CPU / 2000) / 38) < 256)
588  /*
589  * tPWMWrapValue is 210.52 for 38 kHz, 17.58 for 455 kHz @16 MHz clock.
590  * 210 -> 38.095 kHz, 17 -> 470.588 kHz @16 MHz clock.
591  * We use 2000 instead of 1000 in the formula, because of Phase Correct PWM.
592  */
593  const uint16_t tPWMWrapValue = (F_CPU / 2000) / (aFrequencyKHz);
594  TCCR2A = _BV(WGM20); // PWM, Phase Correct, Top is OCR2A
595  TCCR2B = _BV(WGM22) | _BV(CS20); // CS20 -> no prescaling
596  OCR2A = tPWMWrapValue - 1; // The top value for the timer. The modulation frequency will be F_CPU / 2 / (OCR2A + 1).
597  OCR2B = ((tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH) / 100) - 1;
598  TCNT2 = 0; // not really required, since we have an 8 bit counter, but makes the signal more reproducible
599 # else
600  const uint16_t tPWMWrapValue = ((F_CPU / 8) / 2000) / (aFrequencyKHz); // 2000 instead of 1000 because of Phase Correct PWM
601  TCCR2A = _BV(WGM20);// PWM, Phase Correct, Top is OCR2A
602  TCCR2B = _BV(WGM22) | _BV(CS21);// CS21 -> Prescaling by 8
603  OCR2A = tPWMWrapValue - 1;
604  OCR2B = ((tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH) / 100) - 1;
605  TCNT2 = 0;// not really required, since we have an 8 bit counter, but makes the signal more reproducible
606 # endif
607 }
608 # endif // defined(SEND_PWM_BY_TIMER)
609 
610 /*
611  * AVR Timer3 (16 bits)
612  */
613 #elif defined(IR_USE_AVR_TIMER3)
614 
616  TIMSK3 = _BV(OCIE3B);
617 }
619  TIMSK3 = 0;
620 }
621 #define TIMER_INTR_NAME TIMER3_COMPB_vect
622 
623 void timerConfigForReceive() {
624  TCCR3A = 0;
625  TCCR3B = _BV(WGM32) | _BV(CS30);
626  OCR3A = F_CPU * MICROS_PER_TICK / MICROS_IN_ONE_SECOND;
627  OCR3B = F_CPU * MICROS_PER_TICK / MICROS_IN_ONE_SECOND;
628  TCNT3 = 0;
629 }
630 
631 # if defined(SEND_PWM_BY_TIMER)
632 // Set IR_SEND_PIN depending on CPU
633 # if defined(CORE_OC3A_PIN)
634 #define IR_SEND_PIN CORE_OC3A_PIN // Teensy
635 
636 # elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) \
637 || defined(__AVR_ATmega32U4__) || defined(ARDUINO_AVR_PROMICRO)
638 #define IR_SEND_PIN 5 // Arduino Mega, Arduino Leonardo, Sparkfun Pro Micro
639 
640 # elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
641 #define IR_SEND_PIN 6 // MightyCore, MegaCore
642 
643 # else
644 #error Please add OC3A pin number here
645 # endif // Set IR_SEND_PIN depending on CPU
646 
647 void enableSendPWMByTimer() {
648  TCNT3 = 0;
649  TCCR3A |= _BV(COM3A1);
650 }
651 void disableSendPWMByTimer() {
652  TCCR3A &= ~(_BV(COM3A1));
653 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
654 # if defined(IR_SEND_PIN)
656 # else
657  if (__builtin_constant_p(sendPin)) {
658  digitalWriteFast(sendPin, HIGH);
659  } else {
660  digitalWrite(sendPin, HIGH);
661  }
662 # endif // defined(IR_SEND_PIN)
663 # endif // defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
664 }
665 
666 /*
667  * timerConfigForSend() is used exclusively by IRsend::enableIROut()
668  * Set output pin mode and disable receive interrupt if it uses the same resource
669  */
670 void timerConfigForSend(uint16_t aFrequencyKHz) {
671 # if F_CPU > 16000000
672 #error "Creating timer PWM with timer 3 is not supported for F_CPU > 16 MHz"
673 # endif
675 
676  const uint16_t tPWMWrapValue = (F_CPU / 2000) / (aFrequencyKHz); // 210,52 for 38 kHz @16 MHz clock, 2000 instead of 1000 because of Phase Correct PWM
677  TCCR3A = _BV(WGM31);
678  TCCR3B = _BV(WGM33) | _BV(CS30); // PWM, Phase Correct, ICRn as TOP, complete period is double of tPWMWrapValue
679  ICR3 = tPWMWrapValue - 1;
680  OCR3A = ((tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH) / 100) - 1;
681  TCNT3 = 0; // required, since we have an 16 bit counter
682 }
683 # endif // defined(SEND_PWM_BY_TIMER)
684 
685 /*
686  * AVR Timer4 (16 bits)
687  */
688 #elif defined(IR_USE_AVR_TIMER4)
690  TIMSK4 = _BV(OCIE4A);
691 }
693  TIMSK4 = 0;
694 }
695 #define TIMER_INTR_NAME TIMER4_COMPA_vect
696 
697 void timerConfigForReceive() {
698  TCCR4A = 0;
699  TCCR4B = _BV(WGM42) | _BV(CS40);
700  OCR4A = F_CPU * MICROS_PER_TICK / MICROS_IN_ONE_SECOND;
701  TCNT4 = 0;
702 }
703 
704 # if defined(SEND_PWM_BY_TIMER)
705 // Set IR_SEND_PIN depending on CPU
706 # if defined(CORE_OC4A_PIN)
707 #define IR_SEND_PIN CORE_OC4A_PIN
708 # elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
709 #define IR_SEND_PIN 6 // Arduino Mega
710 # else
711 #error Please add OC4A pin number here
712 # endif
713 
714 void enableSendPWMByTimer() {
715  TCNT4 = 0;
716  TCCR4A |= _BV(COM4A1);
717 }
718 void disableSendPWMByTimer() {
719  TCCR4A &= ~(_BV(COM4A1));
720 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
721 # if defined(IR_SEND_PIN)
723 # else
724  if (__builtin_constant_p(sendPin)) {
725  digitalWriteFast(sendPin, HIGH);
726  } else {
727  digitalWrite(sendPin, HIGH);
728  }
729 # endif // defined(IR_SEND_PIN)
730 # endif // defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
731 }
732 
733 void timerConfigForSend(uint16_t aFrequencyKHz) {
734 # if F_CPU > 16000000
735 #error "Creating timer PWM with timer 4 is not supported for F_CPU > 16 MHz"
736 # endif
738  const uint16_t tPWMWrapValue = (F_CPU / 2000) / (aFrequencyKHz); // 210,52 for 38 kHz @16 MHz clock, 2000 instead of 1000 because of Phase Correct PWM
739  TCCR4A = _BV(WGM41);
740  TCCR4B = _BV(WGM43) | _BV(CS40);
741  ICR4 = tPWMWrapValue - 1;
742  OCR4A = ((tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH) / 100) - 1;
743  TCNT4 = 0; // required, since we have an 16 bit counter
744 }
745 # endif // defined(SEND_PWM_BY_TIMER)
746 
747 /*
748  * AVR Timer4 (10 bits, high speed option)
749  */
750 #elif defined(IR_USE_AVR_TIMER4_HS)
751 
753  TIMSK4 = _BV(TOIE4);
754 }
756  TIMSK4 = 0;
757 }
758 #define TIMER_INTR_NAME TIMER4_OVF_vect
759 
760 void timerConfigForReceive() {
761  TCCR4A = 0;
762  TCCR4B = _BV(CS40);
763  TCCR4C = 0;
764  TCCR4D = 0;
765  TCCR4E = 0;
766  TC4H = (F_CPU * MICROS_PER_TICK / MICROS_IN_ONE_SECOND) >> 8;
767  OCR4C = (F_CPU * MICROS_PER_TICK / MICROS_IN_ONE_SECOND) & 255;
768  TC4H = 0;
769  TCNT4 = 0;
770 }
771 
772 # if defined(SEND_PWM_BY_TIMER)
773 # if defined(CORE_OC4A_PIN)
774 #define IR_SEND_PIN CORE_OC4A_PIN // Teensy 2.0
775 # elif defined(ARDUINO_AVR_PROMICRO)
776 #define IR_SEND_PIN 5 // Sparkfun Pro Micro
777 # elif defined(__AVR_ATmega32U4__)
778 #define IR_SEND_PIN 13 // Leonardo
779 # else
780 #error Please add OC4A pin number here
781 # endif
782 
783 # if defined(ARDUINO_AVR_PROMICRO) // Sparkfun Pro Micro
784 void enableSendPWMByTimer() {
785  TCNT4 = 0;
786  TCCR4A |= _BV(COM4A0); // Use complementary OC4A output on pin 5
787 }
788 void disableSendPWMByTimer() {
789  TCCR4A &= ~(_BV(COM4A0)); // (Pro Micro does not map PC7 (32/ICP3/CLK0/OC4A)
790 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
791 # if defined(IR_SEND_PIN)
793 # else
794  if (__builtin_constant_p(sendPin)) {
795  digitalWriteFast(sendPin, HIGH);
796  } else {
797  digitalWrite(sendPin, HIGH);
798  }
799 # endif // defined(IR_SEND_PIN)
800 # endif // defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
801 }
802 // of ATmega32U4 )
803 # else
804 void enableSendPWMByTimer() {
805  TCNT4 = 0;
806  TCCR4A |= _BV(COM4A1);
807  DDRC |= 1 << 7;
808 }
809 void disableSendPWMByTimer() {
810  TCCR4A &= ~(_BV(COM4A1));
811 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
812 # if defined(IR_SEND_PIN)
814 # else
815  if (__builtin_constant_p(sendPin)) {
816  digitalWriteFast(sendPin, HIGH);
817  } else {
818  digitalWrite(sendPin, HIGH);
819  }
820 # endif // defined(IR_SEND_PIN)
821 # endif // defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
822 }
823 # endif
824 
825 /*
826  * timerConfigForSend() is used exclusively by IRsend::enableIROut()
827  * Set output pin mode and disable receive interrupt if it uses the same resource
828  */
829 void timerConfigForSend(uint16_t aFrequencyKHz) {
830 #if F_CPU > 16000000
831 #error "Creating timer PWM with timer 4 HS is not supported for F_CPU > 16 MHz"
832 #endif
834 
835  const uint16_t tPWMWrapValue = ((F_CPU / 2000) / (aFrequencyKHz)) - 1; // 210,52 for 38 kHz @16 MHz clock, 2000 instead of 1000 because of Phase Correct PWM
836  TCCR4A = (1 << PWM4A);
837  TCCR4B = _BV(CS40);
838  TCCR4C = 0;
839  TCCR4D = (1 << WGM40);
840  TCCR4E = 0;
841  TC4H = tPWMWrapValue >> 8;
842  OCR4C = tPWMWrapValue;
843  TC4H = (tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH / 100) >> 8;
844  OCR4A = (tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH / 100) & 255;
845  TCNT4 = 0; // not really required, since we have an 8 bit counter, but makes the signal more reproducible
846 }
847 # endif // defined(SEND_PWM_BY_TIMER)
848 
849 /*
850  * AVR Timer5 (16 bits)
851  */
852 #elif defined(IR_USE_AVR_TIMER5)
853 
855  TIMSK5 = _BV(OCIE5A);
856 }
858  TIMSK5 = 0;
859 }
860 #define TIMER_INTR_NAME TIMER5_COMPA_vect
861 
862 void timerConfigForReceive() {
863  TCCR5A = 0;
864  TCCR5B = _BV(WGM52) | _BV(CS50);
865  OCR5A = F_CPU * MICROS_PER_TICK / MICROS_IN_ONE_SECOND;
866  TCNT5 = 0;
867 }
868 
869 # if defined(SEND_PWM_BY_TIMER)
870 # if defined(CORE_OC5A_PIN)
871 #define IR_SEND_PIN CORE_OC5A_PIN
872 # elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
873 #define IR_SEND_PIN 46 // Arduino Mega
874 # else
875 #error Please add OC5A pin number here
876 # endif
877 
878 void enableSendPWMByTimer() {
879  TCNT5 = 0;
880  TCCR5A |= _BV(COM5A1);
881 }
882 void disableSendPWMByTimer() {
883  TCCR5A &= ~(_BV(COM5A1));
884 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
885 # if defined(IR_SEND_PIN)
887 # else
888  if (__builtin_constant_p(sendPin)) {
889  digitalWriteFast(sendPin, HIGH);
890  } else {
891  digitalWrite(sendPin, HIGH);
892  }
893 # endif // defined(IR_SEND_PIN)
894 # endif // defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
895 }
896 
897 /*
898  * timerConfigForSend() is used exclusively by IRsend::enableIROut()
899  * Set output pin mode and disable receive interrupt if it uses the same resource
900  */
901 void timerConfigForSend(uint16_t aFrequencyKHz) {
902 #if F_CPU > 16000000
903 #error "Creating timer PWM with timer 5 is not supported for F_CPU > 16 MHz"
904 #endif
906 
907  const uint16_t tPWMWrapValue = (F_CPU / 2000) / (aFrequencyKHz); // 210,52 for 38 kHz @16 MHz clock, 2000 instead of 1000 because of Phase Correct PWM
908  TCCR5A = _BV(WGM51);
909  TCCR5B = _BV(WGM53) | _BV(CS50);
910  ICR5 = tPWMWrapValue - 1;
911  OCR5A = ((tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH) / 100) - 1;
912  TCNT5 = 0; // required, since we have an 16 bit counter
913 }
914 # endif // defined(SEND_PWM_BY_TIMER)
915 
916 /*
917  * AVR Timer0 for ATtinies (8 bits)
918  */
919 #elif defined(IR_USE_AVR_TIMER_TINY0)
920 
922  TIMSK |= _BV(OCIE0A);
923 }
925  TIMSK &= ~(_BV(OCIE0A));
926 }
927 #define TIMER_INTR_NAME TIMER0_COMPA_vect
928 
929 #define TIMER_COUNT_TOP (F_CPU * MICROS_PER_TICK / MICROS_IN_ONE_SECOND)
930 
931 void timerConfigForReceive() {
932 # if (TIMER_COUNT_TOP < 256)
933  TCCR0A = _BV(WGM01); // CTC, Top is OCR0A
934  TCCR0B = _BV(CS00);// No prescaling
935  OCR0A = TIMER_COUNT_TOP;
936  TCNT0 = 0;
937 # else
938  TCCR0A = _BV(WGM01);
939  TCCR0B = _BV(CS01); // prescaling by 8
940  OCR0A = TIMER_COUNT_TOP / 8;
941  TCNT0 = 0;
942 # endif
943 }
944 
945 # if defined(SEND_PWM_BY_TIMER)
946 #define IR_SEND_PIN 1
947 
948 void enableSendPWMByTimer() {
949  TCNT0 = 0;
950  TCCR0A |= _BV(COM0B1);
951 }
952 void disableSendPWMByTimer() {
953  TCCR0A &= ~(_BV(COM0B1));
954 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
955 # if defined(IR_SEND_PIN)
957 # else
958  if (__builtin_constant_p(sendPin)) {
959  digitalWriteFast(sendPin, HIGH);
960  } else {
961  digitalWrite(sendPin, HIGH);
962  }
963 # endif // defined(IR_SEND_PIN)
964 # endif // defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
965 }
966 
967 /*
968  * timerConfigForSend() is used exclusively by IRsend::enableIROut()
969  * Set output pin mode and disable receive interrupt if it uses the same resource
970  */
971 void timerConfigForSend(uint16_t aFrequencyKHz) {
972 # if F_CPU > 16000000
973 #error "Creating timer PWM with timer TINY0 is not supported for F_CPU > 16 MHz"
974 # endif
976 
977  const uint16_t tPWMWrapValue = (F_CPU / 2000) / (aFrequencyKHz); // 210,52 for 38 kHz @16 MHz clock, 2000 instead of 1000 because of Phase Correct PWM
978  TCCR0A = _BV(WGM00); // PWM, Phase Correct, Top is OCR0A
979  TCCR0B = _BV(WGM02) | _BV(CS00); // CS00 -> no prescaling
980  OCR0A = tPWMWrapValue - 1;
981  OCR0B = ((tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH) / 100) - 1;
982  TCNT0 = 0; // not really required, since we have an 8 bit counter, but makes the signal more reproducible
983 }
984 # endif // defined(SEND_PWM_BY_TIMER)
985 
986 /*
987  * AVR Timer1 for ATtinies (8 bits)
988  */
989 #elif defined(IR_USE_AVR_TIMER_TINY1)
990 
992  TIMSK |= _BV(OCIE1B);
993 }
995  TIMSK &= ~(_BV(OCIE1B));
996 }
997 #define TIMER_INTR_NAME TIMER1_COMPB_vect
998 
999 #define TIMER_COUNT_TOP (F_CPU * MICROS_PER_TICK / MICROS_IN_ONE_SECOND)
1000 
1001 void timerConfigForReceive() {
1002 # if (TIMER_COUNT_TOP < 256)
1003  TCCR1 = _BV(CTC1) | _BV(CS10); // Clear Timer/Counter on Compare Match, Top is OCR1C, No prescaling
1004  GTCCR = 0;// normal, non-PWM mode
1005  OCR1C = TIMER_COUNT_TOP;
1006  TCNT1 = 0;
1007 # else
1008  TCCR1 = _BV(CTC1) | _BV(CS12); // Clear Timer/Counter on Compare Match, Top is OCR1C, prescaling by 8
1009  GTCCR = 0; // normal, non-PWM mode
1010  OCR1C = TIMER_COUNT_TOP / 8;
1011  TCNT1 = 0;
1012 # endif
1013 }
1014 
1015 # if defined(SEND_PWM_BY_TIMER)
1016 #define IR_SEND_PIN 4
1017 
1018 void enableSendPWMByTimer() {
1019  TCNT1 = 0;
1020  GTCCR |= _BV(PWM1B) | _BV(COM1B0); // Enable pin 4 PWM output (PB4 - Arduino D4)
1021 }
1022 void disableSendPWMByTimer() {
1023  GTCCR &= ~(_BV(PWM1B) | _BV(COM1B0));
1024 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
1025 # if defined(IR_SEND_PIN)
1027 # else
1028  if (__builtin_constant_p(sendPin)) {
1029  digitalWriteFast(sendPin, HIGH);
1030  } else {
1031  digitalWrite(sendPin, HIGH);
1032  }
1033 # endif // defined(IR_SEND_PIN)
1034 # endif // defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
1035 }
1036 
1037 /*
1038  * timerConfigForSend() is used exclusively by IRsend::enableIROut()
1039  * Set output pin mode and disable receive interrupt if it uses the same resource
1040  */
1041 void timerConfigForSend(uint16_t aFrequencyKHz) {
1043 
1044 # if (((F_CPU / 1000) / 38) < 256)
1045  const uint16_t tPWMWrapValue = (F_CPU / 1000) / (aFrequencyKHz); // 421 @16 MHz, 26 @1 MHz and 38 kHz
1046  TCCR1 = _BV(CTC1) | _BV(CS10);// CTC1 = 1: TOP value set to OCR1C, CS10 No Prescaling
1047  OCR1C = tPWMWrapValue - 1;
1048  OCR1B = ((tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH) / 100) - 1;
1049  TCNT1 = 0;// not really required, since we have an 8 bit counter, but makes the signal more reproducible
1050  GTCCR = _BV(PWM1B) | _BV(COM1B0);// PWM1B = 1: Enable PWM for OCR1B, COM1B0 Clear on compare match
1051 # else
1052  const uint16_t tPWMWrapValue = ((F_CPU / 2) / 1000) / (aFrequencyKHz); // 210 for 16 MHz and 38 kHz
1053  TCCR1 = _BV(CTC1) | _BV(CS11); // CTC1 = 1: TOP value set to OCR1C, CS11 Prescaling by 2
1054  OCR1C = tPWMWrapValue - 1;
1055  OCR1B = ((tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH) / 100) - 1;
1056  TCNT1 = 0; // not really required, since we have an 8 bit counter, but makes the signal more reproducible
1057  GTCCR = _BV(PWM1B) | _BV(COM1B0); // PWM1B = 1: Enable PWM for OCR1B, COM1B0 Clear on compare match
1058 # endif
1059 }
1060 # endif // defined(SEND_PWM_BY_TIMER)
1061 
1062 /*
1063  * AVR TimerA for TinyCore 32 (16 bits)
1064  */
1065 #elif defined(IR_USE_AVR_TIMER_A)
1066 #define TIMER_REQUIRES_RESET_INTR_PENDING
1068  TCA0.SINGLE.INTFLAGS = TCA_SINGLE_OVF_bm;
1069 }
1071  TCA0.SINGLE.INTCTRL = TCA_SINGLE_OVF_bm;
1072 }
1074  TCA0.SINGLE.INTCTRL &= ~(TCA_SINGLE_OVF_bm);
1075 }
1076 #define TIMER_INTR_NAME TCA0_OVF_vect
1077 // For MegaTinyCore:
1078 // TCB1 is used by Tone()
1079 // TCB2 is used by Servo, but we cannot hijack the ISR, so we must use a dedicated timer for the 20 ms interrupt
1080 // TCB3 is used by millis()
1081 // Must use TCA0, since TCBx have only prescaler %2. Use single (16bit) mode, because it seems to be easier :-)
1082 void timerConfigForReceive() {
1083  TCA0.SINGLE.CTRLD = 0; // Single mode - required at least for MegaTinyCore
1084  TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_NORMAL_gc; // Normal mode, top = PER
1085  TCA0.SINGLE.PER = (F_CPU / MICROS_IN_ONE_SECOND) * MICROS_PER_TICK; // 800 at 16 MHz
1086  TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; // set prescaler to 1 and enable timer
1087 }
1088 
1089 # if defined(SEND_PWM_BY_TIMER)
1090 #error "No support for hardware PWM generation for ATtiny3216/17 etc."
1091 # endif // defined(SEND_PWM_BY_TIMER)
1092 
1093 /*
1094  * AVR TimerB (8 bits) for ATmega4809 (Nano Every, Uno WiFi Rev2)
1095  */
1096 #elif defined(IR_USE_AVR_TIMER_B)
1097 
1098 // ATmega4809 TCB0
1099 #define TIMER_REQUIRES_RESET_INTR_PENDING
1101  TCB0.INTFLAGS = TCB_CAPT_bm;
1102 }
1104  TCB0.INTCTRL = TCB_CAPT_bm;
1105 }
1107  TCB0.INTCTRL &= ~(TCB_CAPT_bm);
1108 }
1109 #define TIMER_INTR_NAME TCB0_INT_vect
1110 
1111 void timerConfigForReceive() {
1112  TCB0.CTRLB = (TCB_CNTMODE_INT_gc); // Periodic interrupt mode
1113  TCB0.CCMP = ((F_CPU * MICROS_PER_TICK) / MICROS_IN_ONE_SECOND);
1114  TCB0.INTFLAGS = TCB_CAPT_bm; // reset interrupt flags
1115  TCB0.CTRLA = (TCB_CLKSEL_CLKDIV1_gc) | (TCB_ENABLE_bm);
1116 }
1117 
1118 # if defined(SEND_PWM_BY_TIMER)
1119 # if defined(__AVR_ATmega4808__) || defined(__AVR_ATmega4809__)
1120 #define IR_SEND_PIN 6 // PF4 on ATmega4809 / Nano Every (see pins_arduino.h digital_pin_to_timer)
1121 # else
1122 #error SEND_PWM_BY_TIMER not yet supported for this CPU
1123 # endif
1124 
1125 void enableSendPWMByTimer() {
1126  TCB0.CNT = 0;
1127  TCB0.CTRLB |= TCB_CCMPEN_bm; // set Compare/Capture Output Enable
1128 }
1129 void disableSendPWMByTimer() {
1130  TCB0.CTRLB &= ~(TCB_CCMPEN_bm);
1131 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
1132 # if defined(IR_SEND_PIN)
1134 # else
1135  if (__builtin_constant_p(sendPin)) {
1136  digitalWriteFast(sendPin, HIGH);
1137  } else {
1138  digitalWrite(sendPin, HIGH);
1139  }
1140 # endif // defined(IR_SEND_PIN)
1141 # endif // defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
1142 }
1143 
1144 /*
1145  * timerConfigForSend() is used exclusively by IRsend::enableIROut()
1146  * Set output pin mode and disable receive interrupt if it uses the same resource
1147  */
1148 void timerConfigForSend(uint16_t aFrequencyKHz) {
1149 #if F_CPU > 16000000
1150  // we have only prescaler 2 or must take clock of timer A (which is non deterministic)
1151 #error "Creating timer PWM with timer TCB0 is not possible for F_CPU > 16 MHz"
1152 #endif
1154 
1155  const uint16_t tPWMWrapValue = (F_CPU / 2000) / (aFrequencyKHz); // 210,52 for 38 kHz @16 MHz clock, 2000 instead of 1000 because of using CLK / 2
1156  TCB0.CTRLB = TCB_CNTMODE_PWM8_gc; // 8 bit PWM mode
1157  TCB0.CCMPL = tPWMWrapValue - 1; // Period of 8 bit PWM
1158  TCB0.CCMPH = ((tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH) / 100) - 1; // Duty cycle of waveform of 8 bit PWM
1159  TCB0.CTRLA = (TCB_CLKSEL_CLKDIV2_gc) | (TCB_ENABLE_bm); // use CLK / 2
1160  TCB0.CNT = 0; // not really required, since we have an 8 bit counter, but makes the signal more reproducible
1161 }
1162 # endif // defined(SEND_PWM_BY_TIMER)
1163 
1164 /*
1165  * AVR TimerD for TinyCore 32 (16 bits)
1166  */
1167 #elif defined(IR_USE_AVR_TIMER_D)
1168 
1169 #define TIMER_REQUIRES_RESET_INTR_PENDING
1171  TCD0.INTFLAGS = TCD_OVF_bm;
1172 }
1174  TCD0.INTCTRL = TCD_OVF_bm;
1175 }
1177  TCD0.INTCTRL = 0;
1178 }
1179 #define TIMER_INTR_NAME TCD0_OVF_vect
1180 
1181 void timerConfigForReceive() {
1182  TCD0.CTRLA = 0; // reset enable bit in order to unprotect the other bits
1183  TCD0.CTRLB = TCD_WGMODE_ONERAMP_gc; // must be set since it is used by PWM
1184 // TCD0.CMPBSET = 80;
1185  TCD0.CMPBCLR = ((F_CPU * MICROS_PER_TICK) / MICROS_IN_ONE_SECOND) - 1;
1186 
1187  _PROTECTED_WRITE(TCD0.FAULTCTRL, 0); // must disable WOA output at pin 13/PA4
1188 
1189  TCD0.INTFLAGS = TCD_OVF_bm; // reset interrupt flags
1190  // check enable ready
1191 // while ((TCD0.STATUS & TCD_ENRDY_bm) == 0); // Wait for Enable Ready to be high - I guess it is not required
1192  // enable timer - this locks the other bits and static registers and activates values in double buffered registers
1193  TCD0.CTRLA = TCD_ENABLE_bm | TCD_CLKSEL_SYSCLK_gc | TCD_CNTPRES_DIV1_gc; // System clock, no prescale, no synchronization prescaler
1194 }
1195 
1196 # if defined(SEND_PWM_BY_TIMER)
1197 #define IR_SEND_PIN 13
1198 
1199 void timerEnableSendPWM() {
1200  TCD0.CTRLA = 0; // reset enable bit in order to unprotect the other bits
1201  _PROTECTED_WRITE(TCD0.FAULTCTRL, FUSE_CMPAEN_bm); // enable WOA output at pin 13/PA4
1202 // _PROTECTED_WRITE(TCD0.FAULTCTRL, FUSE_CMPAEN_bm | FUSE_CMPBEN_bm); // enable WOA + WOB output pins at 13/PA4 + 14/PA5
1203  TCD0.CTRLA = TCD_ENABLE_bm | TCD_CLKSEL_SYSCLK_gc | TCD_CNTPRES_DIV1_gc; // System clock, no prescale, no synchronization prescaler
1204 }
1205 
1206 void enableSendPWMByTimer() {
1207  timerEnableSendPWM();
1208 }
1209 void disableSendPWMByTimer() {
1210  TCD0.CTRLA = 0; // do not disable output, disable complete timer
1211 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
1212 # if defined(IR_SEND_PIN)
1214 # else
1215  if (__builtin_constant_p(sendPin)) {
1216  digitalWriteFast(sendPin, HIGH);
1217  } else {
1218  digitalWrite(sendPin, HIGH);
1219  }
1220 # endif // defined(IR_SEND_PIN)
1221 # endif // defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
1222 }
1223 
1224 /*
1225  * timerConfigForSend() is used exclusively by IRsend::enableIROut()
1226  * Set output pin mode and disable receive interrupt if it uses the same resource
1227  */
1228 void timerConfigForSend(uint16_t aFrequencyKHz) {
1230 
1231  const uint16_t tPWMWrapValue = (F_CPU / 1000) / (aFrequencyKHz); // 526,31 for 38 kHz @20 MHz clock
1232  // use one ramp mode and overflow interrupt
1233  TCD0.CTRLA = 0; // reset enable bit in order to unprotect the other bits
1234 // while ((TCD0.STATUS & TCD_ENRDY_bm) == 0); // Wait for Enable Ready to be high - I guess it is not required
1235  TCD0.CTRLB = TCD_WGMODE_ONERAMP_gc; // must be set since it is used by PWM
1236  TCD0.CTRLC = 0; // reset WOx output settings
1237 // TCD0.CMPBSET = 80;
1238  TCD0.CMPBCLR = tPWMWrapValue - 1;
1239 
1240  // Generate duty cycle signal for debugging etc.
1241  TCD0.CMPASET = 0;
1242  TCD0.CMPACLR = (tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH / 100) - 1; // duty cycle for WOA
1243 
1244  TCD0.INTFLAGS = TCD_OVF_bm; // reset interrupt flags
1245  TCD0.INTCTRL = TCD_OVF_bm; // overflow interrupt
1246  // Do not enable timer, this is done at timerEnablSendPWM()
1247 }
1248 # endif // defined(SEND_PWM_BY_TIMER)
1249 
1250 #else
1251 #error Internal code configuration error, no timer functions implemented for this AVR CPU / board
1252 #endif //defined(IR_USE_AVR_TIMER*)
1253 /**********************************************************************************************************************
1254  * End of AVR timers
1255  **********************************************************************************************************************/
1256 
1257 /**********************************************
1258  * Uno R4 boards
1259  **********************************************/
1260 #elif defined(ARDUINO_ARCH_RENESAS)
1261 #include "FspTimer.h"
1262 FspTimer s50usTimer;
1263 
1264 // Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
1265 # if defined(ISR)
1266 #undef ISR
1267 # endif
1268 
1269 // callback method used by timer
1270 void IRTimerInterruptHandlerHelper(timer_callback_args_t __attribute((unused)) *p_args) {
1272 }
1274 // s50usTimer.enable_overflow_irq();
1275  s50usTimer.start();
1276 }
1278 // s50usTimer.disable_overflow_irq();
1279  s50usTimer.stop(); // May save power
1280 }
1281 
1282 void timerConfigForReceive() {
1283  uint8_t tTimerType = GPT_TIMER;
1284  int8_t tIndex = FspTimer::get_available_timer(tTimerType); // Get first unused channel. Here we need the address of tTimerType
1285  if (tIndex < 0 || tTimerType != GPT_TIMER) {
1286  // here we found no unused GPT channel
1287  tIndex = FspTimer::get_available_timer(tTimerType, true); // true to force use of already used PWM channel. Sets "force_pwm_reserved" if timer found
1288  if (tIndex < 0) {
1289  // If we already get an tIndex < 0 we have an error, but do not know how to handle :-(
1290  return;
1291  }
1292  }
1293  s50usTimer.begin(TIMER_MODE_PERIODIC, tTimerType, tIndex, MICROS_IN_ONE_SECOND / MICROS_PER_TICK, 0.0,
1294  IRTimerInterruptHandlerHelper);
1295  s50usTimer.setup_overflow_irq();
1296  s50usTimer.open(); // In turn calls R_GPT_Enable()
1297  s50usTimer.stop(); // May save power
1298 }
1299 
1300 # if defined(SEND_PWM_BY_TIMER)
1301 #error PWM generation by hardware not yet implemented for Arduino Uno R4
1302 // Not yet implemented
1303 void enableSendPWMByTimer() {
1304 }
1305 void disableSendPWMByTimer() {
1306 }
1307 
1308 /*
1309  * timerConfigForSend() is used exclusively by IRsend::enableIROut()
1310  */
1311 void timerConfigForSend(uint16_t aFrequencyKHz) {
1312 # if defined(IR_SEND_PIN)
1313 # else
1314 # endif
1315 }
1316 # endif
1317 
1318 /**********************************************
1319  * Teensy 3.0 / Teensy 3.1 / Teensy 3.2 boards
1320  **********************************************/
1321 #elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
1322 
1323 // Special carrier modulator timer for Teensy 3.0 / Teensy 3.1 / Teensy 3.2
1324 #define TIMER_REQUIRES_RESET_INTR_PENDING
1326  uint8_t tmp __attribute__((unused)) = CMT_MSC;
1327  CMT_CMD2 = 30;
1328 }
1330  NVIC_ENABLE_IRQ(IRQ_CMT);
1331  NVIC_SET_PRIORITY(IRQ_CMT, 48);
1332 }
1334  NVIC_DISABLE_IRQ(IRQ_CMT);
1335 }
1336 
1337 #define TIMER_INTR_NAME cmt_isr
1338 # if defined(ISR)
1339 #undef ISR
1340 # endif
1341 #define ISR(f) void f(void)
1342 
1343 #define CMT_PPS_DIV ((F_BUS + 7999999) / 8000000)
1344 # if F_BUS < 8000000
1345 #error IRremote requires at least 8 MHz on Teensy 3.x
1346 # endif
1347 
1348 void timerConfigForReceive() {
1349  SIM_SCGC4 |= SIM_SCGC4_CMT;
1350  CMT_PPS = CMT_PPS_DIV - 1;
1351  CMT_CGH1 = 1;
1352  CMT_CGL1 = 1;
1353  CMT_CMD1 = 0;
1354  CMT_CMD2 = 30;
1355  CMT_CMD3 = 0;
1356  CMT_CMD4 = (F_BUS / 160000 + CMT_PPS_DIV / 2) / CMT_PPS_DIV - 31;
1357  CMT_OC = 0;
1358  CMT_MSC = 0x03;
1359 }
1360 
1361 # if defined(SEND_PWM_BY_TIMER)
1362 #define IR_SEND_PIN 5
1363 
1364 void enableSendPWMByTimer() {
1365  do {
1366  CORE_PIN5_CONFIG = PORT_PCR_MUX(2) | PORT_PCR_DSE | PORT_PCR_SRE;
1367  } while (0);
1368 }
1369 void disableSendPWMByTimer() {
1370  do {
1371  CORE_PIN5_CONFIG = PORT_PCR_MUX(1) | PORT_PCR_DSE | PORT_PCR_SRE;
1372  } while (0);
1373 }
1374 
1375 /*
1376  * timerConfigForSend() is used exclusively by IRsend::enableIROut()
1377  * Set output pin mode and disable receive interrupt if it uses the same resource
1378  */
1379 void timerConfigForSend(uint16_t aFrequencyKHz) {
1380  timerDisableReceiveInterrupt(); // TODO really required here? Do we have a common resource for Teensy3.0, 3.1
1381 # if defined(IR_SEND_PIN)
1382  pinMode(IR_SEND_PIN, OUTPUT);
1383 # else
1384  pinMode(IrSender.sendPin, OUTPUT);
1385 # endif
1386 
1387  SIM_SCGC4 |= SIM_SCGC4_CMT;
1388  SIM_SOPT2 |= SIM_SOPT2_PTD7PAD;
1389  CMT_PPS = CMT_PPS_DIV - 1;
1390  CMT_CGH1 = ((F_BUS / CMT_PPS_DIV / 3000) + ((aFrequencyKHz) / 2)) / (aFrequencyKHz);
1391  CMT_CGL1 = ((F_BUS / CMT_PPS_DIV / 1500) + ((aFrequencyKHz) / 2)) / (aFrequencyKHz);
1392  CMT_CMD1 = 0;
1393  CMT_CMD2 = 30;
1394  CMT_CMD3 = 0;
1395  CMT_CMD4 = 0;
1396  CMT_OC = 0x60;
1397  CMT_MSC = 0x01;
1398 }
1399 # endif // defined(SEND_PWM_BY_TIMER)
1400 
1401 /***************************************
1402  * Teensy-LC board
1403  ***************************************/
1404 #elif defined(__MKL26Z64__)
1405 
1406 // defines for TPM1 timer on Teensy-LC
1407 #define TIMER_REQUIRES_RESET_INTR_PENDING
1409  FTM1_SC |= FTM_SC_TOF;
1410 }
1412  NVIC_ENABLE_IRQ(IRQ_FTM1);
1413  NVIC_SET_PRIORITY(IRQ_FTM1, 0);
1414 }
1416  NVIC_DISABLE_IRQ(IRQ_FTM1);
1417 }
1418 #define TIMER_INTR_NAME ftm1_isr
1419 # if defined(ISR)
1420 #undef ISR
1421 # endif
1422 #define ISR(f) void f(void)
1423 
1424 void timerConfigForReceive() {
1425  SIM_SCGC6 |= SIM_SCGC6_TPM1;
1426  FTM1_SC = 0;
1427  FTM1_CNT = 0;
1428  FTM1_MOD = (F_PLL / 40000) - 1;
1429  FTM1_C0V = 0;
1430  FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0) | FTM_SC_TOF | FTM_SC_TOIE;
1431 }
1432 
1433 # if defined(SEND_PWM_BY_TIMER)
1434 #define IR_SEND_PIN 16
1435 
1436 void enableSendPWMByTimer() {
1437  FTM1_CNT = 0;
1438  CORE_PIN16_CONFIG = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE;
1439 }
1440 void disableSendPWMByTimer() {
1441  CORE_PIN16_CONFIG = PORT_PCR_MUX(1) | PORT_PCR_SRE;
1442 }
1443 
1444 /*
1445  * timerConfigForSend() is used exclusively by IRsend::enableIROut()
1446  * Set output pin mode and disable receive interrupt if it uses the same resource
1447  */
1448 void timerConfigForSend(uint16_t aFrequencyKHz) {
1450 # if defined(IR_SEND_PIN)
1451  pinMode(IR_SEND_PIN, OUTPUT);
1452 # else
1453  pinMode(IrSender.sendPin, OUTPUT);
1454 # endif
1455 
1456  SIM_SCGC6 |= SIM_SCGC6_TPM1;
1457  FTM1_SC = 0;
1458  FTM1_CNT = 0;
1459  FTM1_MOD = ((F_PLL / 2000) / aFrequencyKHz) - 1;
1460  FTM1_C0V = ((F_PLL / 6000) / aFrequencyKHz) - 1;
1461  FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_PS(0);
1462 }
1463 # endif // defined(SEND_PWM_BY_TIMER)
1464 
1465 /***************************************
1466  * Teensy 4.0, 4.1, MicroMod boards
1467  ***************************************/
1468 #elif defined(__IMXRT1062__)
1469 // forward declare ISR function (will be implemented by IRReceive.hpp)
1470 void pwm1_3_isr();
1471 
1472 // defines for FlexPWM1 timer on Teensy 4
1473 #define TIMER_REQUIRES_RESET_INTR_PENDING
1475  FLEXPWM1_SM3STS = FLEXPWM_SMSTS_RF;
1476 }
1478  attachInterruptVector(IRQ_FLEXPWM1_3, pwm1_3_isr);
1479  FLEXPWM1_SM3STS = FLEXPWM_SMSTS_RF;
1480  FLEXPWM1_SM3INTEN = FLEXPWM_SMINTEN_RIE;
1481  NVIC_ENABLE_IRQ (IRQ_FLEXPWM1_3), NVIC_SET_PRIORITY(IRQ_FLEXPWM1_3, 48);
1482 }
1484  NVIC_DISABLE_IRQ (IRQ_FLEXPWM1_3);
1485 }
1486 #define TIMER_INTR_NAME pwm1_3_isr
1487 # if defined(ISR)
1488 #undef ISR
1489 # endif
1490 #define ISR(f) void (f)(void)
1491 
1492 void timerConfigForReceive() {
1493  uint32_t period = (float) F_BUS_ACTUAL * (float) (MICROS_PER_TICK) * 0.0000005f;
1494  uint32_t prescale = 0;
1495  while (period > 32767) {
1496  period = period >> 1;
1497  if (prescale < 7)
1498  prescale++;
1499  }
1500  FLEXPWM1_FCTRL0 |= FLEXPWM_FCTRL0_FLVL(8);
1501  FLEXPWM1_FSTS0 = 0x0008;
1502  FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_CLDOK(8);
1503  FLEXPWM1_SM3CTRL2 = FLEXPWM_SMCTRL2_INDEP;
1504  FLEXPWM1_SM3CTRL = FLEXPWM_SMCTRL_HALF | FLEXPWM_SMCTRL_PRSC(prescale);
1505  FLEXPWM1_SM3INIT = -period;
1506  FLEXPWM1_SM3VAL0 = 0;
1507  FLEXPWM1_SM3VAL1 = period;
1508  FLEXPWM1_SM3VAL2 = 0;
1509  FLEXPWM1_SM3VAL3 = 0;
1510  FLEXPWM1_SM3VAL4 = 0;
1511  FLEXPWM1_SM3VAL5 = 0;
1512  FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_LDOK(8) | FLEXPWM_MCTRL_RUN(8);
1513 }
1514 
1515 # if defined(SEND_PWM_BY_TIMER)
1516 #define IR_SEND_PIN 7
1517 void enableSendPWMByTimer() {
1518  FLEXPWM1_OUTEN |= FLEXPWM_OUTEN_PWMA_EN(8);
1519  IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_00 = 6;
1520 }
1521 
1522 void disableSendPWMByTimer() {
1523  IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_00 = 5;
1524  FLEXPWM1_OUTEN &= ~FLEXPWM_OUTEN_PWMA_EN(8);
1525 }
1526 
1527 /*
1528  * timerConfigForSend() is used exclusively by IRsend::enableIROut()
1529  * Set output pin mode and disable receive interrupt if it uses the same resource
1530  */
1531 void timerConfigForSend(uint16_t aFrequencyKHz) {
1533 # if defined(IR_SEND_PIN)
1534  pinMode(IR_SEND_PIN, OUTPUT);
1535 # else
1536  pinMode(IrSender.sendPin, OUTPUT);
1537 # endif
1538 
1539  uint32_t period = (float) F_BUS_ACTUAL / (float) ((aFrequencyKHz) * 2000);
1540  uint32_t prescale = 0;
1541  while (period > 32767) {
1542  period = period >> 1;
1543  if (prescale < 7)
1544  prescale++;
1545  }
1546  FLEXPWM1_FCTRL0 |= FLEXPWM_FCTRL0_FLVL(8);
1547  FLEXPWM1_FSTS0 = 0x0008;
1548  FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_CLDOK(8);
1549  FLEXPWM1_SM3CTRL2 = FLEXPWM_SMCTRL2_INDEP;
1550  FLEXPWM1_SM3CTRL = FLEXPWM_SMCTRL_HALF | FLEXPWM_SMCTRL_PRSC(prescale);
1551  FLEXPWM1_SM3INIT = -period;
1552  FLEXPWM1_SM3VAL0 = 0;
1553  FLEXPWM1_SM3VAL1 = period;
1554  FLEXPWM1_SM3VAL2 = -(period / 3);
1555  FLEXPWM1_SM3VAL3 = period / 3;
1556  FLEXPWM1_SM3VAL4 = 0;
1557  FLEXPWM1_SM3VAL5 = 0;
1558  FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_LDOK(8) | FLEXPWM_MCTRL_RUN(8);
1559 }
1560 # endif // defined(SEND_PWM_BY_TIMER)
1561 
1562 /**********************************************************
1563  * ESP8266 boards
1564  **********************************************************/
1565 #elif defined(ESP8266)
1566 # if defined(SEND_PWM_BY_TIMER)
1567 #error "No support for hardware PWM generation for ESP8266"
1568 # endif // defined(SEND_PWM_BY_TIMER)
1569 
1570 // Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
1571 # if defined(ISR)
1572 #undef ISR
1573 # endif
1574 
1576  timer1_attachInterrupt(&IRReceiveTimerInterruptHandler); // enables interrupt too
1577 }
1579  timer1_detachInterrupt(); // disables interrupt too
1580 }
1581 
1582 void timerConfigForReceive() {
1583  timer1_isr_init();
1584  /*
1585  * TIM_DIV1 = 0, //80MHz (80 ticks/us - 104857.588 us max)
1586  * TIM_DIV16 = 1, //5MHz (5 ticks/us - 1677721.4 us max)
1587  * TIM_DIV256 = 3 //312.5Khz (1 tick = 3.2us - 26843542.4 us max)
1588  */
1589  timer1_enable(TIM_DIV16, TIM_EDGE, TIM_LOOP);
1590  timer1_write((80 / 16) * MICROS_PER_TICK); // 80 for 80 and 160! MHz clock, 16 for TIM_DIV16 above
1591 }
1592 
1593 /**********************************************************
1594  * ESP32 boards - can use any pin for send PWM
1595  * Receive timer and send generation are independent,
1596  * so it is recommended to always define SEND_PWM_BY_TIMER
1597  **********************************************************/
1598 #elif defined(ESP32)
1599 # if !defined(ESP_ARDUINO_VERSION)
1600 #define ESP_ARDUINO_VERSION 0x010101 // Version 1.1.1
1601 # endif
1602 
1603 // Variables specific to the ESP32.
1604 // the ledc functions behave like hardware timers for us :-), so we do not require our own soft PWM generation code.
1605 hw_timer_t *s50usTimer = nullptr; // set by timerConfigForReceive()
1606 #define _IRREMOTE_ESP32_LEDC_RESOLUTION 8
1607 #define _IRREMOTE_ESP32_LEDC_RESOLUTION_MAX_PWM_VALUE 255
1608 
1609 //# if ESP_ARDUINO_VERSION < ESP_ARDUINO_VERSION_VAL(3, 0, 0) && !defined(SEND_LEDC_CHANNEL)
1610 # if ESP_ARDUINO_VERSION < (3 << 16 | 0 << 8 | 0) && !defined(SEND_LEDC_CHANNEL) // works also in case ESP_ARDUINO_VERSION_VAL is not defined
1611 #define SEND_LEDC_CHANNEL 0 // The channel used for PWM 0 to 7 are high speed PWM channels
1612 # endif
1613 
1615 //# if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
1616 # if ESP_ARDUINO_VERSION >= (3 << 16 | 0 << 8 | 0)
1617  timerStart(s50usTimer);
1618 # else
1619  timerAlarmEnable(s50usTimer);
1620 # endif
1621 }
1622 
1623 //# if ESP_ARDUINO_VERSION < ESP_ARDUINO_VERSION_VAL(2, 0, 2)
1624 # if ESP_ARDUINO_VERSION < (2 << 16 | 0 << 8 | 2)
1625 /*
1626  * Special support for ESP core < 202
1627  */
1629  if (s50usTimer != nullptr) {
1630  timerDetachInterrupt(s50usTimer);
1631  timerEnd(s50usTimer);
1632  }
1633 }
1634 # else
1635 
1637  if (s50usTimer != nullptr) {
1638 //# if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
1639 # if ESP_ARDUINO_VERSION >= (3 << 16 | 0 << 8 | 0)
1640  timerStop(s50usTimer);
1641 # else
1642  timerAlarmDisable(s50usTimer);
1643 # endif
1644  }
1645 }
1646 # endif
1647 
1648 // Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
1649 # if defined(ISR)
1650 #undef ISR
1651 # endif
1652 
1653 # if !defined(DISABLE_CODE_FOR_RECEIVER) // Otherwise the &IRReceiveTimerInterruptHandler is referenced, but not available
1654 void timerConfigForReceive() {
1655  // ESP32 has a proper API to setup timers, no weird chip macros needed
1656  // simply call the readable API versions :)
1657  // 3 timers, choose #1, 80 divider for microsecond precision @80MHz clock, count_up = true
1658  if (s50usTimer == nullptr) {
1659 //# if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
1660 # if ESP_ARDUINO_VERSION >= (3 << 16 | 0 << 8 | 0)
1661  s50usTimer = timerBegin(1000000); // Only 1 parameter is required. 1000000 corresponds to 1 MHz / 1 uSec. After successful setup the timer will automatically start.
1662  timerStop(s50usTimer); // Stop it here, to avoid "error E (3447) gptimer: gptimer_start(348): timer is not enabled yet" at timerEnableReceiveInterrupt()
1663  timerAttachInterrupt(s50usTimer, &IRReceiveTimerInterruptHandler);
1664  timerAlarm(s50usTimer, MICROS_PER_TICK, true, 0); // 0 in the last parameter is repeat forever
1665 # else
1666  s50usTimer = timerBegin(1, 80, true);
1667  timerAttachInterrupt(s50usTimer, &IRReceiveTimerInterruptHandler, false); // false -> level interrupt, true -> edge interrupt, but this is not supported :-(
1668  timerAlarmWrite(s50usTimer, MICROS_PER_TICK, true);
1669 # endif
1670  }
1671  // every 50 us, autoreload = true
1672 }
1673 # endif
1674 
1675 uint8_t sLastSendPin = 0; // 0 means channel not initialized / pin not attached
1676 uint16_t sLastFrequencyKHz = 0;
1677 
1678 # if defined(SEND_PWM_BY_TIMER)
1679 void enableSendPWMByTimer() {
1680 //# if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
1681 # if ESP_ARDUINO_VERSION >= (3 << 16 | 0 << 8 | 0)
1682 # if defined(IR_SEND_PIN)
1683  ledcWrite(IR_SEND_PIN, (IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH * _IRREMOTE_ESP32_LEDC_RESOLUTION_MAX_PWM_VALUE) / 100); // 3.x API
1684 # else
1685  ledcWrite(IrSender.sendPin, (IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH * _IRREMOTE_ESP32_LEDC_RESOLUTION_MAX_PWM_VALUE) / 100); // 3.x API
1686 # endif
1687 # else
1688  // ESP version < 3.0
1689  ledcWrite(SEND_LEDC_CHANNEL, (IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH * _IRREMOTE_ESP32_LEDC_RESOLUTION_MAX_PWM_VALUE) / 100); // * 256 since we have 8 bit resolution
1690 # endif
1691 }
1692 void disableSendPWMByTimer() {
1693 //# if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
1694 # if ESP_ARDUINO_VERSION >= (3 << 16 | 0 << 8 | 0)
1695 # if defined(IR_SEND_PIN)
1696 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
1697  ledcWrite(IR_SEND_PIN, _IRREMOTE_ESP32_LEDC_RESOLUTION_MAX_PWM_VALUE); // 3.x API
1698 # else
1699  ledcWrite(IR_SEND_PIN, 0); // 3.x API
1700 # endif
1701 # else
1702 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
1703  ledcWrite(IrSender.sendPin, _IRREMOTE_ESP32_LEDC_RESOLUTION_MAX_PWM_VALUE); // 3.x API
1704 # else
1705  ledcWrite(IrSender.sendPin, 0); // 3.x API
1706 # endif
1707 # endif
1708 # else
1709  // ESP version < 3.0
1710  ledcWrite(SEND_LEDC_CHANNEL, 0);
1711 # endif
1712 }
1713 
1714 /*
1715  * timerConfigForSend() is used exclusively by IRsend::enableIROut() (or enableHighFrequencyIROut())
1716  * ledcWrite since ESP 2.0.2 does not work if pin mode is set.
1717  */
1718 void timerConfigForSend(uint16_t aFrequencyKHz) {
1719 //# if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
1720 # if ESP_ARDUINO_VERSION >= (3 << 16 | 0 << 8 | 0)
1721 # if defined(IR_SEND_PIN)
1722  if(sLastSendPin == 0){
1723  // Do it only once - except for frequency change
1724  ledcAttach(IR_SEND_PIN, aFrequencyKHz * 1000, _IRREMOTE_ESP32_LEDC_RESOLUTION);
1725  sLastSendPin = IR_SEND_PIN;
1726  } else if(sLastFrequencyKHz != aFrequencyKHz){
1727  // Frequency change here
1728  ledcDetach(IR_SEND_PIN); // detach pin before new attaching see #1194
1729  ledcAttach(IR_SEND_PIN, aFrequencyKHz * 1000, _IRREMOTE_ESP32_LEDC_RESOLUTION); // 3.x API
1730  sLastFrequencyKHz = aFrequencyKHz;
1731  }
1732 # else
1733  if(sLastSendPin != IrSender.sendPin || sLastFrequencyKHz != aFrequencyKHz){
1734  if(sLastSendPin != 0) {
1735  // do not detach initially
1736  ledcDetach(sLastSendPin); // detach pin before new attaching see #1194
1737  }
1738  ledcAttach(IrSender.sendPin, aFrequencyKHz * 1000, _IRREMOTE_ESP32_LEDC_RESOLUTION); // 3.x API
1739  sLastSendPin = IrSender.sendPin;
1740  sLastFrequencyKHz = aFrequencyKHz;
1741  }
1742 # endif
1743 # else
1744  // ESP version < 3.0 - no support for changing frequency
1745  ledcSetup(SEND_LEDC_CHANNEL, aFrequencyKHz * 1000, _IRREMOTE_ESP32_LEDC_RESOLUTION); // 8 bit PWM resolution
1746 # if defined(IR_SEND_PIN)
1747  ledcAttachPin(IR_SEND_PIN, SEND_LEDC_CHANNEL); // attach pin to channel
1748 # else
1749  if(sLastSendPin != 0 && sLastSendPin != IrSender.sendPin){
1750  }
1751  if( sLastSendPin != IrSender.sendPin){
1752  if(sLastSendPin != 0) {
1753  // do not detach initially
1754  ledcDetachPin(sLastSendPin); // detach pin before new attaching see #1194
1755  }
1756  ledcAttachPin(IrSender.sendPin, SEND_LEDC_CHANNEL); // attach pin to channel
1757  sLastSendPin = IrSender.sendPin;
1758  }
1759 # endif
1760 # endif
1761 }
1762 # endif // defined(SEND_PWM_BY_TIMER)
1763 
1764 /***************************************
1765  * SAMD boards like DUE and Zero
1766  ***************************************/
1767 #elif defined(ARDUINO_ARCH_SAMD)
1768 # if defined(SEND_PWM_BY_TIMER)
1769 #error PWM generation by hardware is not yet implemented for SAMD
1770 # endif
1771 
1772 # if !defined(IR_SAMD_TIMER)
1773 # if defined(__SAMD51__)
1774 # if defined(TC5)
1775 #define IR_SAMD_TIMER TC5
1776 #define IR_SAMD_TIMER_IRQ TC5_IRQn
1777 # else
1778 #define IR_SAMD_TIMER TC3
1779 #define IR_SAMD_TIMER_IRQ TC3_IRQn
1780 # endif
1781 # else
1782 // SAMD21
1783 #define IR_SAMD_TIMER TC3
1784 #define IR_SAMD_TIMER_ID GCLK_CLKCTRL_ID_TCC2_TC3
1785 #define IR_SAMD_TIMER_IRQ TC3_IRQn
1786 # endif
1787 # endif
1788 
1790  NVIC_EnableIRQ (IR_SAMD_TIMER_IRQ);
1791 }
1793  NVIC_DisableIRQ (IR_SAMD_TIMER_IRQ); // or TC5->INTENCLR.bit.MC0 = 1; or TC5->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE;
1794 
1795 }
1796 // Undefine ISR, because we call the plain function IRReceiveTimerInterruptHandler()
1797 // The ISR is now TC3_Handler() or TC5_Handler() below
1798 # if defined(ISR)
1799 #undef ISR
1800 # endif
1801 
1810 void timerConfigForReceive() {
1811  TcCount16 *TC = (TcCount16*) IR_SAMD_TIMER;
1812 
1813 # if defined(__SAMD51__)
1814  // Enable the TC5 clock, use generic clock generator 0 (F_CPU) for TC5
1815 # if defined(TC5_GCLK_ID)
1816  GCLK->PCHCTRL[TC5_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
1817 # else
1818  GCLK->PCHCTRL[TC3_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
1819 # endif
1820 
1821  // The TC should be disabled before the TC is reset in order to avoid undefined behavior.
1822  TC->CTRLA.reg &= ~TC_CTRLA_ENABLE; // Disable the Timer
1823  while (TC->SYNCBUSY.bit.ENABLE)
1824  ; // Wait for disabled
1825  // Reset TCx
1826  TC->CTRLA.reg = TC_CTRLA_SWRST;
1827  // When writing a '1' to the CTRLA.SWRST bit it will immediately read as '1'.
1828  while (TC->SYNCBUSY.bit.SWRST)
1829  ; // CTRL.SWRST will be cleared by hardware when the peripheral has been reset.
1830 
1831  // SAMD51 has F_CPU = 120 MHz
1832  TC->CC[0].reg = ((MICROS_PER_TICK * (F_CPU / MICROS_IN_ONE_SECOND)) / 16) - 1; // (375 - 1);
1833 
1834  /*
1835  * Set timer counter mode to 16 bits, set mode as match frequency, prescaler is DIV16 => 7.5 MHz clock, start counter
1836  */
1837  TC->CTRLA.reg |= TC_CTRLA_MODE_COUNT16 | TC_WAVE_WAVEGEN_MFRQ | TC_CTRLA_PRESCALER_DIV16 | TC_CTRLA_ENABLE;
1838 // while (TC5->COUNT16.STATUS.bit.SYNCBUSY == 1); // The next commands do an implicit wait :-)
1839 # else
1840  // Enable GCLK and select GCLK0 (F_CPU) as clock for TC4 and TC5
1841  REG_GCLK_CLKCTRL = (uint16_t)(GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | IR_SAMD_TIMER_ID);
1842  while (GCLK->STATUS.bit.SYNCBUSY == 1)
1843  ;
1844 
1845  // The TC should be disabled before the TC is reset in order to avoid undefined behavior.
1846  TC->CTRLA.reg &= ~TC_CTRLA_ENABLE;
1847  // When write-synchronization is ongoing for a register, any subsequent write attempts to this register will be discarded, and an error will be reported.
1848  while (TC->STATUS.bit.SYNCBUSY == 1)
1849  ; // wait for sync to ensure that we can write again to COUNT16.CTRLA.reg
1850  // Reset TCx
1851  TC->CTRLA.reg = TC_CTRLA_SWRST;
1852  // When writing a 1 to the CTRLA.SWRST bit it will immediately read as 1.
1853  while (TC->CTRLA.bit.SWRST)
1854  ; // CTRL.SWRST will be cleared by hardware when the peripheral has been reset.
1855 
1856  // SAMD51 has F_CPU = 48 MHz
1857  TC->CC[0].reg = ((MICROS_PER_TICK * (F_CPU / MICROS_IN_ONE_SECOND)) / 16) - 1; // (150 - 1);
1858 
1859  /*
1860  * Set timer counter mode to 16 bits, set mode as match frequency, prescaler is DIV16 => 3 MHz clock, start counter
1861  */
1862  TC->CTRLA.reg |= TC_CTRLA_MODE_COUNT16 | TC_CTRLA_WAVEGEN_MFRQ | TC_CTRLA_PRESCALER_DIV16 | TC_CTRLA_ENABLE;
1863 
1864 # endif
1865  // Configure interrupt request
1866  NVIC_DisableIRQ (IR_SAMD_TIMER_IRQ);
1867  NVIC_ClearPendingIRQ(IR_SAMD_TIMER_IRQ);
1868  NVIC_SetPriority(IR_SAMD_TIMER_IRQ, 0);
1869  NVIC_EnableIRQ(IR_SAMD_TIMER_IRQ);
1870 
1871  // Enable the compare interrupt
1872  TC->INTENSET.bit.MC0 = 1;
1873 }
1874 
1875 # if !defined(DISABLE_CODE_FOR_RECEIVER)
1876 # if defined(__SAMD51__) && defined(TC5)
1877 void TC5_Handler(void)
1878 # else
1879 void TC3_Handler(void)
1880 # endif // defined(__SAMD51__)
1881 {
1882  TcCount16 *TC = (TcCount16*) IR_SAMD_TIMER;
1883  // Check for right interrupt bit
1884  if (TC->INTFLAG.bit.MC0 == 1) {
1885  // reset bit for next turn
1886  TC->INTFLAG.bit.MC0 = 1;
1888  }
1889 }
1890 # endif // !defined(DISABLE_CODE_FOR_RECEIVER)
1891 
1892 /***************************************
1893  * Mbed based boards
1894  ***************************************/
1895 #elif defined(ARDUINO_ARCH_MBED) // Arduino Nano 33 BLE + Sparkfun Apollo3 + Nano RP2040 Connect
1896 #include "mbed.h"
1897 mbed::Ticker s50usTimer;
1898 
1899 // Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
1900 # if defined(ISR)
1901 #undef ISR
1902 # endif
1903 
1905  s50usTimer.attach(IRReceiveTimerInterruptHandler, std::chrono::microseconds(MICROS_PER_TICK));
1906 }
1908  s50usTimer.detach();
1909 }
1910 
1911 void timerConfigForReceive() {
1912  s50usTimer.attach(IRReceiveTimerInterruptHandler, std::chrono::microseconds(MICROS_PER_TICK));
1913 }
1914 
1915 # if defined(SEND_PWM_BY_TIMER)
1916 #include "pins_arduino.h" // for digitalPinToPinName()
1917 
1918 # if defined(IR_SEND_PIN)
1919 mbed::PwmOut sPwmOutForSendPWM(digitalPinToPinName(IR_SEND_PIN));
1920 # else
1921 mbed::PwmOut sPwmOutForSendPWM(digitalPinToPinName(IrSender.sendPin));
1922 # endif
1923 uint8_t sIROutPuseWidth;
1924 uint8_t sIROutPuseWidthForHigh; // for setting level to 1
1925 
1926 void enableSendPWMByTimer() {
1927  sPwmOutForSendPWM.pulsewidth_us(sIROutPuseWidth);
1928 }
1929 //void enableSendPWMByTimer() { sPwmOutForSendPWM.resume(); sPwmOutForSendPWM.pulsewidth_us(sIROutPuseWidth);}
1930 //void disableSendPWMByTimer() { sPwmOutForSendPWM.suspend();} // this kills pulsewidth_us value and does not set output level to LOW
1931 
1932 void disableSendPWMByTimer() {
1933 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
1934  sPwmOutForSendPWM.pulsewidth_us(sIROutPuseWidthForHigh); // this also sets output level to HIGH :-)
1935 # else
1936  sPwmOutForSendPWM.pulsewidth_us(0); // this also sets output level to LOW :-)
1937 # endif
1938 }
1939 
1940 /*
1941  * timerConfigForSend() is used exclusively by IRsend::enableIROut()
1942  * Set output pin mode and disable receive interrupt if it uses the same resource
1943  */
1944 void timerConfigForSend(uint16_t aFrequencyKHz) {
1945  sIROutPuseWidthForHigh = 1000 / aFrequencyKHz;
1946  sPwmOutForSendPWM.period_us(sIROutPuseWidthForHigh); // 26.315 for 38 kHz
1947  sIROutPuseWidth = (1000 * IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH) / (aFrequencyKHz * 100);
1948 }
1949 # endif // defined(SEND_PWM_BY_TIMER)
1950 
1951 /*************************************************************************************************************************************
1952  * RP2040 based boards for pico core
1953  * https://github.com/earlephilhower/arduino-pico
1954  * https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
1955  * Can use any pin for PWM, no timer restrictions
1956  *************************************************************************************************************************************/
1957 #elif defined(ARDUINO_ARCH_RP2040) // Raspberry Pi Pico, Adafruit Feather RP2040, etc.
1958 #include "pico/time.h"
1959 
1960 repeating_timer_t s50usTimer;
1961 
1962 // Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
1963 # if defined(ISR)
1964 #undef ISR
1965 # endif
1966 
1967 // The timer callback has a parameter and a return value
1968 bool IRTimerInterruptHandlerHelper(repeating_timer_t*) {
1970  return true;
1971 }
1972 
1974  add_repeating_timer_us(-(MICROS_PER_TICK), IRTimerInterruptHandlerHelper, nullptr, &s50usTimer);
1975 }
1977  cancel_repeating_timer(&s50usTimer);
1978 }
1979 
1980 void timerConfigForReceive() {
1981  // no need for initializing timer at setup()
1982 }
1983 #define SEND_PWM_BY_TIMER // Disable carrier PWM generation in software and use (restricted) hardware PWM.
1984 
1985 # if defined(SEND_PWM_BY_TIMER)
1986 #include "hardware/pwm.h"
1987 #define USE_RP2040_NATIVE_COMMANDS
1988 
1989 # if defined(USE_RP2040_NATIVE_COMMANDS)
1990 uint sSliceNumberForSendPWM;
1991 uint sChannelNumberForSendPWM;
1992 uint sIROutPuseWidth;
1993 uint16_t sIROutPuseWidthForHigh; // for setting level to 1
1994 # else
1995 uint sFrequency;
1996 # endif
1997 
1998 /*
1999  * If we just disable the PWM, the counter stops and the output stays at the state is currently has
2000  */
2001 void enableSendPWMByTimer() {
2002 # if defined(USE_RP2040_NATIVE_COMMANDS)
2003  pwm_set_counter(sSliceNumberForSendPWM, 0);
2004  pwm_set_chan_level(sSliceNumberForSendPWM, sChannelNumberForSendPWM, sIROutPuseWidth);
2005 # else
2006  analogWriteFreq(sFrequency);
2007 # if defined(IR_SEND_PIN)
2008  analogWrite(IR_SEND_PIN, (uint8_t) (IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH * 255 / 100)); // Calculate duty as 0-255 value (analogWrite uses 8-bit resolution)
2009 # else
2010  analogWrite(IrSender.sendPin, (uint8_t) (IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH * 255 / 100)); // Calculate duty as 0-255 value (analogWrite uses 8-bit resolution)
2011 # endif
2012 # endif
2013 }
2014 
2015 void disableSendPWMByTimer() {
2016 # if defined(USE_RP2040_NATIVE_COMMANDS)
2017 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
2018  pwm_set_chan_level(sSliceNumberForSendPWM, sChannelNumberForSendPWM, sIROutPuseWidthForHigh); // this sets output also to HIGH
2019 # else
2020  pwm_set_chan_level(sSliceNumberForSendPWM, sChannelNumberForSendPWM, 0); // this sets output also to LOW
2021 # endif
2022 # else
2023 # if defined(IR_SEND_PIN)
2024 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
2025  analogWrite(IR_SEND_PIN, 255); // analogWrite(0) disables PWM and sets pin HIGH
2026 # else
2027  analogWrite(IR_SEND_PIN, 0); // analogWrite(0) disables PWM and sets pin LOW
2028 # endif
2029 # else
2030 # if defined(USE_ACTIVE_LOW_OUTPUT_FOR_SEND_PIN)
2031  analogWrite(IrSender.sendPin, 255); // analogWrite(0) disables PWM and sets pin HIGH
2032 # else
2033  analogWrite(IrSender.sendPin, 0); // analogWrite(0) disables PWM and sets pin LOW
2034 # endif
2035 # endif
2036 # endif
2037 }
2038 
2039 /*
2040  * timerConfigForSend() is used exclusively by IRsend::enableIROut()
2041  * Set output pin mode and disable receive interrupt if it uses the same resource
2042  */
2043 void timerConfigForSend(uint16_t aFrequencyKHz) {
2044 # if defined(USE_RP2040_NATIVE_COMMANDS)
2045 # if defined(IR_SEND_PIN)
2046  gpio_set_function(IR_SEND_PIN, GPIO_FUNC_PWM);
2047  // Find out which PWM slice is connected to IR_SEND_PIN
2048  sSliceNumberForSendPWM = pwm_gpio_to_slice_num(IR_SEND_PIN);
2049  sChannelNumberForSendPWM = pwm_gpio_to_channel(IR_SEND_PIN);
2050 # else
2051  gpio_set_function(IrSender.sendPin, GPIO_FUNC_PWM);
2052  // Find out which PWM slice is connected to IR_SEND_PIN
2053  sSliceNumberForSendPWM = pwm_gpio_to_slice_num(IrSender.sendPin);
2054  sChannelNumberForSendPWM = pwm_gpio_to_channel(IrSender.sendPin);
2055 # endif
2056 # else
2057 # if defined(IR_SEND_PIN)
2058  pinMode(IR_SEND_PIN, OUTPUT); // Set the pin to output mode initially
2059 # else
2060  pinMode(IrSender.sendPin, OUTPUT); // Set the pin to output mode initially
2061 # endif
2062 # endif
2063 # if defined(USE_RP2040_NATIVE_COMMANDS)
2064  uint16_t tPWMWrapValue = (clock_get_hz(clk_sys)) / (aFrequencyKHz * 1000); // 3289.473 for 38 kHz @125 MHz clock. We have a 16 bit counter and use system clock (125 MHz)
2065  pwm_config tPWMConfig = pwm_get_default_config();
2066  sIROutPuseWidthForHigh = tPWMWrapValue;
2067  pwm_config_set_wrap(&tPWMConfig, tPWMWrapValue - 1);
2068  pwm_init(sSliceNumberForSendPWM, &tPWMConfig, false); // we do not want to send now
2069  sIROutPuseWidth = ((tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH) / 100) - 1; // 985.84 for 38 kHz
2070  pwm_set_chan_level(sSliceNumberForSendPWM, sChannelNumberForSendPWM, 0);
2071  pwm_set_enabled(sSliceNumberForSendPWM, true);
2072 # else
2073  sFrequency = aFrequencyKHz * 1000;
2074 # endif
2075 }
2076 # endif // defined(SEND_PWM_BY_TIMER)
2077 
2078 /***************************************
2079  * NRF5 boards like the BBC:Micro
2080  ***************************************/
2081 #elif defined(NRF5) || defined(ARDUINO_ARCH_NRF52840) || defined(ARDUINO_ARCH_NRF52)
2082 # if defined(SEND_PWM_BY_TIMER)
2083 #error PWM generation by hardware not implemented for NRF5
2084 # endif
2085 
2087  NVIC_EnableIRQ (TIMER2_IRQn);
2088 }
2090  NVIC_DisableIRQ (TIMER2_IRQn);
2091 }
2092 
2093 // Undefine ISR, because we call the plain function IRReceiveTimerInterruptHandler()
2094 # if defined(ISR)
2095 #undef ISR
2096 # endif
2097 
2098 void timerConfigForReceive() {
2099  NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer; // Set the timer in Timer Mode
2100  NRF_TIMER2->TASKS_CLEAR = 1; // clear the task first to be usable for later
2101  NRF_TIMER2->PRESCALER = 4; // f TIMER = 16 MHz / (2 ^ PRESCALER ) : 4 -> 1 MHz, 1 uS
2102  NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit; //Set counter to 16 bit resolution
2103  NRF_TIMER2->CC[0] = MICROS_PER_TICK; //Set value for TIMER2 compare register 0, to trigger every 50 uS
2104  NRF_TIMER2->CC[1] = 0; //Set value for TIMER2 compare register 1
2105 
2106  // Enable interrupt on Timer 2, for CC[0] compare match events
2107  NRF_TIMER2->INTENSET = (TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos);
2108  NRF_TIMER2->TASKS_START = 1; // Start TIMER2
2109 
2110  // timerAttachInterrupt(timer, &IRTimerInterruptHandler, 1);
2111 }
2112 
2113 #if !defined(DISABLE_CODE_FOR_RECEIVER)
2114 
2117 extern "C" {
2118 void TIMER2_IRQHandler(void) {
2119  // Interrupt Service Routine - Fires every 50uS
2120  if ((NRF_TIMER2->EVENTS_COMPARE[0] != 0) && ((NRF_TIMER2->INTENSET & TIMER_INTENSET_COMPARE0_Msk) != 0)) {
2121  NRF_TIMER2->EVENTS_COMPARE[0] = 0; //Clear compare register 0 event
2122  IRReceiveTimerInterruptHandler(); // call the IR-receive function
2123  NRF_TIMER2->CC[0] += 50;
2124  }
2125 }
2126 }
2127 #endif
2128 
2129 /**********************************************************************************************************************
2130  * BluePill in 2 flavors see https://samuelpinches.com.au/3d-printer/cutting-through-some-confusion-on-stm32-and-arduino/
2131  *
2132  * Recommended original Arduino_STM32 by Roger Clark.
2133  * http://dan.drown.org/stm32duino/package_STM32duino_index.json
2134  * STM32F1 architecture for "Generic STM32F103C series" from "STM32F1 Boards (Arduino_STM32)" of Arduino Board manager
2135  **********************************************************************************************************************/
2136 #elif defined(__STM32F1__) || defined(ARDUINO_ARCH_STM32F1)
2137 #include <HardwareTimer.h> // 4 timers and 4. timer (4.channel) is used for tone()
2138 # if defined(SEND_PWM_BY_TIMER)
2139 #error PWM generation by hardware not implemented for STM32
2140 # endif
2141 
2142 /*
2143  * Use timer 3 as IR timer.
2144  * Timer 3 blocks PA6, PA7, PB0, PB1, so if you require one of them as tone() or Servo output, you must choose another timer.
2145  */
2146 HardwareTimer s50usTimer(3);
2147 
2149  s50usTimer.resume();
2150 }
2152  s50usTimer.pause();
2153 }
2154 
2155 // Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
2156 # if defined(ISR)
2157 #undef ISR
2158 # endif
2159 
2160 void timerConfigForReceive() {
2161  s50usTimer.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE);
2162  s50usTimer.setPrescaleFactor(1);
2163  s50usTimer.setOverflow((F_CPU / MICROS_IN_ONE_SECOND) * MICROS_PER_TICK);
2164  s50usTimer.attachInterrupt(TIMER_CH1, IRReceiveTimerInterruptHandler);
2165  s50usTimer.refresh();
2166 }
2167 
2168 /**********************************************************************************************************************
2169  * STM32duino by ST Microsystems.
2170  * https://github.com/stm32duino/Arduino_Core_STM32
2171  * https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json
2172  * stm32 architecture for "Generic STM32F1 series" from "STM32 Boards (selected from submenu)" of Arduino Board manager
2173  **********************************************************************************************************************/
2174 #elif defined(STM32F1xx) || defined(ARDUINO_ARCH_STM32)
2175 #include <HardwareTimer.h> // 4 timers and 3. timer is used for tone(), 2. for Servo
2176 # if defined(SEND_PWM_BY_TIMER)
2177 #error PWM generation by hardware not implemented for STM32
2178 # endif
2179 
2180 /*
2181  * Use timer 4 as IR timer.
2182  * Timer 4 blocks PB6, PB7, PB8, PB9, so if you need one them as tone() or Servo output, you must choose another timer.
2183  */
2184 # if defined(TIM4)
2185 HardwareTimer s50usTimer(TIM4);
2186 # else
2187 HardwareTimer s50usTimer(TIM2);
2188 # endif
2189 
2191  s50usTimer.resume();
2192 }
2194  s50usTimer.pause();
2195 }
2196 
2197 // Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
2198 # if defined(ISR)
2199 #undef ISR
2200 # endif
2201 
2202 void timerConfigForReceive() {
2203  s50usTimer.setOverflow(MICROS_PER_TICK, MICROSEC_FORMAT); // 50 uS
2204  s50usTimer.attachInterrupt(IRReceiveTimerInterruptHandler);
2205  s50usTimer.resume();
2206 }
2207 
2208 /***************************************
2209  * Particle special IntervalTimer
2210  * !!!UNTESTED!!!
2211  ***************************************/
2212 #elif defined(PARTICLE)
2213 # ifndef __INTERVALTIMER_H__
2214 #include "SparkIntervalTimer.h" // SparkIntervalTimer.h is required if PARTICLE is defined.
2215 # endif
2216 
2217 extern IntervalTimer timer;
2218 extern int ir_out_kHz;
2219 
2221  timer.begin(IRReceiveTimerInterruptHandler, MICROS_PER_TICK, uSec);
2222 }
2224  timer.end();
2225 }
2226 
2227 // Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
2228 # if defined(ISR)
2229 #undef ISR
2230 # endif
2231 
2232 void timerConfigForReceive() {
2233 }
2234 
2235 # if defined(SEND_PWM_BY_TIMER)
2236 # if defined(IR_SEND_PIN)
2237 void enableSendPWMByTimer() {
2238  analogWrite(IR_SEND_PIN, ((255L * 100) / IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH)), ir_out_kHz*1000);
2239 }
2240 void disableSendPWMByTimer() {
2241  analogWrite(IR_SEND_PIN, 0, ir_out_kHz*1000);
2242 }
2243 # else
2244 void enableSendPWMByTimer() {
2245  analogWrite(IrSender.sendPin, ((255L * 100) / IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH), ir_out_kHz * 1000);
2246 }
2247 void disableSendPWMByTimer() {
2248  analogWrite(IrSender.sendPin, 0, ir_out_kHz * 1000);
2249 }
2250 # endif
2251 
2252 
2253 /*
2254  * timerConfigForSend() is used exclusively by IRsend::enableIROut()
2255  * Set output pin mode and disable receive interrupt if it uses the same resource
2256  */
2257 void timerConfigForSend(uint16_t aFrequencyKHz) {
2259 # if defined(IR_SEND_PIN)
2260  pinMode(IR_SEND_PIN, OUTPUT);
2261 # else
2262  pinMode(IrSender.sendPin, OUTPUT);
2263 # endif
2264  ir_out_kHz = aFrequencyKHz;
2265 }
2266 # endif // defined(SEND_PWM_BY_TIMER)
2267 
2268 #elif defined(VEGA_ARIES_V2) || defined(VEGA_ARIES_V3) || defined(VEGA_ARIES_IOT) || defined(VEGA_ARIES_MICRO)
2269 #include "Timer.h"
2270 Timer Timer(0);
2271 
2272 #define TIMER_RESET_INTR_PENDING
2273 #define TIMER_ENABLE_RECEIVE_INTR Timer.attachInterrupt(IRTimerInterruptHandler)
2274 #define TIMER_DISABLE_RECEIVE_INTR Timer.detachInterrupt()
2275 
2277  Timer.resume();
2278 }
2280  Timer.stop();
2281 }
2282 
2283 # if defined(ISR)
2284 #undef ISR
2285 # endif
2286 #define ISR() void IRTimerInterruptHandler(void)
2287 void IRTimerInterruptHandler(void);
2288 
2289 void timerConfigForReceive() {
2290  Timer.initialize(MICROS_PER_TICK); // 50 uS
2291  Timer.attachInterrupt(IRTimerInterruptHandler);
2292  Timer.resume();
2293 }
2294 
2295 # if defined(SEND_PWM_BY_TIMER)
2296 #define ENABLE_SEND_PWM_BY_TIMER
2297 #define DISABLE_SEND_PWM_BY_TIMER
2298 
2299 void timerConfigForSend(uint8_t aFrequencyKHz) {
2300  TIMER_DISABLE_RECEIVE_INTR;
2301 # if defined(IR_SEND_PIN)
2302  pinMode(IR_SEND_PIN, OUTPUT);
2303 # else
2304  pinMode(IrSender.sendPin, OUTPUT);
2305 # endif
2306  (void) aFrequencyKHz;
2307 }
2308 # endif // defined(SEND_PWM_BY_TIMER)
2309 
2310 #else // CPU types
2311 /***************************************
2312  * Unknown CPU board
2313  ***************************************/
2314 #error Internal code configuration error, no timer functions implemented for this CPU / board
2315 /*
2316  * Dummy definitions to avoid more irritating compile errors
2317  */
2318 
2319 void timerEnableReceiveInterrupt() {};
2321 
2322 # if defined(ISR)
2323 #undef ISR
2324 # endif
2325 #define ISR() void notImplemented(void)
2326 
2327 void timerConfigForReceive() {
2328 }
2329 
2330 # if defined(SEND_PWM_BY_TIMER)
2331 void enableSendPWMByTimer() {
2332 }
2333 void disableSendPWMByTimer() {
2334 }
2335 
2336 void timerConfigForSend(uint16_t aFrequencyKHz) {
2338 # if defined(IR_SEND_PIN)
2339  pinMode(IR_SEND_PIN, OUTPUT);
2340 # else
2341  pinMode(IrSender.sendPin, OUTPUT);
2342 # endif
2343  (void) aFrequencyKHz;
2344 }
2345 # endif // defined(SEND_PWM_BY_TIMER)
2346 
2347 #endif // defined(DOXYGEN / CPU_TYPES)
2348 
2351 #endif // _IR_TIMER_HPP
timerConfigForReceive
void timerConfigForReceive()
Configures the timer to be able to generate the receive sample interrupt, which consumes a small amou...
Definition: IRTimer.hpp:112
MICROS_PER_TICK
#define MICROS_PER_TICK
microseconds per clock interrupt tick
Definition: IRremote.hpp:133
IRsend::sendPin
uint8_t sendPin
Definition: IRremoteInt.h:739
digitalWriteFast
#define digitalWriteFast
Definition: digitalWriteFast.h:347
IR_SEND_PIN
#define IR_SEND_PIN
Hardware / timer dependent pin number for sending IR if SEND_PWM_BY_TIMER is defined.
Definition: IRTimer.hpp:104
timerDisableReceiveInterrupt
void timerDisableReceiveInterrupt()
Disables the receive sample timer interrupt.
Definition: IRTimer.hpp:124
timerConfigForSend
void timerConfigForSend(uint16_t aFrequencyKHz)
IF PWM should be generated not by software, but by a timer, this function sets output pin mode,...
Definition: IRTimer.hpp:136
IRReceiveTimerInterruptHandler
void IRReceiveTimerInterruptHandler()
Definition: IRReceive.hpp:277
MICROS_IN_ONE_SECOND
#define MICROS_IN_ONE_SECOND
Definition: IRremote.hpp:216
timerResetInterruptPending
void timerResetInterruptPending()
timerEnableReceiveInterrupt
void timerEnableReceiveInterrupt()
Enables the receive sample timer interrupt, which consumes a small amount of CPU every 50 us.
Definition: IRTimer.hpp:117
enableSendPWMByTimer
void enableSendPWMByTimer()
Enables output of the PWM signal of the timer at the timer pin.
Definition: IRTimer.hpp:142
IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH
#define IR_SEND_DUTY_CYCLE_PERCENT_FOR_LEVEL_HIGH
Definition: IRTimer.hpp:70
IrSender
IRsend IrSender
Definition: IRSend.hpp:62
disableSendPWMByTimer
void disableSendPWMByTimer()
Disables output of the PWM signal of the timer at the timer pin and set it to inactive.
Definition: IRTimer.hpp:147