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