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