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