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 /**********************************************************
1401  * ESP8266 boards
1402  **********************************************************/
1403 #elif defined(ESP8266)
1404 # if defined(SEND_PWM_BY_TIMER)
1405 #error "No support for hardware PWM generation for ESP8266"
1406 # endif // defined(SEND_PWM_BY_TIMER)
1407 
1408 // Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
1409 # if defined(ISR)
1410 #undef ISR
1411 # endif
1412 
1414  timer1_attachInterrupt(&IRReceiveTimerInterruptHandler); // enables interrupt too
1415 }
1417  timer1_detachInterrupt(); // disables interrupt too
1418 }
1419 
1420 void timerConfigForReceive() {
1421  timer1_isr_init();
1422  /*
1423  * TIM_DIV1 = 0, //80MHz (80 ticks/us - 104857.588 us max)
1424  * TIM_DIV16 = 1, //5MHz (5 ticks/us - 1677721.4 us max)
1425  * TIM_DIV256 = 3 //312.5Khz (1 tick = 3.2us - 26843542.4 us max)
1426  */
1427  timer1_enable(TIM_DIV16, TIM_EDGE, TIM_LOOP);
1428  timer1_write((80 / 16) * MICROS_PER_TICK); // 80 for 80 and 160! MHz clock, 16 for TIM_DIV16 above
1429 }
1430 
1431 /**********************************************************
1432  * ESP32 boards - can use any pin for send PWM
1433  * Receive timer and send generation are independent,
1434  * so it is recommended to always define SEND_PWM_BY_TIMER
1435  **********************************************************/
1436 #elif defined(ESP32)
1437 # if ESP_ARDUINO_VERSION >= ESP_ARDUINO_VERSION_VAL(3, 0, 0)
1438 #error This library does not work with ESP32 core 3.x. Please use ESP 2.0.17 core. You are kindly invited to port and document the code to 3.x, to fix this problem!
1439 # endif
1440 
1441 // Variables specific to the ESP32.
1442 // the ledc functions behave like hardware timers for us :-), so we do not require our own soft PWM generation code.
1443 hw_timer_t *s50usTimer = NULL; // set by timerConfigForReceive()
1444 
1445 # if ESP_ARDUINO_VERSION < ESP_ARDUINO_VERSION_VAL(3, 0, 0) && !defined(SEND_LEDC_CHANNEL)
1446 #define SEND_LEDC_CHANNEL 0 // The channel used for PWM 0 to 7 are high speed PWM channels
1447 # endif
1448 
1450  timerAlarmEnable(s50usTimer);
1451 }
1452 
1453 # if !defined(ESP_ARDUINO_VERSION)
1454 #define ESP_ARDUINO_VERSION 0
1455 # endif
1456 # if !defined(ESP_ARDUINO_VERSION_VAL)
1457 #define ESP_ARDUINO_VERSION_VAL(major, minor, patch) 202
1458 # endif
1459 # if ESP_ARDUINO_VERSION < ESP_ARDUINO_VERSION_VAL(2, 0, 2)
1461  if (s50usTimer != NULL) {
1462  timerDetachInterrupt(s50usTimer);
1463  timerEnd(s50usTimer);
1464  }
1465 }
1466 # else
1468  if (s50usTimer != NULL) {
1469  timerAlarmDisable(s50usTimer);
1470  }
1471 }
1472 # endif
1473 
1474 // Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
1475 # if defined(ISR)
1476 #undef ISR
1477 # endif
1478 
1479 # if !defined(DISABLE_CODE_FOR_RECEIVER) // &IRReceiveTimerInterruptHandler is referenced, but not available
1480 void timerConfigForReceive() {
1481  // ESP32 has a proper API to setup timers, no weird chip macros needed
1482  // simply call the readable API versions :)
1483  // 3 timers, choose #1, 80 divider for microsecond precision @80MHz clock, count_up = true
1484  if(s50usTimer == NULL) {
1485  s50usTimer = timerBegin(1, 80, true);
1486  timerAttachInterrupt(s50usTimer, &IRReceiveTimerInterruptHandler, false); // false -> level interrupt, true -> edge interrupt, but this is not supported :-(
1487  timerAlarmWrite(s50usTimer, MICROS_PER_TICK, true);
1488  }
1489  // every 50 us, autoreload = true
1490 }
1491 # endif
1492 
1493 # if !defined(IR_SEND_PIN)
1494 uint8_t sLastSendPin = 0; // To detach before attach, if already attached
1495 # endif
1496 
1497 # if defined(SEND_PWM_BY_TIMER)
1498 void enableSendPWMByTimer() {
1499 # if ESP_ARDUINO_VERSION < ESP_ARDUINO_VERSION_VAL(3, 0, 0)
1500  ledcWrite(SEND_LEDC_CHANNEL, (IR_SEND_DUTY_CYCLE_PERCENT * 256) / 100); // * 256 since we have 8 bit resolution
1501 # else
1502  ledcWrite(IrSender.sendPin, (IR_SEND_DUTY_CYCLE_PERCENT * 256) / 100); // New API
1503 # endif
1504 }
1505 void disableSendPWMByTimer() {
1506 # if ESP_ARDUINO_VERSION < ESP_ARDUINO_VERSION_VAL(3, 0, 0)
1507  ledcWrite(SEND_LEDC_CHANNEL, 0);
1508 # else
1509  ledcWrite(IrSender.sendPin, 0); // New API
1510 # endif
1511 }
1512 
1513 /*
1514  * timerConfigForSend() is used exclusively by IRsend::enableIROut() (or enableHighFrequencyIROut())
1515  * ledcWrite since ESP 2.0.2 does not work if pin mode is set.
1516  */
1517 void timerConfigForSend(uint16_t aFrequencyKHz) {
1518 # if ESP_ARDUINO_VERSION < ESP_ARDUINO_VERSION_VAL(3, 0, 0)
1519  ledcSetup(SEND_LEDC_CHANNEL, aFrequencyKHz * 1000, 8); // 8 bit PWM resolution
1520 # if defined(IR_SEND_PIN)
1521  ledcAttachPin(IR_SEND_PIN, SEND_LEDC_CHANNEL); // attach pin to channel
1522 # else
1523  if(sLastSendPin != 0 && sLastSendPin != IrSender.sendPin){
1524  ledcDetachPin(IrSender.sendPin); // detach pin before new attaching see #1194
1525  }
1526  ledcAttachPin(IrSender.sendPin, SEND_LEDC_CHANNEL); // attach pin to channel
1527  sLastSendPin = IrSender.sendPin;
1528 # endif
1529 # else // New API here
1530 # if defined(IR_SEND_PIN)
1531  ledcAttach(IR_SEND_PIN, aFrequencyKHz * 1000, 8); // New API
1532 # else
1533  if(sLastSendPin != 0 && sLastSendPin != IrSender.sendPin){
1534  ledcDetach(IrSender.sendPin); // detach pin before new attaching see #1194
1535  }
1536  ledcAttach(IrSender.sendPin, aFrequencyKHz * 1000, 8); // New API
1537  sLastSendPin = IrSender.sendPin;
1538 # endif
1539 # endif
1540 }
1541 # endif // defined(SEND_PWM_BY_TIMER)
1542 
1543 /***************************************
1544  * SAMD boards like DUE and Zero
1545  ***************************************/
1546 #elif defined(ARDUINO_ARCH_SAMD)
1547 # if defined(SEND_PWM_BY_TIMER)
1548 #error PWM generation by hardware is not yet implemented for SAMD
1549 # endif
1550 
1551 # if !defined(IR_SAMD_TIMER)
1552 # if defined(__SAMD51__)
1553 #define IR_SAMD_TIMER TC5
1554 #define IR_SAMD_TIMER_IRQ TC5_IRQn
1555 # else
1556 // SAMD21
1557 #define IR_SAMD_TIMER TC3
1558 #define IR_SAMD_TIMER_ID GCLK_CLKCTRL_ID_TCC2_TC3
1559 #define IR_SAMD_TIMER_IRQ TC3_IRQn
1560 # endif
1561 # endif
1562 
1564  NVIC_EnableIRQ (IR_SAMD_TIMER_IRQ);
1565 }
1567  NVIC_DisableIRQ (IR_SAMD_TIMER_IRQ); // or TC5->INTENCLR.bit.MC0 = 1; or TC5->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE;
1568 
1569 }
1570 // Undefine ISR, because we call the plain function IRReceiveTimerInterruptHandler()
1571 // The ISR is now TC3_Handler() or TC5_Handler() below
1572 # if defined(ISR)
1573 #undef ISR
1574 # endif
1575 
1584 void timerConfigForReceive() {
1585  TcCount16 *TC = (TcCount16*) IR_SAMD_TIMER;
1586 
1587 # if defined(__SAMD51__)
1588  // Enable the TC5 clock, use generic clock generator 0 (F_CPU) for TC5
1589  GCLK->PCHCTRL[TC5_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
1590 
1591  // The TC should be disabled before the TC is reset in order to avoid undefined behavior.
1592  TC->CTRLA.reg &= ~TC_CTRLA_ENABLE; // Disable the Timer
1593  while (TC->SYNCBUSY.bit.ENABLE)
1594  ; // Wait for disabled
1595  // Reset TCx
1596  TC->CTRLA.reg = TC_CTRLA_SWRST;
1597  // When writing a '1' to the CTRLA.SWRST bit it will immediately read as '1'.
1598  while (TC->SYNCBUSY.bit.SWRST)
1599  ; // CTRL.SWRST will be cleared by hardware when the peripheral has been reset.
1600 
1601  // SAMD51 has F_CPU = 120 MHz
1602  TC->CC[0].reg = ((MICROS_PER_TICK * (F_CPU / MICROS_IN_ONE_SECOND)) / 16) - 1; // (375 - 1);
1603 
1604  /*
1605  * Set timer counter mode to 16 bits, set mode as match frequency, prescaler is DIV16 => 7.5 MHz clock, start counter
1606  */
1607  TC->CTRLA.reg |= TC_CTRLA_MODE_COUNT16 | TC_WAVE_WAVEGEN_MFRQ | TC_CTRLA_PRESCALER_DIV16 | TC_CTRLA_ENABLE;
1608 // while (TC5->COUNT16.STATUS.bit.SYNCBUSY == 1); // The next commands do an implicit wait :-)
1609 # else
1610  // Enable GCLK and select GCLK0 (F_CPU) as clock for TC4 and TC5
1611  REG_GCLK_CLKCTRL = (uint16_t)(GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | IR_SAMD_TIMER_ID);
1612  while (GCLK->STATUS.bit.SYNCBUSY == 1)
1613  ;
1614 
1615  // The TC should be disabled before the TC is reset in order to avoid undefined behavior.
1616  TC->CTRLA.reg &= ~TC_CTRLA_ENABLE;
1617  // When write-synchronization is ongoing for a register, any subsequent write attempts to this register will be discarded, and an error will be reported.
1618  while (TC->STATUS.bit.SYNCBUSY == 1)
1619  ; // wait for sync to ensure that we can write again to COUNT16.CTRLA.reg
1620  // Reset TCx
1621  TC->CTRLA.reg = TC_CTRLA_SWRST;
1622  // When writing a 1 to the CTRLA.SWRST bit it will immediately read as 1.
1623  while (TC->CTRLA.bit.SWRST)
1624  ; // CTRL.SWRST will be cleared by hardware when the peripheral has been reset.
1625 
1626  // SAMD51 has F_CPU = 48 MHz
1627  TC->CC[0].reg = ((MICROS_PER_TICK * (F_CPU / MICROS_IN_ONE_SECOND)) / 16) - 1; // (150 - 1);
1628 
1629  /*
1630  * Set timer counter mode to 16 bits, set mode as match frequency, prescaler is DIV16 => 3 MHz clock, start counter
1631  */
1632  TC->CTRLA.reg |= TC_CTRLA_MODE_COUNT16 | TC_CTRLA_WAVEGEN_MFRQ | TC_CTRLA_PRESCALER_DIV16 | TC_CTRLA_ENABLE;
1633 
1634 # endif
1635  // Configure interrupt request
1636  NVIC_DisableIRQ (IR_SAMD_TIMER_IRQ);
1637  NVIC_ClearPendingIRQ(IR_SAMD_TIMER_IRQ);
1638  NVIC_SetPriority(IR_SAMD_TIMER_IRQ, 0);
1639  NVIC_EnableIRQ(IR_SAMD_TIMER_IRQ);
1640 
1641  // Enable the compare interrupt
1642  TC->INTENSET.bit.MC0 = 1;
1643 }
1644 
1645 # if !defined(DISABLE_CODE_FOR_RECEIVER)
1646 # if defined(__SAMD51__)
1647 void TC5_Handler(void) {
1648  TcCount16 *TC = (TcCount16*) IR_SAMD_TIMER;
1649  // Check for right interrupt bit
1650  if (TC->INTFLAG.bit.MC0 == 1) {
1651  // reset bit for next turn
1652  TC->INTFLAG.bit.MC0 = 1;
1654  }
1655 }
1656 # else
1657 void TC3_Handler(void) {
1658  TcCount16 *TC = (TcCount16*) IR_SAMD_TIMER;
1659  // Check for right interrupt bit
1660  if (TC->INTFLAG.bit.MC0 == 1) {
1661  // reset bit for next turn
1662  TC->INTFLAG.bit.MC0 = 1;
1664  }
1665 }
1666 # endif // defined(__SAMD51__)
1667 # endif // !defined(DISABLE_CODE_FOR_RECEIVER)
1668 
1669 /***************************************
1670  * Mbed based boards
1671  ***************************************/
1672 #elif defined(ARDUINO_ARCH_MBED) // Arduino Nano 33 BLE + Sparkfun Apollo3 + Nano RP2040 Connect
1673 #include "mbed.h"
1674 mbed::Ticker s50usTimer;
1675 
1676 // Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
1677 # if defined(ISR)
1678 #undef ISR
1679 # endif
1680 
1682  s50usTimer.attach(IRReceiveTimerInterruptHandler, std::chrono::microseconds(MICROS_PER_TICK));
1683 }
1685  s50usTimer.detach();
1686 }
1687 
1688 void timerConfigForReceive() {
1689  s50usTimer.attach(IRReceiveTimerInterruptHandler, std::chrono::microseconds(MICROS_PER_TICK));
1690 }
1691 
1692 # if defined(SEND_PWM_BY_TIMER)
1693 #include "pins_arduino.h" // for digitalPinToPinName()
1694 
1695 # if defined(IR_SEND_PIN)
1696 mbed::PwmOut sPwmOutForSendPWM(digitalPinToPinName(IR_SEND_PIN));
1697 # else
1698 mbed::PwmOut sPwmOutForSendPWM(digitalPinToPinName(IrSender.sendPin));
1699 # endif
1700 uint8_t sIROutPuseWidth;
1701 
1702 void enableSendPWMByTimer() {
1703  sPwmOutForSendPWM.pulsewidth_us(sIROutPuseWidth);
1704 }
1705 //void enableSendPWMByTimer() { sPwmOutForSendPWM.resume(); sPwmOutForSendPWM.pulsewidth_us(sIROutPuseWidth);}
1706 //void disableSendPWMByTimer() { sPwmOutForSendPWM.suspend();} // this kills pulsewidth_us value and does not set output level to LOW
1707 
1708 void disableSendPWMByTimer() {
1709  sPwmOutForSendPWM.pulsewidth_us(0); // this also sets output level to LOW :-)
1710 }
1711 
1712 /*
1713  * timerConfigForSend() is used exclusively by IRsend::enableIROut()
1714  * Set output pin mode and disable receive interrupt if it uses the same resource
1715  */
1716 void timerConfigForSend(uint16_t aFrequencyKHz) {
1717  sPwmOutForSendPWM.period_us(1000 / aFrequencyKHz); // 26.315 for 38 kHz
1718  sIROutPuseWidth = (1000 * IR_SEND_DUTY_CYCLE_PERCENT) / (aFrequencyKHz * 100);
1719 }
1720 # endif // defined(SEND_PWM_BY_TIMER)
1721 
1722 /*************************************************************************************************************************************
1723  * RP2040 based boards for pico core
1724  * https://github.com/earlephilhower/arduino-pico
1725  * https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
1726  * Can use any pin for PWM, no timer restrictions
1727  *************************************************************************************************************************************/
1728 #elif defined(ARDUINO_ARCH_RP2040) // Raspberry Pi Pico, Adafruit Feather RP2040, etc.
1729 #include "pico/time.h"
1730 
1731 repeating_timer_t s50usTimer;
1732 
1733 // Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
1734 # if defined(ISR)
1735 #undef ISR
1736 # endif
1737 
1738 // The timer callback has a parameter and a return value
1739 bool IRTimerInterruptHandlerHelper(repeating_timer_t*) {
1741  return true;
1742 }
1743 
1745  add_repeating_timer_us(-(MICROS_PER_TICK), IRTimerInterruptHandlerHelper, NULL, &s50usTimer);
1746 }
1748  cancel_repeating_timer(&s50usTimer);
1749 }
1750 
1751 void timerConfigForReceive() {
1752  // no need for initializing timer at setup()
1753 }
1754 
1755 # if defined(SEND_PWM_BY_TIMER)
1756 #include "hardware/pwm.h"
1757 
1758 uint sSliceNumberForSendPWM;
1759 uint sChannelNumberForSendPWM;
1760 uint sIROutPuseWidth;
1761 
1762 /*
1763  * If we just disable the PWM, the counter stops and the output stays at the state is currently has
1764  */
1765 void enableSendPWMByTimer() {
1766  pwm_set_counter(sSliceNumberForSendPWM, 0);
1767  pwm_set_chan_level(sSliceNumberForSendPWM, sChannelNumberForSendPWM, sIROutPuseWidth);
1768 }
1769 void disableSendPWMByTimer() {
1770  pwm_set_chan_level(sSliceNumberForSendPWM, sChannelNumberForSendPWM, 0); // this sets output also to LOW
1771 }
1772 
1773 /*
1774  * timerConfigForSend() is used exclusively by IRsend::enableIROut()
1775  * Set output pin mode and disable receive interrupt if it uses the same resource
1776  */
1777 void timerConfigForSend(uint16_t aFrequencyKHz) {
1778 # if defined(IR_SEND_PIN)
1779  gpio_set_function(IR_SEND_PIN, GPIO_FUNC_PWM);
1780  // Find out which PWM slice is connected to IR_SEND_PIN
1781  sSliceNumberForSendPWM = pwm_gpio_to_slice_num(IR_SEND_PIN);
1782  sChannelNumberForSendPWM = pwm_gpio_to_channel(IR_SEND_PIN);
1783 # else
1784  gpio_set_function(IrSender.sendPin, GPIO_FUNC_PWM);
1785  // Find out which PWM slice is connected to IR_SEND_PIN
1786  sSliceNumberForSendPWM = pwm_gpio_to_slice_num(IrSender.sendPin);
1787  sChannelNumberForSendPWM = pwm_gpio_to_channel(IrSender.sendPin);
1788 # endif
1789  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)
1790 
1791  pwm_config tPWMConfig = pwm_get_default_config();
1792  pwm_config_set_wrap(&tPWMConfig, tPWMWrapValue - 1);
1793  pwm_init(sSliceNumberForSendPWM, &tPWMConfig, false); // we do not want to send now
1794  sIROutPuseWidth = ((tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT) / 100) - 1; // 985.84 for 38 kHz
1795  pwm_set_chan_level(sSliceNumberForSendPWM, sChannelNumberForSendPWM, 0);
1796  pwm_set_enabled(sSliceNumberForSendPWM, true);
1797 }
1798 # endif // defined(SEND_PWM_BY_TIMER)
1799 
1800 /***************************************
1801  * NRF5 boards like the BBC:Micro
1802  ***************************************/
1803 #elif defined(NRF5) || defined(ARDUINO_ARCH_NRF52840) || defined(ARDUINO_ARCH_NRF52)
1804 # if defined(SEND_PWM_BY_TIMER)
1805 #error PWM generation by hardware not implemented for NRF5
1806 # endif
1807 
1809  NVIC_EnableIRQ (TIMER2_IRQn);
1810 }
1812  NVIC_DisableIRQ (TIMER2_IRQn);
1813 }
1814 
1815 // Undefine ISR, because we call the plain function IRReceiveTimerInterruptHandler()
1816 # if defined(ISR)
1817 #undef ISR
1818 # endif
1819 
1820 void timerConfigForReceive() {
1821  NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer; // Set the timer in Timer Mode
1822  NRF_TIMER2->TASKS_CLEAR = 1; // clear the task first to be usable for later
1823  NRF_TIMER2->PRESCALER = 4; // f TIMER = 16 MHz / (2 ^ PRESCALER ) : 4 -> 1 MHz, 1 uS
1824  NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit; //Set counter to 16 bit resolution
1825  NRF_TIMER2->CC[0] = MICROS_PER_TICK; //Set value for TIMER2 compare register 0, to trigger every 50 uS
1826  NRF_TIMER2->CC[1] = 0; //Set value for TIMER2 compare register 1
1827 
1828  // Enable interrupt on Timer 2, for CC[0] compare match events
1829  NRF_TIMER2->INTENSET = (TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos);
1830  NRF_TIMER2->TASKS_START = 1; // Start TIMER2
1831 
1832  // timerAttachInterrupt(timer, &IRTimerInterruptHandler, 1);
1833 }
1834 
1835 #if !defined(DISABLE_CODE_FOR_RECEIVER)
1836 
1839 extern "C" {
1840 void TIMER2_IRQHandler(void) {
1841  // Interrupt Service Routine - Fires every 50uS
1842  if ((NRF_TIMER2->EVENTS_COMPARE[0] != 0) && ((NRF_TIMER2->INTENSET & TIMER_INTENSET_COMPARE0_Msk) != 0)) {
1843  NRF_TIMER2->EVENTS_COMPARE[0] = 0; //Clear compare register 0 event
1844  IRReceiveTimerInterruptHandler(); // call the IR-receive function
1845  NRF_TIMER2->CC[0] += 50;
1846  }
1847 }
1848 }
1849 #endif
1850 
1851 /**********************************************************************************************************************
1852  * BluePill in 2 flavors see https://samuelpinches.com.au/3d-printer/cutting-through-some-confusion-on-stm32-and-arduino/
1853  *
1854  * Recommended original Arduino_STM32 by Roger Clark.
1855  * http://dan.drown.org/stm32duino/package_STM32duino_index.json
1856  * STM32F1 architecture for "Generic STM32F103C series" from "STM32F1 Boards (Arduino_STM32)" of Arduino Board manager
1857  **********************************************************************************************************************/
1858 #elif defined(__STM32F1__) || defined(ARDUINO_ARCH_STM32F1)
1859 #include <HardwareTimer.h> // 4 timers and 4. timer (4.channel) is used for tone()
1860 # if defined(SEND_PWM_BY_TIMER)
1861 #error PWM generation by hardware not implemented for STM32
1862 # endif
1863 
1864 /*
1865  * Use timer 3 as IR timer.
1866  * Timer 3 blocks PA6, PA7, PB0, PB1, so if you require one of them as tone() or Servo output, you must choose another timer.
1867  */
1868 HardwareTimer s50usTimer(3);
1869 
1871  s50usTimer.resume();
1872 }
1874  s50usTimer.pause();
1875 }
1876 
1877 // Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
1878 # if defined(ISR)
1879 #undef ISR
1880 # endif
1881 
1882 void timerConfigForReceive() {
1883  s50usTimer.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE);
1884  s50usTimer.setPrescaleFactor(1);
1885  s50usTimer.setOverflow((F_CPU / MICROS_IN_ONE_SECOND) * MICROS_PER_TICK);
1886  s50usTimer.attachInterrupt(TIMER_CH1, IRReceiveTimerInterruptHandler);
1887  s50usTimer.refresh();
1888 }
1889 
1890 /**********************************************************************************************************************
1891  * STM32duino by ST Microsystems.
1892  * https://github.com/stm32duino/Arduino_Core_STM32
1893  * https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json
1894  * stm32 architecture for "Generic STM32F1 series" from "STM32 Boards (selected from submenu)" of Arduino Board manager
1895  **********************************************************************************************************************/
1896 #elif defined(STM32F1xx) || defined(ARDUINO_ARCH_STM32)
1897 #include <HardwareTimer.h> // 4 timers and 3. timer is used for tone(), 2. for Servo
1898 # if defined(SEND_PWM_BY_TIMER)
1899 #error PWM generation by hardware not implemented for STM32
1900 # endif
1901 
1902 /*
1903  * Use timer 4 as IR timer.
1904  * Timer 4 blocks PB6, PB7, PB8, PB9, so if you need one them as tone() or Servo output, you must choose another timer.
1905  */
1906 # if defined(TIM4)
1907 HardwareTimer s50usTimer(TIM4);
1908 # else
1909 HardwareTimer s50usTimer(TIM2);
1910 # endif
1911 
1913  s50usTimer.resume();
1914 }
1916  s50usTimer.pause();
1917 }
1918 
1919 // Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
1920 # if defined(ISR)
1921 #undef ISR
1922 # endif
1923 
1924 void timerConfigForReceive() {
1925  s50usTimer.setOverflow(MICROS_PER_TICK, MICROSEC_FORMAT); // 50 uS
1926  s50usTimer.attachInterrupt(IRReceiveTimerInterruptHandler);
1927  s50usTimer.resume();
1928 }
1929 
1930 /***************************************
1931  * Particle special IntervalTimer
1932  * !!!UNTESTED!!!
1933  ***************************************/
1934 #elif defined(PARTICLE)
1935 # ifndef __INTERVALTIMER_H__
1936 #include "SparkIntervalTimer.h" // SparkIntervalTimer.h is required if PARTICLE is defined.
1937 # endif
1938 
1939 extern IntervalTimer timer;
1940 extern int ir_out_kHz;
1941 
1943  timer.begin(IRReceiveTimerInterruptHandler, MICROS_PER_TICK, uSec);
1944 }
1946  timer.end();
1947 }
1948 
1949 // Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
1950 # if defined(ISR)
1951 #undef ISR
1952 # endif
1953 
1954 void timerConfigForReceive() {
1955 }
1956 
1957 # if defined(SEND_PWM_BY_TIMER)
1958 # if defined(IR_SEND_PIN)
1959 void enableSendPWMByTimer() {
1960  analogWrite(IR_SEND_PIN, ((256L * 100) / IR_SEND_DUTY_CYCLE_PERCENT)), ir_out_kHz*1000);
1961 }
1962 void disableSendPWMByTimer() {
1963  analogWrite(IR_SEND_PIN, 0, ir_out_kHz*1000);
1964 }
1965 # else
1966 void enableSendPWMByTimer() {
1967  analogWrite(IrSender.sendPin, ((256L * 100) / IR_SEND_DUTY_CYCLE_PERCENT), ir_out_kHz * 1000);
1968 }
1969 void disableSendPWMByTimer() {
1970  analogWrite(IrSender.sendPin, 0, ir_out_kHz * 1000);
1971 }
1972 # endif
1973 
1974 
1975 /*
1976  * timerConfigForSend() is used exclusively by IRsend::enableIROut()
1977  * Set output pin mode and disable receive interrupt if it uses the same resource
1978  */
1979 void timerConfigForSend(uint16_t aFrequencyKHz) {
1981 # if defined(IR_SEND_PIN)
1982  pinMode(IR_SEND_PIN, OUTPUT);
1983 # else
1984  pinMode(IrSender.sendPin, OUTPUT);
1985 # endif
1986  ir_out_kHz = aFrequencyKHz;
1987 }
1988 # endif // defined(SEND_PWM_BY_TIMER)
1989 
1990 /***************************************
1991  * Unknown CPU board
1992  ***************************************/
1993 #else
1994 #error Internal code configuration error, no timer functions implemented for this CPU / board
1995 /*
1996  * Dummy definitions to avoid more irritating compile errors
1997  */
1998 
1999 void timerEnableReceiveInterrupt() {};
2001 
2002 # if defined(ISR)
2003 #undef ISR
2004 # endif
2005 #define ISR() void notImplemented(void)
2006 
2007 void timerConfigForReceive() {
2008 }
2009 
2010 # if defined(SEND_PWM_BY_TIMER)
2011 void enableSendPWMByTimer() {
2012 }
2013 void disableSendPWMByTimer() {
2014 }
2015 
2016 void timerConfigForSend(uint16_t aFrequencyKHz) {
2018 # if defined(IR_SEND_PIN)
2019  pinMode(IR_SEND_PIN, OUTPUT);
2020 # else
2021  pinMode(IrSender.sendPin, OUTPUT);
2022 # endif
2023  (void) aFrequencyKHz;
2024 }
2025 # endif // defined(SEND_PWM_BY_TIMER)
2026 
2027 #endif // defined(DOXYGEN / CPU_TYPES)
2028 
2031 #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:250
IRsend::sendPin
uint8_t sendPin
Definition: IRremoteInt.h:645
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:122
MICROS_IN_ONE_SECOND
#define MICROS_IN_ONE_SECOND
Definition: IRremote.hpp:254
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:243
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