2021-03-06 20:47:47 +08:00
/**
2021-09-09 21:53:50 +08:00
* @ file IRTimer . hpp
2021-03-06 20:47:47 +08:00
*
* @ brief All timer specific definitions are contained in this file .
2022-01-27 01:36:50 +08:00
* Sets IR_SEND_PIN if required , e . g . if SEND_PWM_BY_TIMER for AVR is defined , which restricts the output to a dedicated pin number
*
* timerConfigForSend ( aFrequencyKHz ) must set output pin mode and disable receive interrupt if it uses the same resource
2021-03-06 20:47:47 +08:00
*
* This file is part of Arduino - IRremote https : //github.com/Arduino-IRremote/Arduino-IRremote.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* MIT License
*
2023-03-14 06:18:40 +08:00
* Copyright ( c ) 2021 - 2023 Armin Joachimsmeyer
2021-03-06 20:47:47 +08:00
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is furnished
* to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR IMPLIED ,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY , FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN ACTION OF
* CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
2022-04-05 10:47:32 +08:00
# ifndef _IR_TIMER_HPP
# define _IR_TIMER_HPP
2021-10-07 15:25:36 +08:00
2021-03-18 04:52:41 +08:00
/** \addtogroup HardwareDependencies CPU / board dependent definitions
* @ {
*/
/** \addtogroup Timer Usage of timers for the different CPU / boards
* @ {
*/
2022-12-23 22:24:10 +08:00
/*
* Functions declared here
*/
void timerResetInterruptPending ( ) ;
void timerEnableReceiveInterrupt ( ) ;
void timerDisableReceiveInterrupt ( ) ;
void timerConfigForReceive ( ) ;
void enableSendPWMByTimer ( ) ;
void disableSendPWMByTimer ( ) ;
2023-03-29 19:28:06 +08:00
void timerConfigForSend ( uint16_t aFrequencyKHz ) ;
2022-01-27 01:36:50 +08:00
2024-01-01 06:53:49 +08:00
// SEND_PWM_BY_TIMER is defined in IRremote.hpp line 195.
# if defined(SEND_PWM_BY_TIMER) && ( (defined(ESP32) || defined(ARDUINO_ARCH_RP2040) || defined(PARTICLE)) || defined(ARDUINO_ARCH_MBED) )
# define SEND_PWM_DOES_NOT_USE_RECEIVE_TIMER // Receive timer and send generation timer are independent here.
2022-05-21 00:54:51 +08:00
# endif
2024-01-01 06:53:49 +08:00
# 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
# undef IR_SEND_PIN // To avoid "warning: "IR_SEND_PIN" redefined". The user warning is done at IRremote.hpp line 202.
2021-03-09 08:31:31 +08:00
# endif
2021-03-06 20:47:47 +08:00
2022-12-23 22:24:10 +08:00
// Macros for enabling timers for development
//#define SEND_PWM_BY_TIMER
//#define IR_USE_AVR_TIMER1
//#define IR_USE_AVR_TIMER2
//#define IR_USE_AVR_TIMER3
//#define IR_USE_AVR_TIMER4
//#define IR_USE_AVR_TIMER4_HS
//#define IR_USE_AVR_TIMER5
//#define IR_USE_AVR_TIMER_TINY0
//#define IR_USE_AVR_TIMER_TINY1
//#define IR_USE_AVR_TIMER_A
//#define IR_USE_AVR_TIMER_B
//#define IR_USE_AVR_TIMER_D
//#define __MK20DX128__
//#define __MKL26Z64__
//#define __IMXRT1062__
//#define ESP8266
//#define ESP32
//#define ARDUINO_ARCH_SAMD
//#define ARDUINO_ARCH_MBED
//#define ARDUINO_ARCH_RP2040
//#define NRF5
//#define __STM32F1__
//#define STM32F1xx
//#define PARTICLE
2023-07-27 04:15:40 +08:00
//#define ARDUINO_ARCH_RENESAS
2022-12-23 22:24:10 +08:00
2021-03-18 04:52:41 +08:00
# if defined (DOXYGEN)
2021-03-06 20:47:47 +08:00
/**
2021-03-18 04:52:41 +08:00
* Hardware / timer dependent pin number for sending IR if SEND_PWM_BY_TIMER is defined . Otherwise used as default for IrSender . sendPin .
2021-03-06 20:47:47 +08:00
*/
# define IR_SEND_PIN
2022-12-30 01:46:09 +08:00
/**
* Configures the timer to be able to generate the receive sample interrupt ,
* which consumes a small amount of CPU every 50 ( MICROS_PER_TICK ) us .
* The actual interrupt generation is controlled by timerEnableReceiveInterrupt ( ) and timerDisableReceiveInterrupt ( ) .
* timerConfigForReceive ( ) is used exclusively by IRrecv : : start ( )
*/
void timerConfigForReceive ( ) {
}
/**
* Enables the receive sample timer interrupt , which consumes a small amount of CPU every 50 us .
*/
void timerEnableReceiveInterrupt ( ) {
}
/**
* Disables the receive sample timer interrupt . This must be done before using the timer for e . g . tone ( ) .
* Is a synonym for calling end ( ) or stop ( ) .
*/
void timerDisableReceiveInterrupt ( ) {
}
/**
* IF PWM should be generated not by software , but by a timer , this function sets output pin mode ,
* configures the timer for generating a PWM with duty cycle of IR_SEND_DUTY_CYCLE_PERCENT
* and disables the receive interrupt if it uses the same resource .
* For most architectures , the pin number ( s ) which can be used for output is determined by the timer used !
* The output of the PWM signal is controlled by enableSendPWMByTimer ( ) and disableSendPWMByTimer ( ) .
* timerConfigForSend ( ) is used exclusively by IRsend : : enableIROut ( ) .
* @ param aFrequencyKHz Frequency of the sent PWM signal in kHz . There is no practical reason to have a sub kHz resolution for sending frequency : - ) .
*/
2023-03-29 19:28:06 +08:00
void timerConfigForSend ( uint16_t aFrequencyKHz ) {
2022-12-30 01:46:09 +08:00
}
/**
* Enables output of the PWM signal of the timer at the timer pin .
*/
void enableSendPWMByTimer ( ) {
}
/**
* Disables output of the PWM signal of the timer at the timer pin and set it to inactive .
*/
void disableSendPWMByTimer ( ) {
}
2021-03-06 20:47:47 +08:00
# elif defined(__AVR__)
/**********************************************************************************************************************
* Mapping of AVR boards to AVR timers
* For some CPU ' s you have the option to switch the timer and the hardware send pin
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/***************************************
* Plain AVR CPU ' s , no boards
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Arduino Duemilanove, Diecimila, LilyPad, Mini, Fio, Nano, etc
2022-12-23 22:24:10 +08:00
# if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) || defined(__AVR_ATmega168__) \
2023-01-08 09:00:37 +08:00
| | defined ( __AVR_ATmega88P__ ) | | defined ( __AVR_ATmega88PB__ )
2021-03-06 20:47:47 +08:00
# if !defined(IR_USE_AVR_TIMER1) && !defined(IR_USE_AVR_TIMER2)
//#define IR_USE_AVR_TIMER1 // send pin = pin 9
# define IR_USE_AVR_TIMER2 // send pin = pin 3
# endif
// Arduino Mega
# elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
# 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)
//#define IR_USE_AVR_TIMER1 // send pin = pin 11
# define IR_USE_AVR_TIMER2 // send pin = pin 9
//#define IR_USE_AVR_TIMER3 // send pin = pin 5
//#define IR_USE_AVR_TIMER4 // send pin = pin 6
//#define IR_USE_AVR_TIMER5 // send pin = pin 46
# endif
// Leonardo
# elif defined(__AVR_ATmega32U4__) && ! defined(TEENSYDUINO) && ! defined(ARDUINO_AVR_PROMICRO)
# if !defined(IR_USE_AVR_TIMER1) && !defined(IR_USE_AVR_TIMER3) && !defined(IR_USE_AVR_TIMER4_HS)
//#define IR_USE_AVR_TIMER1 // send pin = pin 9
# define IR_USE_AVR_TIMER3 // send pin = pin 5
//#define IR_USE_AVR_TIMER4_HS // send pin = pin 13
# endif
2021-04-27 03:57:55 +08:00
// Nano Every, Uno WiFi Rev2 and similar
# elif defined(__AVR_ATmega808__) || defined(__AVR_ATmega809__) || defined(__AVR_ATmega3208__) || defined(__AVR_ATmega3209__) \
| | defined ( __AVR_ATmega1608__ ) | | defined ( __AVR_ATmega1609__ ) | | defined ( __AVR_ATmega4808__ ) | | defined ( __AVR_ATmega4809__ ) | | defined ( __AVR_ATtiny1604__ )
2021-03-06 20:47:47 +08:00
# if !defined(IR_USE_AVR_TIMER_B)
2021-12-02 04:45:53 +08:00
# define IR_USE_AVR_TIMER_B // send pin = pin 6 on ATmega4809 1 on ATmega4809
2021-03-06 20:47:47 +08:00
# endif
2022-12-12 20:53:43 +08:00
# elif defined(__AVR_ATtiny816__) || defined(__AVR_ATtiny1614__) || defined(__AVR_ATtiny1616__) || defined(__AVR_ATtiny3216__) || defined(__AVR_ATtiny3217__) // e.g. TinyCore boards
2022-02-01 07:52:17 +08:00
# if !defined(IR_USE_AVR_TIMER_A) && !defined(IR_USE_AVR_TIMER_D)
2023-11-03 05:03:25 +08:00
# define IR_USE_AVR_TIMER_A // use this if you use megaTinyCore, Tone is on TCB and millis() on TCD
2022-02-01 07:52:17 +08:00
//#define IR_USE_AVR_TIMER_D // use this if you use TinyCore
# endif
2023-01-14 03:30:46 +08:00
// ATmega8u2, ATmega16U2, ATmega32U2, ATmega8 - Timer 2 does not work with existing code below
2023-01-08 09:00:37 +08:00
# elif defined(__AVR_ATmega8U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega8__)
2021-03-06 20:47:47 +08:00
# if !defined(IR_USE_AVR_TIMER1)
# define IR_USE_AVR_TIMER1 // send pin = pin C6
# endif
// ATtiny84
2021-03-11 18:28:41 +08:00
# elif defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny88__)
2021-03-06 20:47:47 +08:00
# if !defined(IR_USE_AVR_TIMER1)
# define IR_USE_AVR_TIMER1 // send pin = pin 6
# endif
2021-06-21 06:32:42 +08:00
# elif defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
# if !defined(IR_USE_AVR_TIMER1)
2021-07-28 04:34:30 +08:00
# define IR_USE_AVR_TIMER1 // send pin = pin PB1 / 8
2021-06-21 06:32:42 +08:00
# endif
2021-07-28 04:34:30 +08:00
# define USE_TIMER_CHANNEL_B
2021-06-21 06:32:42 +08:00
2022-01-12 21:59:56 +08:00
//ATtiny85, 45, 25
# elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
2021-03-06 20:47:47 +08:00
# if !defined(IR_USE_AVR_TIMER_TINY0) && !defined(IR_USE_AVR_TIMER_TINY1)
2021-03-09 08:31:31 +08:00
# if defined(ARDUINO_AVR_DIGISPARK) // tested with 16 and 8 MHz
# define IR_USE_AVR_TIMER_TINY0 // send pin = pin 1
// standard Digispark settings use timer 1 for millis() and micros()
# else
// standard ATTinyCore settings use timer 0 for millis() and micros()
2021-03-06 20:47:47 +08:00
# define IR_USE_AVR_TIMER_TINY1 // send pin = pin 4
2021-03-09 08:31:31 +08:00
# endif
2021-03-06 20:47:47 +08:00
# endif
/***************************************
* SPARKFUN Pro Micro board
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# elif defined(ARDUINO_AVR_PROMICRO)
# if !defined(IR_USE_AVR_TIMER1) && !defined(IR_USE_AVR_TIMER3) && !defined(IR_USE_AVR_TIMER4_HS)
//#define IR_USE_AVR_TIMER1 // send pin = pin 9
# define IR_USE_AVR_TIMER3 // send pin = pin 5
//#define IR_USE_AVR_TIMER4_HS // send pin = pin 13
# endif
/***************************************
* TEENSY Boards
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Teensy 1.0
# elif defined(__AVR_AT90USB162__)
# if !defined(IR_USE_AVR_TIMER1)
# define IR_USE_AVR_TIMER1 // send pin = pin 17
# endif
// Teensy++ 1.0 & 2.0
# elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
# if !defined(IR_USE_AVR_TIMER1) && !defined(IR_USE_AVR_TIMER2) && !defined(IR_USE_AVR_TIMER3)
//#define IR_USE_AVR_TIMER1 // send pin = pin 25
# define IR_USE_AVR_TIMER2 // send pin = pin 1
//#define IR_USE_AVR_TIMER3 // send pin = pin 16
# endif
// Teensy 2.0
# elif defined(__AVR_ATmega32U4__) && defined(TEENSYDUINO)
# if !defined(IR_USE_AVR_TIMER1) && !defined(IR_USE_AVR_TIMER3) && !defined(IR_USE_AVR_TIMER4_HS)
//#define IR_USE_AVR_TIMER1 // send pin = pin 14 (Teensy 2.0 - physical pin: B5)
2021-12-22 04:51:28 +08:00
//#define IR_USE_AVR_TIMER3 // send pin = pin 9 (Teensy 2.0 - physical pin: C6)
# define IR_USE_AVR_TIMER4_HS // send pin = pin 10 (Teensy 2.0 - physical pin: C7)
2021-03-06 20:47:47 +08:00
# endif
/***************************************
* CPU ' s with MegaCore
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// MegaCore - ATmega64, ATmega128
# elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2560__)
# if !defined(IR_USE_AVR_TIMER1)
# define IR_USE_AVR_TIMER1 // send pin = pin 13
# endif
/***************************************
* CPU ' s with MajorCore
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# elif defined(__AVR_ATmega8515__) || defined(__AVR_ATmega162__)
# if !defined(IR_USE_AVR_TIMER1) && !defined(IR_USE_AVR_TIMER3)
# define IR_USE_AVR_TIMER1 // send pin = pin 13
//#define IR_USE_AVR_TIMER3 // send pin = pin 12 - ATmega162 only
# endif
/***************************************
* CPU ' s with MightyCore
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// MightyCore - ATmega1284
# elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
# if !defined(IR_USE_AVR_TIMER1) && !defined(IR_USE_AVR_TIMER2) && !defined(IR_USE_AVR_TIMER3)
//#define IR_USE_AVR_TIMER1 // send pin = pin 13
# define IR_USE_AVR_TIMER2 // send pin = pin 14
//#define IR_USE_AVR_TIMER3 // send pin = pin 6
# endif
// MightyCore - ATmega164, ATmega324, ATmega644
# elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) \
| | defined ( __AVR_ATmega324P__ ) | | defined ( __AVR_ATmega324A__ ) \
| | defined ( __AVR_ATmega324PA__ ) | | defined ( __AVR_ATmega164A__ ) \
| | defined ( __AVR_ATmega164P__ )
# if !defined(IR_USE_AVR_TIMER1) && !defined(IR_USE_AVR_TIMER2)
//#define IR_USE_AVR_TIMER1 // send pin = pin 13
# define IR_USE_AVR_TIMER2 // send pin = pin 14
# endif
// MightyCore - ATmega8535, ATmega16, ATmega32
# elif defined(__AVR_ATmega8535__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__)
# if !defined(IR_USE_AVR_TIMER1)
# define IR_USE_AVR_TIMER1 // send pin = pin 13
# endif
# endif // AVR CPU's
/**********************************************************************************************************************
* End of AVR mapping , start of AVR timers
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* AVR Timer1 ( 16 bits )
*/
# if defined(IR_USE_AVR_TIMER1)
2022-01-27 01:36:50 +08:00
2022-12-23 22:24:10 +08:00
# if defined(TIMSK1)
2023-01-08 09:00:37 +08:00
# define TIMSK TIMSK1 // use the value of TIMSK1 for the statements below
# endif
2022-12-23 22:24:10 +08:00
void timerEnableReceiveInterrupt ( ) {
TIMSK | = _BV ( OCIE1A ) ;
}
void timerDisableReceiveInterrupt ( ) {
TIMSK & = ~ _BV ( OCIE1A ) ;
}
2022-01-27 01:36:50 +08:00
# if defined(USE_TIMER_CHANNEL_B)
# if defined(TIMER1_COMPB_vect)
# define TIMER_INTR_NAME TIMER1_COMPB_vect
# elif defined(TIM1_COMPB_vect)
# define TIMER_INTR_NAME TIM1_COMPB_vect
# endif
# else
# if defined(TIMER1_COMPA_vect)
# define TIMER_INTR_NAME TIMER1_COMPA_vect
# elif defined(TIM1_COMPA_vect)
# define TIMER_INTR_NAME TIM1_COMPA_vect
# endif
# endif
void timerConfigForReceive ( ) {
TCCR1A = 0 ;
2022-08-06 20:39:28 +08:00
TCCR1B = _BV ( WGM12 ) | _BV ( CS10 ) ; // CTC mode, no prescaling
OCR1A = ( F_CPU * MICROS_PER_TICK ) / MICROS_IN_ONE_SECOND ; // 16 * 50 = 800
2022-01-27 01:36:50 +08:00
TCNT1 = 0 ;
}
2021-03-11 18:28:41 +08:00
# if defined(SEND_PWM_BY_TIMER)
# if defined(CORE_OC1A_PIN)
2021-03-06 20:47:47 +08:00
# define IR_SEND_PIN CORE_OC1A_PIN // Teensy
2021-03-11 18:28:41 +08:00
# elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
2021-03-06 20:47:47 +08:00
# define IR_SEND_PIN 11 // Arduino Mega
2021-03-09 04:38:06 +08:00
// MightyCore, MegaCore, MajorCore
2021-03-11 18:28:41 +08:00
# elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) \
2021-03-06 20:47:47 +08:00
| | defined ( __AVR_ATmega644__ ) | | defined ( __AVR_ATmega644P__ ) \
| | defined ( __AVR_ATmega324P__ ) | | defined ( __AVR_ATmega324A__ ) \
| | defined ( __AVR_ATmega324PA__ ) | | defined ( __AVR_ATmega164A__ ) \
| | defined ( __AVR_ATmega164P__ ) | | defined ( __AVR_ATmega32__ ) \
| | defined ( __AVR_ATmega16__ ) | | defined ( __AVR_ATmega8535__ ) \
| | defined ( __AVR_ATmega64__ ) | | defined ( __AVR_ATmega128__ ) \
| | defined ( __AVR_ATmega1281__ ) | | defined ( __AVR_ATmega2561__ ) \
| | defined ( __AVR_ATmega8515__ ) | | defined ( __AVR_ATmega162__ )
2021-03-09 04:38:06 +08:00
# define IR_SEND_PIN 13
2021-03-06 20:47:47 +08:00
2021-03-11 18:28:41 +08:00
# elif defined(__AVR_ATtiny84__)
2021-06-21 06:32:42 +08:00
# define IR_SEND_PIN 6
2021-07-27 21:03:49 +08:00
# elif defined(__AVR_ATtiny88__)
# define IR_SEND_PIN 8
2021-06-21 06:32:42 +08:00
# elif defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
2022-12-12 23:10:52 +08:00
/*
* ! ! ! IR_SEND_PIN value must correspond to ENABLE_SEND_PWM_BY_TIMER below ! ! !
*/
# if defined(USE_TIMER_CHANNEL_B)
# define IR_SEND_PIN PIN_PB1 // OC1BU / PB1 / Pin9 at ATTinyCore
//#define IR_SEND_PIN PIN_PB3 // OC1BV / PB3 / Pin11 at ATTinyCore
//#define IR_SEND_PIN PIN_PB5 // OC1BW / PB5 / Pin13 at ATTinyCore
//#define IR_SEND_PIN PIN_PB7 // OC1BX / PB7 / Pin15 at ATTinyCore
# else
# define IR_SEND_PIN PIN_PB0 // OC1AU / PB1 / Pin8 at ATTinyCore
//#define IR_SEND_PIN PIN_PB2 // OC1AV / PB3 / Pin10 at ATTinyCore
//#define IR_SEND_PIN PIN_PB4 // OC1AW / PB5 / Pin12 at ATTinyCore
//#define IR_SEND_PIN PIN_PB6 // OC1AX / PB6 / Pin14 at ATTinyCore
# endif
2021-03-06 20:47:47 +08:00
2021-03-11 18:28:41 +08:00
# else
# define IR_SEND_PIN 9 // OC1A Arduino Duemilanove, Diecimila, LilyPad, Sparkfun Pro Micro, Leonardo, MH-ET Tiny88 etc.
# endif // defined(CORE_OC1A_PIN)
2021-03-06 20:47:47 +08:00
2021-06-21 06:32:42 +08:00
# if defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
2022-12-14 01:40:50 +08:00
// Clear OC1A/OC1B on Compare Match when up-counting. Set OC1A/OC1B on Compare Match when down counting.
2022-12-12 23:10:52 +08:00
# if defined(USE_TIMER_CHANNEL_B)
2022-12-23 22:24:10 +08:00
void enableSendPWMByTimer ( ) {
TCNT1 = 0 ;
TCCR1A | = _BV ( COM1B1 ) ;
TCCR1D | = _BV ( OC1BU ) ; // + enable OC1BU as output
//TCNT1 = 0; TCCR1A |= _BV(COM1B1); TCCR1D |= _BV(OC1BV); // + enable OC1BV as output
//TCNT1 = 0; TCCR1A |= _BV(COM1B1); TCCR1D |= _BV(OC1BW); // + enable OC1BW as output
//TCNT1 = 0; TCCR1A |= _BV(COM1B1); TCCR1D |= _BV(OC1BX); // + enable OC1BX as output
}
2022-12-12 23:10:52 +08:00
# else
2022-12-23 22:24:10 +08:00
void disableSendPWMByTimer ( ) {
TCNT1 = 0 ;
TCCR1A | = _BV ( COM1A1 ) ;
TCCR1D | = _BV ( OC1AU ) ; // + enable OC1BU as output
//TCNT1 = 0; TCCR1A |= _BV(COM1A1); TCCR1D |= _BV(OC1AV); // + enable OC1BV as output
//TCNT1 = 0; TCCR1A |= _BV(COM1A1); TCCR1D |= _BV(OC1AW); // + enable OC1BW as output
//TCNT1 = 0; TCCR1A |= _BV(COM1A1); TCCR1D |= _BV(OC1AX); // + enable OC1BX as output
}
2022-12-12 23:10:52 +08:00
# endif
2022-12-23 22:24:10 +08:00
void disableSendPWMByTimer ( ) {
TCCR1D = 0 ;
}
2021-06-21 06:32:42 +08:00
# else
2022-12-12 23:10:52 +08:00
# if defined(USE_TIMER_CHANNEL_B)
2022-12-23 22:24:10 +08:00
void enableSendPWMByTimer ( ) {
2023-08-08 03:45:57 +08:00
TCNT1 = 0 ;
TCCR1A | = _BV ( COM1B1 ) ; // Clear OC1A/OC1B on Compare Match when up-counting. Set OC1A/OC1B on Compare Match when counting down.
2022-12-23 22:24:10 +08:00
}
void disableSendPWMByTimer ( ) {
TCCR1A & = ~ ( _BV ( COM1B1 ) ) ;
}
2022-12-12 23:10:52 +08:00
# else
2022-12-23 22:24:10 +08:00
void enableSendPWMByTimer ( ) {
TCNT1 = 0 ;
TCCR1A | = _BV ( COM1A1 ) ; // Clear OC1A/OC1B on Compare Match when up-counting. Set OC1A/OC1B on Compare Match when downcounting.
}
void disableSendPWMByTimer ( ) {
TCCR1A & = ~ ( _BV ( COM1A1 ) ) ;
}
2022-12-12 23:10:52 +08:00
# endif
2021-06-21 06:32:42 +08:00
# endif
2021-03-06 20:47:47 +08:00
2022-01-27 01:36:50 +08:00
/*
* timerConfigForSend ( ) is used exclusively by IRsend : : enableIROut ( )
* Set output pin mode and disable receive interrupt if it uses the same resource
*/
2023-03-29 19:28:06 +08:00
void timerConfigForSend ( uint16_t aFrequencyKHz ) {
2022-12-23 22:24:10 +08:00
timerDisableReceiveInterrupt ( ) ;
2022-01-27 01:36:50 +08:00
2021-04-11 19:16:53 +08:00
# if (((F_CPU / 2000) / 38) < 256)
2022-01-27 01:36:50 +08:00
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
2022-12-23 22:24:10 +08:00
TCCR1A = _BV ( WGM11 ) ; // PWM, Phase Correct, Top is ICR1
TCCR1B = _BV ( WGM13 ) | _BV ( CS10 ) ; // CS10 -> no prescaling
2022-01-27 01:36:50 +08:00
ICR1 = tPWMWrapValue - 1 ;
2021-06-21 06:32:42 +08:00
# if defined(USE_TIMER_CHANNEL_B)
2022-12-12 23:10:52 +08:00
OCR1B = ( ( tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT ) / 100 ) - 1 ;
2021-06-21 06:32:42 +08:00
# else
2022-01-27 01:36:50 +08:00
OCR1A = ( ( tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT ) / 100 ) - 1 ;
2021-06-21 06:32:42 +08:00
# endif
2022-01-27 01:36:50 +08:00
TCNT1 = 0 ; // not really required, since we have an 8 bit counter, but makes the signal more reproducible
2021-04-11 19:16:53 +08:00
# else
2022-01-27 01:36:50 +08:00
const uint16_t tPWMWrapValue = ( ( F_CPU / 8 ) / 2000 ) / ( aFrequencyKHz ) ; // 2000 instead of 1000 because of Phase Correct PWM
2021-04-11 19:16:53 +08:00
TCCR1A = _BV ( WGM11 ) ; // PWM, Phase Correct, Top is ICR1
TCCR1B = _BV ( WGM13 ) | _BV ( CS11 ) ; // CS11 -> Prescaling by 8
2022-01-27 01:36:50 +08:00
ICR1 = tPWMWrapValue - 1 ;
2021-06-21 06:32:42 +08:00
# if defined(USE_TIMER_CHANNEL_B)
2022-01-27 01:36:50 +08:00
OCR1A = ( ( tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT ) / 100 ) - 1 ;
2021-06-21 06:32:42 +08:00
# else
2022-01-27 01:36:50 +08:00
OCR1A = ( ( tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT ) / 100 ) - 1 ;
2021-06-21 06:32:42 +08:00
# endif
2022-01-27 01:36:50 +08:00
TCNT1 = 0 ; // not really required, since we have an 8 bit counter, but makes the signal more reproducible
2021-04-11 19:16:53 +08:00
# endif
2021-03-06 20:47:47 +08:00
}
2022-01-27 01:36:50 +08:00
# endif // defined(SEND_PWM_BY_TIMER)
2021-03-06 20:47:47 +08:00
/*
2023-08-05 17:26:17 +08:00
* AVR Timer2 ( 8 bits ) // Tone timer on Uno
2021-03-06 20:47:47 +08:00
*/
# elif defined(IR_USE_AVR_TIMER2)
2022-01-27 01:36:50 +08:00
2022-12-23 22:24:10 +08:00
void timerEnableReceiveInterrupt ( ) {
TIMSK2 = _BV ( OCIE2B ) ; // Output Compare Match A Interrupt Enable
}
void timerDisableReceiveInterrupt ( ) {
TIMSK2 = 0 ;
}
2022-01-27 01:36:50 +08:00
# define TIMER_INTR_NAME TIMER2_COMPB_vect // We use TIMER2_COMPB_vect to be compatible with tone() library
# define TIMER_COUNT_TOP (F_CPU * MICROS_PER_TICK / MICROS_IN_ONE_SECOND)
2022-12-30 01:46:09 +08:00
2022-01-27 01:36:50 +08:00
void timerConfigForReceive ( ) {
# if (TIMER_COUNT_TOP < 256)
TCCR2A = _BV ( WGM21 ) ;
TCCR2B = _BV ( CS20 ) ;
OCR2A = TIMER_COUNT_TOP ;
OCR2B = TIMER_COUNT_TOP ;
TCNT2 = 0 ;
# else
TCCR2A = _BV ( WGM21 ) ;
TCCR2B = _BV ( CS21 ) ;
OCR2A = TIMER_COUNT_TOP / 8 ;
OCR2B = TIMER_COUNT_TOP / 8 ;
TCNT2 = 0 ;
# endif
}
2021-03-11 18:28:41 +08:00
# if defined(SEND_PWM_BY_TIMER)
# if defined(CORE_OC2B_PIN)
2021-03-06 20:47:47 +08:00
# define IR_SEND_PIN CORE_OC2B_PIN // Teensy
2021-03-11 18:28:41 +08:00
# elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
2021-03-06 20:47:47 +08:00
# define IR_SEND_PIN 9 // Arduino Mega
2021-03-11 18:28:41 +08:00
# elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) \
2021-03-06 20:47:47 +08:00
| | defined ( __AVR_ATmega644__ ) | | defined ( __AVR_ATmega644P__ ) \
| | defined ( __AVR_ATmega324P__ ) | | defined ( __AVR_ATmega324A__ ) \
| | defined ( __AVR_ATmega324PA__ ) | | defined ( __AVR_ATmega164A__ ) \
| | defined ( __AVR_ATmega164P__ )
# define IR_SEND_PIN 14 // MightyCore, MegaCore
2021-03-11 18:28:41 +08:00
# else
2021-03-06 20:47:47 +08:00
# define IR_SEND_PIN 3 // Arduino Duemilanove, Diecimila, LilyPad, etc
2021-03-11 18:28:41 +08:00
# endif // defined(CORE_OC2B_PIN)
2021-03-06 20:47:47 +08:00
2022-12-23 22:24:10 +08:00
void enableSendPWMByTimer ( ) {
TCNT2 = 0 ;
TCCR2A | = _BV ( COM2B1 ) ; // Clear OC2B on Compare Match
}
void disableSendPWMByTimer ( ) {
TCCR2A & = ~ ( _BV ( COM2B1 ) ) ; // Normal port operation, OC2B disconnected.
}
2021-06-21 06:32:42 +08:00
2021-03-06 20:47:47 +08:00
/*
* timerConfigForSend ( ) is used exclusively by IRsend : : enableIROut ( )
2022-01-27 01:36:50 +08:00
* Set output pin mode and disable receive interrupt if it uses the same resource
2021-03-06 20:47:47 +08:00
*/
2023-03-29 19:28:06 +08:00
void timerConfigForSend ( uint16_t aFrequencyKHz ) {
2022-12-23 22:24:10 +08:00
timerDisableReceiveInterrupt ( ) ;
2022-01-27 01:36:50 +08:00
2021-04-11 19:16:53 +08:00
# if (((F_CPU / 2000) / 38) < 256)
2023-03-29 19:28:06 +08:00
/*
* tPWMWrapValue is 210.52 for 38 kHz , 17.58 for 455 kHz @ 16 MHz clock .
* 210 - > 38.095 kHz , 17 - > 470.588 kHz @ 16 MHz clock .
* We use 2000 instead of 1000 in the formula , because of Phase Correct PWM .
*/
const uint16_t tPWMWrapValue = ( F_CPU / 2000 ) / ( aFrequencyKHz ) ;
2022-12-23 22:24:10 +08:00
TCCR2A = _BV ( WGM20 ) ; // PWM, Phase Correct, Top is OCR2A
TCCR2B = _BV ( WGM22 ) | _BV ( CS20 ) ; // CS20 -> no prescaling
2023-03-29 19:28:06 +08:00
OCR2A = tPWMWrapValue - 1 ; // The top value for the timer. The modulation frequency will be F_CPU / 2 / (OCR2A + 1).
2022-01-27 01:36:50 +08:00
OCR2B = ( ( tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT ) / 100 ) - 1 ;
TCNT2 = 0 ; // not really required, since we have an 8 bit counter, but makes the signal more reproducible
2021-04-11 19:16:53 +08:00
# else
2022-01-27 01:36:50 +08:00
const uint16_t tPWMWrapValue = ( ( F_CPU / 8 ) / 2000 ) / ( aFrequencyKHz ) ; // 2000 instead of 1000 because of Phase Correct PWM
2021-04-11 19:16:53 +08:00
TCCR2A = _BV ( WGM20 ) ; // PWM, Phase Correct, Top is OCR2A
TCCR2B = _BV ( WGM22 ) | _BV ( CS21 ) ; // CS21 -> Prescaling by 8
2022-01-27 01:36:50 +08:00
OCR2A = tPWMWrapValue - 1 ;
OCR2B = ( ( tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT ) / 100 ) - 1 ;
2022-12-23 22:24:10 +08:00
TCNT2 = 0 ; // not really required, since we have an 8 bit counter, but makes the signal more reproducible
2021-04-11 19:16:53 +08:00
# endif
2021-03-06 20:47:47 +08:00
}
2022-01-27 01:36:50 +08:00
# endif // defined(SEND_PWM_BY_TIMER)
2021-03-06 20:47:47 +08:00
/*
2022-01-27 01:36:50 +08:00
* AVR Timer3 ( 16 bits )
2021-03-06 20:47:47 +08:00
*/
2022-01-27 01:36:50 +08:00
# elif defined(IR_USE_AVR_TIMER3)
2022-12-23 22:24:10 +08:00
void timerEnableReceiveInterrupt ( ) {
TIMSK3 = _BV ( OCIE3B ) ;
}
void timerDisableReceiveInterrupt ( ) {
TIMSK3 = 0 ;
}
2022-01-27 01:36:50 +08:00
# define TIMER_INTR_NAME TIMER3_COMPB_vect
2021-03-06 20:47:47 +08:00
void timerConfigForReceive ( ) {
2022-01-27 01:36:50 +08:00
TCCR3A = 0 ;
TCCR3B = _BV ( WGM32 ) | _BV ( CS30 ) ;
OCR3A = F_CPU * MICROS_PER_TICK / MICROS_IN_ONE_SECOND ;
OCR3B = F_CPU * MICROS_PER_TICK / MICROS_IN_ONE_SECOND ;
TCNT3 = 0 ;
2021-03-06 20:47:47 +08:00
}
2021-03-11 18:28:41 +08:00
# if defined(SEND_PWM_BY_TIMER)
# if defined(CORE_OC3A_PIN)
2021-03-06 20:47:47 +08:00
# define IR_SEND_PIN CORE_OC3A_PIN // Teensy
2021-03-11 18:28:41 +08:00
# elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) \
2021-03-06 20:47:47 +08:00
| | defined ( __AVR_ATmega32U4__ ) | | defined ( ARDUINO_AVR_PROMICRO )
# define IR_SEND_PIN 5 // Arduino Mega, Arduino Leonardo, Sparkfun Pro Micro
2021-03-11 18:28:41 +08:00
# elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__)
2021-03-06 20:47:47 +08:00
# define IR_SEND_PIN 6 // MightyCore, MegaCore
2021-03-11 18:28:41 +08:00
# else
2021-03-06 20:47:47 +08:00
# error Please add OC3A pin number here
2021-03-11 18:28:41 +08:00
# endif
2021-03-06 20:47:47 +08:00
2022-12-23 22:24:10 +08:00
void enableSendPWMByTimer ( ) {
TCNT3 = 0 ;
TCCR3A | = _BV ( COM3A1 ) ;
}
void disableSendPWMByTimer ( ) {
TCCR3A & = ~ ( _BV ( COM3A1 ) ) ;
}
2021-03-06 20:47:47 +08:00
2022-01-27 01:36:50 +08:00
/*
* timerConfigForSend ( ) is used exclusively by IRsend : : enableIROut ( )
* Set output pin mode and disable receive interrupt if it uses the same resource
*/
2023-03-29 19:28:06 +08:00
void timerConfigForSend ( uint16_t aFrequencyKHz ) {
2022-01-27 01:36:50 +08:00
# if F_CPU > 16000000
2021-04-11 19:16:53 +08:00
# error "Creating timer PWM with timer 3 is not supported for F_CPU > 16 MHz"
# endif
2022-12-23 22:24:10 +08:00
timerDisableReceiveInterrupt ( ) ;
2022-01-27 01:36:50 +08:00
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
2021-03-06 20:47:47 +08:00
TCCR3A = _BV ( WGM31 ) ;
2022-12-23 22:24:10 +08:00
TCCR3B = _BV ( WGM33 ) | _BV ( CS30 ) ; // PWM, Phase Correct, ICRn as TOP, complete period is double of tPWMWrapValue
2022-01-27 01:36:50 +08:00
ICR3 = tPWMWrapValue - 1 ;
OCR3A = ( ( tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT ) / 100 ) - 1 ;
2022-12-23 22:24:10 +08:00
TCNT3 = 0 ; // required, since we have an 16 bit counter
2021-03-06 20:47:47 +08:00
}
2022-01-27 01:36:50 +08:00
# endif // defined(SEND_PWM_BY_TIMER)
2021-03-06 20:47:47 +08:00
/*
* AVR Timer4 ( 16 bits )
*/
# elif defined(IR_USE_AVR_TIMER4)
2022-12-23 22:24:10 +08:00
void timerEnableReceiveInterrupt ( ) {
TIMSK4 = _BV ( OCIE4A ) ;
}
void timerDisableReceiveInterrupt ( ) {
TIMSK4 = 0 ;
}
2022-05-21 00:54:51 +08:00
# define TIMER_INTR_NAME TIMER4_COMPA_vect
void timerConfigForReceive ( ) {
TCCR4A = 0 ;
TCCR4B = _BV ( WGM42 ) | _BV ( CS40 ) ;
OCR4A = F_CPU * MICROS_PER_TICK / MICROS_IN_ONE_SECOND ;
TCNT4 = 0 ;
}
2021-03-11 18:28:41 +08:00
# if defined(SEND_PWM_BY_TIMER)
# if defined(CORE_OC4A_PIN)
2021-03-06 20:47:47 +08:00
# define IR_SEND_PIN CORE_OC4A_PIN
2021-03-11 18:28:41 +08:00
# elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
2021-03-06 20:47:47 +08:00
# define IR_SEND_PIN 6 // Arduino Mega
2021-03-11 18:28:41 +08:00
# else
2021-03-06 20:47:47 +08:00
# error Please add OC4A pin number here
2021-03-11 18:28:41 +08:00
# endif
2021-03-06 20:47:47 +08:00
2022-12-23 22:24:10 +08:00
void enableSendPWMByTimer ( ) {
TCNT4 = 0 ;
TCCR4A | = _BV ( COM4A1 ) ;
}
void disableSendPWMByTimer ( ) {
TCCR4A & = ~ ( _BV ( COM4A1 ) ) ;
}
2021-03-06 20:47:47 +08:00
2023-03-29 19:28:06 +08:00
void timerConfigForSend ( uint16_t aFrequencyKHz ) {
2022-01-27 01:36:50 +08:00
# if F_CPU > 16000000
2021-04-11 19:16:53 +08:00
# error "Creating timer PWM with timer 4 is not supported for F_CPU > 16 MHz"
# endif
2022-12-23 22:24:10 +08:00
timerDisableReceiveInterrupt ( ) ;
2022-01-27 01:36:50 +08:00
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
2021-03-06 20:47:47 +08:00
TCCR4A = _BV ( WGM41 ) ;
TCCR4B = _BV ( WGM43 ) | _BV ( CS40 ) ;
2022-01-27 01:36:50 +08:00
ICR4 = tPWMWrapValue - 1 ;
OCR4A = ( ( tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT ) / 100 ) - 1 ;
2022-12-23 22:24:10 +08:00
TCNT4 = 0 ; // required, since we have an 16 bit counter
2021-03-06 20:47:47 +08:00
}
2022-01-27 01:36:50 +08:00
# endif // defined(SEND_PWM_BY_TIMER)
2021-03-06 20:47:47 +08:00
/*
* AVR Timer4 ( 10 bits , high speed option )
*/
# elif defined(IR_USE_AVR_TIMER4_HS)
2022-01-27 01:36:50 +08:00
2022-12-23 22:24:10 +08:00
void timerEnableReceiveInterrupt ( ) {
TIMSK4 = _BV ( TOIE4 ) ;
}
void timerDisableReceiveInterrupt ( ) {
TIMSK4 = 0 ;
}
2022-01-27 01:36:50 +08:00
# define TIMER_INTR_NAME TIMER4_OVF_vect
void timerConfigForReceive ( ) {
TCCR4A = 0 ;
TCCR4B = _BV ( CS40 ) ;
TCCR4C = 0 ;
TCCR4D = 0 ;
TCCR4E = 0 ;
TC4H = ( F_CPU * MICROS_PER_TICK / MICROS_IN_ONE_SECOND ) > > 8 ;
OCR4C = ( F_CPU * MICROS_PER_TICK / MICROS_IN_ONE_SECOND ) & 255 ;
TC4H = 0 ;
TCNT4 = 0 ;
}
2021-03-11 18:28:41 +08:00
# if defined(SEND_PWM_BY_TIMER)
# if defined(CORE_OC4A_PIN)
2021-12-22 04:51:28 +08:00
# define IR_SEND_PIN CORE_OC4A_PIN // Teensy 2.0
2021-03-11 18:28:41 +08:00
# elif defined(ARDUINO_AVR_PROMICRO)
2021-03-06 20:47:47 +08:00
# define IR_SEND_PIN 5 // Sparkfun Pro Micro
2021-03-11 18:28:41 +08:00
# elif defined(__AVR_ATmega32U4__)
2021-03-06 20:47:47 +08:00
# define IR_SEND_PIN 13 // Leonardo
2021-03-11 18:28:41 +08:00
# else
2021-03-06 20:47:47 +08:00
# error Please add OC4A pin number here
2021-03-11 18:28:41 +08:00
# endif
2021-03-06 20:47:47 +08:00
2021-06-21 06:32:42 +08:00
# if defined(ARDUINO_AVR_PROMICRO) // Sparkfun Pro Micro
2023-08-08 03:45:57 +08:00
void enableSendPWMByTimer ( ) {
TCNT4 = 0 ;
TCCR4A | = _BV ( COM4A0 ) ; // Use complementary OC4A output on pin 5
}
void disableSendPWMByTimer ( ) {
TCCR4A & = ~ ( _BV ( COM4A0 ) ) ; // (Pro Micro does not map PC7 (32/ICP3/CLK0/OC4A)
}
2021-03-06 20:47:47 +08:00
// of ATmega32U4 )
2021-06-21 06:32:42 +08:00
# else
2022-12-23 22:24:10 +08:00
void enableSendPWMByTimer ( ) {
TCNT4 = 0 ;
TCCR4A | = _BV ( COM4A1 ) ;
DDRC | = 1 < < 7 ;
}
void disableSendPWMByTimer ( ) {
TCCR4A & = ~ ( _BV ( COM4A1 ) ) ;
}
2021-06-21 06:32:42 +08:00
# endif
2021-03-06 20:47:47 +08:00
2022-01-27 01:36:50 +08:00
/*
* timerConfigForSend ( ) is used exclusively by IRsend : : enableIROut ( )
* Set output pin mode and disable receive interrupt if it uses the same resource
*/
2023-03-29 19:28:06 +08:00
void timerConfigForSend ( uint16_t aFrequencyKHz ) {
2022-01-27 01:36:50 +08:00
# if F_CPU > 16000000
2021-04-11 19:16:53 +08:00
# error "Creating timer PWM with timer 4 HS is not supported for F_CPU > 16 MHz"
# endif
2022-12-23 22:24:10 +08:00
timerDisableReceiveInterrupt ( ) ;
2022-01-27 01:36:50 +08:00
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
2021-03-06 20:47:47 +08:00
TCCR4A = ( 1 < < PWM4A ) ;
TCCR4B = _BV ( CS40 ) ;
TCCR4C = 0 ;
TCCR4D = ( 1 < < WGM40 ) ;
TCCR4E = 0 ;
2022-01-27 01:36:50 +08:00
TC4H = tPWMWrapValue > > 8 ;
OCR4C = tPWMWrapValue ;
TC4H = ( tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT / 100 ) > > 8 ;
OCR4A = ( tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT / 100 ) & 255 ;
2022-12-23 22:24:10 +08:00
TCNT4 = 0 ; // not really required, since we have an 8 bit counter, but makes the signal more reproducible
2021-03-06 20:47:47 +08:00
}
2022-01-27 01:36:50 +08:00
# endif // defined(SEND_PWM_BY_TIMER)
2021-03-06 20:47:47 +08:00
/*
* AVR Timer5 ( 16 bits )
*/
# elif defined(IR_USE_AVR_TIMER5)
2022-01-27 01:36:50 +08:00
2022-12-23 22:24:10 +08:00
void timerEnableReceiveInterrupt ( ) {
TIMSK5 = _BV ( OCIE5A ) ;
}
void timerDisableReceiveInterrupt ( ) {
TIMSK5 = 0 ;
}
2022-01-27 01:36:50 +08:00
# define TIMER_INTR_NAME TIMER5_COMPA_vect
void timerConfigForReceive ( ) {
TCCR5A = 0 ;
TCCR5B = _BV ( WGM52 ) | _BV ( CS50 ) ;
OCR5A = F_CPU * MICROS_PER_TICK / MICROS_IN_ONE_SECOND ;
TCNT5 = 0 ;
}
2021-03-11 18:28:41 +08:00
# if defined(SEND_PWM_BY_TIMER)
# if defined(CORE_OC5A_PIN)
2021-03-06 20:47:47 +08:00
# define IR_SEND_PIN CORE_OC5A_PIN
2021-03-11 18:28:41 +08:00
# elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
2021-03-06 20:47:47 +08:00
# define IR_SEND_PIN 46 // Arduino Mega
2021-03-11 18:28:41 +08:00
# else
2021-03-06 20:47:47 +08:00
# error Please add OC5A pin number here
2021-03-11 18:28:41 +08:00
# endif
2021-03-06 20:47:47 +08:00
2022-12-23 22:24:10 +08:00
void enableSendPWMByTimer ( ) {
TCNT5 = 0 ;
TCCR5A | = _BV ( COM5A1 ) ;
}
void disableSendPWMByTimer ( ) {
TCCR5A & = ~ ( _BV ( COM5A1 ) ) ;
}
2021-03-06 20:47:47 +08:00
2022-01-27 01:36:50 +08:00
/*
* timerConfigForSend ( ) is used exclusively by IRsend : : enableIROut ( )
* Set output pin mode and disable receive interrupt if it uses the same resource
*/
2023-03-29 19:28:06 +08:00
void timerConfigForSend ( uint16_t aFrequencyKHz ) {
2022-01-27 01:36:50 +08:00
# if F_CPU > 16000000
2021-04-11 19:16:53 +08:00
# error "Creating timer PWM with timer 5 is not supported for F_CPU > 16 MHz"
# endif
2022-12-23 22:24:10 +08:00
timerDisableReceiveInterrupt ( ) ;
2022-01-27 01:36:50 +08:00
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
2021-03-06 20:47:47 +08:00
TCCR5A = _BV ( WGM51 ) ;
TCCR5B = _BV ( WGM53 ) | _BV ( CS50 ) ;
2022-01-27 01:36:50 +08:00
ICR5 = tPWMWrapValue - 1 ;
OCR5A = ( ( tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT ) / 100 ) - 1 ;
2022-12-23 22:24:10 +08:00
TCNT5 = 0 ; // required, since we have an 16 bit counter
2021-03-06 20:47:47 +08:00
}
2022-01-27 01:36:50 +08:00
# endif // defined(SEND_PWM_BY_TIMER)
2021-03-06 20:47:47 +08:00
/*
* AVR Timer0 for ATtinies ( 8 bits )
*/
# elif defined(IR_USE_AVR_TIMER_TINY0)
2021-06-21 06:32:42 +08:00
2022-12-23 22:24:10 +08:00
void timerEnableReceiveInterrupt ( ) {
TIMSK | = _BV ( OCIE0A ) ;
}
void timerDisableReceiveInterrupt ( ) {
TIMSK & = ~ ( _BV ( OCIE0A ) ) ;
}
2021-03-06 20:47:47 +08:00
# define TIMER_INTR_NAME TIMER0_COMPA_vect
2021-11-03 13:57:27 +08:00
# define TIMER_COUNT_TOP (F_CPU * MICROS_PER_TICK / MICROS_IN_ONE_SECOND)
2022-12-30 01:46:09 +08:00
2021-03-06 20:47:47 +08:00
void timerConfigForReceive ( ) {
# if (TIMER_COUNT_TOP < 256)
TCCR0A = _BV ( WGM01 ) ; // CTC, Top is OCR0A
TCCR0B = _BV ( CS00 ) ; // No prescaling
OCR0A = TIMER_COUNT_TOP ;
TCNT0 = 0 ;
# else
TCCR0A = _BV ( WGM01 ) ;
TCCR0B = _BV ( CS01 ) ; // prescaling by 8
OCR0A = TIMER_COUNT_TOP / 8 ;
TCNT0 = 0 ;
# endif
}
2022-01-27 01:36:50 +08:00
# if defined(SEND_PWM_BY_TIMER)
# define IR_SEND_PIN 1
2022-12-23 22:24:10 +08:00
void enableSendPWMByTimer ( ) {
TCNT0 = 0 ;
TCCR0A | = _BV ( COM0B1 ) ;
}
void disableSendPWMByTimer ( ) {
TCCR0A & = ~ ( _BV ( COM0B1 ) ) ;
}
2022-01-27 01:36:50 +08:00
/*
* timerConfigForSend ( ) is used exclusively by IRsend : : enableIROut ( )
* Set output pin mode and disable receive interrupt if it uses the same resource
*/
2023-03-29 19:28:06 +08:00
void timerConfigForSend ( uint16_t aFrequencyKHz ) {
2022-01-27 01:36:50 +08:00
# if F_CPU > 16000000
# error "Creating timer PWM with timer TINY0 is not supported for F_CPU > 16 MHz"
# endif
2022-12-23 22:24:10 +08:00
timerDisableReceiveInterrupt ( ) ;
2022-01-27 01:36:50 +08:00
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
2022-12-23 22:24:10 +08:00
TCCR0A = _BV ( WGM00 ) ; // PWM, Phase Correct, Top is OCR0A
TCCR0B = _BV ( WGM02 ) | _BV ( CS00 ) ; // CS00 -> no prescaling
2022-01-27 01:36:50 +08:00
OCR0A = tPWMWrapValue - 1 ;
OCR0B = ( ( tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT ) / 100 ) - 1 ;
2022-12-23 22:24:10 +08:00
TCNT0 = 0 ; // not really required, since we have an 8 bit counter, but makes the signal more reproducible
2022-01-27 01:36:50 +08:00
}
# endif // defined(SEND_PWM_BY_TIMER)
2021-03-06 20:47:47 +08:00
/*
* AVR Timer1 for ATtinies ( 8 bits )
*/
# elif defined(IR_USE_AVR_TIMER_TINY1)
2021-06-21 06:32:42 +08:00
2022-12-23 22:24:10 +08:00
void timerEnableReceiveInterrupt ( ) {
TIMSK | = _BV ( OCIE1B ) ;
}
void timerDisableReceiveInterrupt ( ) {
TIMSK & = ~ ( _BV ( OCIE1B ) ) ;
}
2021-03-06 20:47:47 +08:00
# define TIMER_INTR_NAME TIMER1_COMPB_vect
2021-11-03 13:57:27 +08:00
# define TIMER_COUNT_TOP (F_CPU * MICROS_PER_TICK / MICROS_IN_ONE_SECOND)
2022-12-30 01:46:09 +08:00
2021-03-06 20:47:47 +08:00
void timerConfigForReceive ( ) {
# if (TIMER_COUNT_TOP < 256)
TCCR1 = _BV ( CTC1 ) | _BV ( CS10 ) ; // Clear Timer/Counter on Compare Match, Top is OCR1C, No prescaling
2022-01-27 01:36:50 +08:00
GTCCR = 0 ; // normal, non-PWM mode
2021-03-06 20:47:47 +08:00
OCR1C = TIMER_COUNT_TOP ;
TCNT1 = 0 ;
# else
TCCR1 = _BV ( CTC1 ) | _BV ( CS12 ) ; // Clear Timer/Counter on Compare Match, Top is OCR1C, prescaling by 8
2022-12-23 22:24:10 +08:00
GTCCR = 0 ; // normal, non-PWM mode
2021-03-06 20:47:47 +08:00
OCR1C = TIMER_COUNT_TOP / 8 ;
TCNT1 = 0 ;
# endif
}
2022-01-27 01:36:50 +08:00
# if defined(SEND_PWM_BY_TIMER)
# define IR_SEND_PIN 4
2022-12-23 22:24:10 +08:00
void enableSendPWMByTimer ( ) {
TCNT1 = 0 ;
GTCCR | = _BV ( PWM1B ) | _BV ( COM1B0 ) ; // Enable pin 4 PWM output (PB4 - Arduino D4)
}
void disableSendPWMByTimer ( ) {
GTCCR & = ~ ( _BV ( PWM1B ) | _BV ( COM1B0 ) ) ;
}
2022-01-27 01:36:50 +08:00
/*
* timerConfigForSend ( ) is used exclusively by IRsend : : enableIROut ( )
* Set output pin mode and disable receive interrupt if it uses the same resource
*/
2023-03-29 19:28:06 +08:00
void timerConfigForSend ( uint16_t aFrequencyKHz ) {
2022-12-23 22:24:10 +08:00
timerDisableReceiveInterrupt ( ) ;
2022-01-27 01:36:50 +08:00
2022-12-23 22:24:10 +08:00
# if (((F_CPU / 1000) / 38) < 256)
2022-01-27 01:36:50 +08:00
const uint16_t tPWMWrapValue = ( F_CPU / 1000 ) / ( aFrequencyKHz ) ; // 421 @16 MHz, 26 @1 MHz and 38 kHz
TCCR1 = _BV ( CTC1 ) | _BV ( CS10 ) ; // CTC1 = 1: TOP value set to OCR1C, CS10 No Prescaling
OCR1C = tPWMWrapValue - 1 ;
OCR1B = ( ( tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT ) / 100 ) - 1 ;
TCNT1 = 0 ; // not really required, since we have an 8 bit counter, but makes the signal more reproducible
GTCCR = _BV ( PWM1B ) | _BV ( COM1B0 ) ; // PWM1B = 1: Enable PWM for OCR1B, COM1B0 Clear on compare match
# else
const uint16_t tPWMWrapValue = ( ( F_CPU / 2 ) / 1000 ) / ( aFrequencyKHz ) ; // 210 for 16 MHz and 38 kHz
2022-12-23 22:24:10 +08:00
TCCR1 = _BV ( CTC1 ) | _BV ( CS11 ) ; // CTC1 = 1: TOP value set to OCR1C, CS11 Prescaling by 2
2022-01-27 01:36:50 +08:00
OCR1C = tPWMWrapValue - 1 ;
OCR1B = ( ( tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT ) / 100 ) - 1 ;
2022-12-23 22:24:10 +08:00
TCNT1 = 0 ; // not really required, since we have an 8 bit counter, but makes the signal more reproducible
GTCCR = _BV ( PWM1B ) | _BV ( COM1B0 ) ; // PWM1B = 1: Enable PWM for OCR1B, COM1B0 Clear on compare match
2022-01-27 01:36:50 +08:00
# endif
}
# endif // defined(SEND_PWM_BY_TIMER)
2022-02-01 07:52:17 +08:00
/*
* AVR TimerA for TinyCore 32 ( 16 bits )
*/
# elif defined(IR_USE_AVR_TIMER_A)
2022-12-23 22:24:10 +08:00
# define TIMER_REQUIRES_RESET_INTR_PENDING
void timerResetInterruptPending ( ) {
TCA0 . SINGLE . INTFLAGS = TCA_SINGLE_OVF_bm ;
}
void timerEnableReceiveInterrupt ( ) {
TCA0 . SINGLE . INTCTRL = TCA_SINGLE_OVF_bm ;
}
void timerDisableReceiveInterrupt ( ) {
TCA0 . SINGLE . INTCTRL & = ~ ( TCA_SINGLE_OVF_bm ) ;
}
2022-02-01 07:52:17 +08:00
# define TIMER_INTR_NAME TCA0_OVF_vect
// For MegaTinyCore:
// TCB1 is used by Tone()
// TCB2 is used by Servo, but we cannot hijack the ISR, so we must use a dedicated timer for the 20 ms interrupt
// TCB3 is used by millis()
// Must use TCA0, since TCBx have only prescaler %2. Use single (16bit) mode, because it seems to be easier :-)
void timerConfigForReceive ( ) {
TCA0 . SINGLE . CTRLD = 0 ; // Single mode - required at least for MegaTinyCore
TCA0 . SINGLE . CTRLB = TCA_SINGLE_WGMODE_NORMAL_gc ; // Normal mode, top = PER
TCA0 . SINGLE . PER = ( F_CPU / MICROS_IN_ONE_SECOND ) * MICROS_PER_TICK ; // 800 at 16 MHz
TCA0 . SINGLE . CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm ; // set prescaler to 1 and enable timer
}
2022-04-05 10:47:32 +08:00
# if defined(SEND_PWM_BY_TIMER)
2022-05-21 00:54:51 +08:00
# error "No support for hardware PWM generation for ATtiny3216 / 17 etc."
2022-02-01 07:52:17 +08:00
# endif // defined(SEND_PWM_BY_TIMER)
2022-01-27 01:36:50 +08:00
2021-03-06 20:47:47 +08:00
/*
2021-12-02 04:45:53 +08:00
* AVR TimerB ( 8 bits ) for ATmega4809 ( Nano Every , Uno WiFi Rev2 )
2021-03-06 20:47:47 +08:00
*/
# elif defined(IR_USE_AVR_TIMER_B)
2022-01-27 01:36:50 +08:00
// ATmega4809 TCB0
2022-12-23 22:24:10 +08:00
# define TIMER_REQUIRES_RESET_INTR_PENDING
void timerResetInterruptPending ( ) {
TCB0 . INTFLAGS = TCB_CAPT_bm ;
}
void timerEnableReceiveInterrupt ( ) {
TCB0 . INTCTRL = TCB_CAPT_bm ;
}
void timerDisableReceiveInterrupt ( ) {
TCB0 . INTCTRL & = ~ ( TCB_CAPT_bm ) ;
}
2022-01-27 01:36:50 +08:00
# define TIMER_INTR_NAME TCB0_INT_vect
void timerConfigForReceive ( ) {
TCB0 . CTRLB = ( TCB_CNTMODE_INT_gc ) ; // Periodic interrupt mode
TCB0 . CCMP = ( ( F_CPU * MICROS_PER_TICK ) / MICROS_IN_ONE_SECOND ) ;
2022-12-23 22:24:10 +08:00
TCB0 . INTFLAGS = TCB_CAPT_bm ; // reset interrupt flags
2022-01-27 01:36:50 +08:00
TCB0 . CTRLA = ( TCB_CLKSEL_CLKDIV1_gc ) | ( TCB_ENABLE_bm ) ;
}
2021-03-11 18:28:41 +08:00
# if defined(SEND_PWM_BY_TIMER)
2021-12-02 04:45:53 +08:00
# if defined(__AVR_ATmega4808__) || defined(__AVR_ATmega4809__)
# define IR_SEND_PIN 6 // PF4 on ATmega4809 / Nano Every (see pins_arduino.h digital_pin_to_timer)
# else
# error SEND_PWM_BY_TIMER not yet supported for this CPU
# endif
2021-06-21 06:32:42 +08:00
2022-12-23 22:24:10 +08:00
void enableSendPWMByTimer ( ) {
TCB0 . CNT = 0 ;
TCB0 . CTRLB | = TCB_CCMPEN_bm ; // set Compare/Capture Output Enable
}
void disableSendPWMByTimer ( ) {
TCB0 . CTRLB & = ~ ( TCB_CCMPEN_bm ) ;
}
2021-03-06 20:47:47 +08:00
2022-01-27 01:36:50 +08:00
/*
* timerConfigForSend ( ) is used exclusively by IRsend : : enableIROut ( )
* Set output pin mode and disable receive interrupt if it uses the same resource
*/
2023-03-29 19:28:06 +08:00
void timerConfigForSend ( uint16_t aFrequencyKHz ) {
2022-01-27 01:36:50 +08:00
# if F_CPU > 16000000
2022-12-23 22:24:10 +08:00
// we have only prescaler 2 or must take clock of timer A (which is non deterministic)
2021-04-11 19:16:53 +08:00
# error "Creating timer PWM with timer TCB0 is not possible for F_CPU > 16 MHz"
# endif
2022-12-23 22:24:10 +08:00
timerDisableReceiveInterrupt ( ) ;
2022-01-27 01:36:50 +08:00
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
2022-12-23 22:24:10 +08:00
TCB0 . CTRLB = TCB_CNTMODE_PWM8_gc ; // 8 bit PWM mode
TCB0 . CCMPL = tPWMWrapValue - 1 ; // Period of 8 bit PWM
TCB0 . CCMPH = ( ( tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT ) / 100 ) - 1 ; // Duty cycle of waveform of 8 bit PWM
TCB0 . CTRLA = ( TCB_CLKSEL_CLKDIV2_gc ) | ( TCB_ENABLE_bm ) ; // use CLK / 2
TCB0 . CNT = 0 ; // not really required, since we have an 8 bit counter, but makes the signal more reproducible
2021-03-06 20:47:47 +08:00
}
2022-01-27 01:36:50 +08:00
# endif // defined(SEND_PWM_BY_TIMER)
2021-03-06 20:47:47 +08:00
/*
* AVR TimerD for TinyCore 32 ( 16 bits )
*/
# elif defined(IR_USE_AVR_TIMER_D)
2021-06-21 06:32:42 +08:00
2022-12-23 22:24:10 +08:00
# define TIMER_REQUIRES_RESET_INTR_PENDING
void timerResetInterruptPending ( ) {
TCD0 . INTFLAGS = TCD_OVF_bm ;
}
void timerEnableReceiveInterrupt ( ) {
TCD0 . INTCTRL = TCD_OVF_bm ;
}
void timerDisableReceiveInterrupt ( ) {
TCD0 . INTCTRL = 0 ;
}
2021-03-06 20:47:47 +08:00
# define TIMER_INTR_NAME TCD0_OVF_vect
2022-01-27 01:36:50 +08:00
void timerConfigForReceive ( ) {
2022-02-01 07:52:17 +08:00
TCD0 . CTRLA = 0 ; // reset enable bit in order to unprotect the other bits
TCD0 . CTRLB = TCD_WGMODE_ONERAMP_gc ; // must be set since it is used by PWM
2022-01-27 01:36:50 +08:00
// TCD0.CMPBSET = 80;
TCD0 . CMPBCLR = ( ( F_CPU * MICROS_PER_TICK ) / MICROS_IN_ONE_SECOND ) - 1 ;
2022-02-01 07:52:17 +08:00
_PROTECTED_WRITE ( TCD0 . FAULTCTRL , 0 ) ; // must disable WOA output at pin 13/PA4
2022-01-27 01:36:50 +08:00
2022-02-01 07:52:17 +08:00
TCD0 . INTFLAGS = TCD_OVF_bm ; // reset interrupt flags
2022-01-27 01:36:50 +08:00
// check enable ready
// while ((TCD0.STATUS & TCD_ENRDY_bm) == 0); // Wait for Enable Ready to be high - I guess it is not required
// enable timer - this locks the other bits and static registers and activates values in double buffered registers
2022-12-23 22:24:10 +08:00
TCD0 . CTRLA = TCD_ENABLE_bm | TCD_CLKSEL_SYSCLK_gc | TCD_CNTPRES_DIV1_gc ; // System clock, no prescale, no synchronization prescaler
2022-01-27 01:36:50 +08:00
}
# if defined(SEND_PWM_BY_TIMER)
# define IR_SEND_PIN 13
void timerEnableSendPWM ( ) {
2021-03-06 20:47:47 +08:00
TCD0 . CTRLA = 0 ; // reset enable bit in order to unprotect the other bits
2022-12-23 22:24:10 +08:00
_PROTECTED_WRITE ( TCD0 . FAULTCTRL , FUSE_CMPAEN_bm ) ; // enable WOA output at pin 13/PA4
2021-03-06 20:47:47 +08:00
// _PROTECTED_WRITE(TCD0.FAULTCTRL, FUSE_CMPAEN_bm | FUSE_CMPBEN_bm); // enable WOA + WOB output pins at 13/PA4 + 14/PA5
2022-12-23 22:24:10 +08:00
TCD0 . CTRLA = TCD_ENABLE_bm | TCD_CLKSEL_SYSCLK_gc | TCD_CNTPRES_DIV1_gc ; // System clock, no prescale, no synchronization prescaler
}
void enableSendPWMByTimer ( ) {
timerEnableSendPWM ( ) ;
}
void disableSendPWMByTimer ( ) {
TCD0 . CTRLA = 0 ; // do not disable output, disable complete timer
2021-03-06 20:47:47 +08:00
}
2022-01-27 01:36:50 +08:00
/*
* timerConfigForSend ( ) is used exclusively by IRsend : : enableIROut ( )
* Set output pin mode and disable receive interrupt if it uses the same resource
*/
2023-03-29 19:28:06 +08:00
void timerConfigForSend ( uint16_t aFrequencyKHz ) {
2022-12-23 22:24:10 +08:00
timerDisableReceiveInterrupt ( ) ;
2022-01-27 01:36:50 +08:00
const uint16_t tPWMWrapValue = ( F_CPU / 1000 ) / ( aFrequencyKHz ) ; // 526,31 for 38 kHz @20 MHz clock
2021-03-06 20:47:47 +08:00
// use one ramp mode and overflow interrupt
2022-12-23 22:24:10 +08:00
TCD0 . CTRLA = 0 ; // reset enable bit in order to unprotect the other bits
2021-03-06 20:47:47 +08:00
// while ((TCD0.STATUS & TCD_ENRDY_bm) == 0); // Wait for Enable Ready to be high - I guess it is not required
2022-12-23 22:24:10 +08:00
TCD0 . CTRLB = TCD_WGMODE_ONERAMP_gc ; // must be set since it is used by PWM
TCD0 . CTRLC = 0 ; // reset WOx output settings
2021-03-06 20:47:47 +08:00
// TCD0.CMPBSET = 80;
2022-01-27 01:36:50 +08:00
TCD0 . CMPBCLR = tPWMWrapValue - 1 ;
2021-03-06 20:47:47 +08:00
// Generate duty cycle signal for debugging etc.
TCD0 . CMPASET = 0 ;
2022-12-23 22:24:10 +08:00
TCD0 . CMPACLR = ( tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT / 100 ) - 1 ; // duty cycle for WOA
2021-03-06 20:47:47 +08:00
2022-12-23 22:24:10 +08:00
TCD0 . INTFLAGS = TCD_OVF_bm ; // reset interrupt flags
TCD0 . INTCTRL = TCD_OVF_bm ; // overflow interrupt
2021-03-06 20:47:47 +08:00
// Do not enable timer, this is done at timerEnablSendPWM()
}
2022-01-27 01:36:50 +08:00
# endif // defined(SEND_PWM_BY_TIMER)
2021-03-06 20:47:47 +08:00
2021-04-09 05:30:49 +08:00
# else
# error Internal code configuration error, no timer functions implemented for this AVR CPU / board
2021-03-06 20:47:47 +08:00
# endif //defined(IR_USE_AVR_TIMER*)
/**********************************************************************************************************************
* End of AVR timers
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2023-07-27 04:15:40 +08:00
/**********************************************
2023-08-05 17:26:17 +08:00
* Uno R4 boards
2023-07-27 04:15:40 +08:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# elif defined(ARDUINO_ARCH_RENESAS)
# include "FspTimer.h"
FspTimer s50usTimer ;
// Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
# if defined(ISR)
# undef ISR
# endif
// callback method used by timer
void IRTimerInterruptHandlerHelper ( timer_callback_args_t __attribute ( ( unused ) ) * p_args ) {
IRReceiveTimerInterruptHandler ( ) ;
}
void timerEnableReceiveInterrupt ( ) {
// s50usTimer.enable_overflow_irq();
s50usTimer . start ( ) ;
}
void timerDisableReceiveInterrupt ( ) {
// s50usTimer.disable_overflow_irq();
s50usTimer . stop ( ) ; // May save power
}
void timerConfigForReceive ( ) {
uint8_t tTimerType = GPT_TIMER ;
int8_t tIndex = FspTimer : : get_available_timer ( tTimerType ) ; // Get first unused channel. Here we need the address of tTimerType
if ( tIndex < 0 | | tTimerType ! = GPT_TIMER ) {
// here we found no unused GPT channel
tIndex = FspTimer : : get_available_timer ( tTimerType , true ) ; // true to force use of already used PWM channel. Sets "force_pwm_reserved" if timer found
if ( tIndex < 0 ) {
// If we already get an tIndex < 0 we have an error, but do not know how to handle :-(
return ;
}
}
s50usTimer . begin ( TIMER_MODE_PERIODIC , tTimerType , tIndex , MICROS_IN_ONE_SECOND / MICROS_PER_TICK , 0.0 ,
IRTimerInterruptHandlerHelper ) ;
s50usTimer . setup_overflow_irq ( ) ;
s50usTimer . open ( ) ; // In turn calls R_GPT_Enable()
s50usTimer . stop ( ) ; // May save power
}
# if defined(SEND_PWM_BY_TIMER)
# error PWM generation by hardware not yet implemented for Arduino Uno R4
// Not yet implemented
void enableSendPWMByTimer ( ) {
}
void disableSendPWMByTimer ( ) {
}
/*
* timerConfigForSend ( ) is used exclusively by IRsend : : enableIROut ( )
*/
void timerConfigForSend ( uint16_t aFrequencyKHz ) {
# if defined(IR_SEND_PIN)
# else
# endif
}
# endif
2022-12-30 01:46:09 +08:00
/**********************************************
* Teensy 3.0 / Teensy 3.1 / Teensy 3.2 boards
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-01-27 01:36:50 +08:00
# elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
2021-03-06 20:47:47 +08:00
2022-12-30 01:46:09 +08:00
// Special carrier modulator timer for Teensy 3.0 / Teensy 3.1 / Teensy 3.2
2022-12-23 22:24:10 +08:00
# define TIMER_REQUIRES_RESET_INTR_PENDING
void timerResetInterruptPending ( ) {
uint8_t tmp __attribute__ ( ( unused ) ) = CMT_MSC ;
CMT_CMD2 = 30 ;
}
void timerEnableReceiveInterrupt ( ) {
NVIC_ENABLE_IRQ ( IRQ_CMT ) ;
NVIC_SET_PRIORITY ( IRQ_CMT , 48 ) ;
}
void timerDisableReceiveInterrupt ( ) {
NVIC_DISABLE_IRQ ( IRQ_CMT ) ;
}
2021-03-06 20:47:47 +08:00
2023-03-01 20:37:15 +08:00
# define TIMER_INTR_NAME cmt_isr
2022-04-05 10:47:32 +08:00
# if defined(ISR)
2021-03-06 20:47:47 +08:00
# undef ISR
# endif
2021-12-22 04:51:28 +08:00
# define ISR(f) void f(void)
2021-03-06 20:47:47 +08:00
# define CMT_PPS_DIV ((F_BUS + 7999999) / 8000000)
# if F_BUS < 8000000
# error IRremote requires at least 8 MHz on Teensy 3.x
# endif
2022-01-27 01:36:50 +08:00
void timerConfigForReceive ( ) {
2021-03-06 20:47:47 +08:00
SIM_SCGC4 | = SIM_SCGC4_CMT ;
CMT_PPS = CMT_PPS_DIV - 1 ;
2022-01-27 01:36:50 +08:00
CMT_CGH1 = 1 ;
CMT_CGL1 = 1 ;
2021-03-06 20:47:47 +08:00
CMT_CMD1 = 0 ;
CMT_CMD2 = 30 ;
CMT_CMD3 = 0 ;
2022-01-27 01:36:50 +08:00
CMT_CMD4 = ( F_BUS / 160000 + CMT_PPS_DIV / 2 ) / CMT_PPS_DIV - 31 ;
CMT_OC = 0 ;
CMT_MSC = 0x03 ;
2021-03-06 20:47:47 +08:00
}
2022-01-27 01:36:50 +08:00
# if defined(SEND_PWM_BY_TIMER)
# define IR_SEND_PIN 5
2022-12-23 22:24:10 +08:00
void enableSendPWMByTimer ( ) {
do {
CORE_PIN5_CONFIG = PORT_PCR_MUX ( 2 ) | PORT_PCR_DSE | PORT_PCR_SRE ;
} while ( 0 ) ;
}
void disableSendPWMByTimer ( ) {
do {
CORE_PIN5_CONFIG = PORT_PCR_MUX ( 1 ) | PORT_PCR_DSE | PORT_PCR_SRE ;
} while ( 0 ) ;
}
2022-01-27 01:36:50 +08:00
/*
* timerConfigForSend ( ) is used exclusively by IRsend : : enableIROut ( )
* Set output pin mode and disable receive interrupt if it uses the same resource
*/
2023-03-29 19:28:06 +08:00
void timerConfigForSend ( uint16_t aFrequencyKHz ) {
2022-12-23 22:24:10 +08:00
timerDisableReceiveInterrupt ( ) ; // TODO really required here? Do we have a common resource for Teensy3.0, 3.1
2022-07-17 03:33:09 +08:00
# if defined(IR_SEND_PIN)
pinMode ( IR_SEND_PIN , OUTPUT ) ;
# else
pinMode ( IrSender . sendPin , OUTPUT ) ;
# endif
2022-01-27 01:36:50 +08:00
2021-03-06 20:47:47 +08:00
SIM_SCGC4 | = SIM_SCGC4_CMT ;
2022-01-27 01:36:50 +08:00
SIM_SOPT2 | = SIM_SOPT2_PTD7PAD ;
2021-03-06 20:47:47 +08:00
CMT_PPS = CMT_PPS_DIV - 1 ;
2022-01-27 01:36:50 +08:00
CMT_CGH1 = ( ( F_BUS / CMT_PPS_DIV / 3000 ) + ( ( aFrequencyKHz ) / 2 ) ) / ( aFrequencyKHz ) ;
CMT_CGL1 = ( ( F_BUS / CMT_PPS_DIV / 1500 ) + ( ( aFrequencyKHz ) / 2 ) ) / ( aFrequencyKHz ) ;
2021-03-06 20:47:47 +08:00
CMT_CMD1 = 0 ;
CMT_CMD2 = 30 ;
CMT_CMD3 = 0 ;
2022-01-27 01:36:50 +08:00
CMT_CMD4 = 0 ;
CMT_OC = 0x60 ;
CMT_MSC = 0x01 ;
2021-03-06 20:47:47 +08:00
}
2022-01-27 01:36:50 +08:00
# endif // defined(SEND_PWM_BY_TIMER)
2021-03-06 20:47:47 +08:00
/***************************************
* Teensy - LC board
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# elif defined(__MKL26Z64__)
// defines for TPM1 timer on Teensy-LC
2022-12-23 22:24:10 +08:00
# define TIMER_REQUIRES_RESET_INTR_PENDING
void timerResetInterruptPending ( ) {
FTM1_SC | = FTM_SC_TOF ;
}
void timerEnableReceiveInterrupt ( ) {
NVIC_ENABLE_IRQ ( IRQ_FTM1 ) ;
NVIC_SET_PRIORITY ( IRQ_FTM1 , 0 ) ;
}
void timerDisableReceiveInterrupt ( ) {
NVIC_DISABLE_IRQ ( IRQ_FTM1 ) ;
}
2021-03-06 20:47:47 +08:00
# define TIMER_INTR_NAME ftm1_isr
2022-04-05 10:47:32 +08:00
# if defined(ISR)
2021-03-06 20:47:47 +08:00
# undef ISR
# endif
2021-12-22 04:51:28 +08:00
# define ISR(f) void f(void)
2021-03-06 20:47:47 +08:00
2022-01-27 01:36:50 +08:00
void timerConfigForReceive ( ) {
2021-03-06 20:47:47 +08:00
SIM_SCGC6 | = SIM_SCGC6_TPM1 ;
FTM1_SC = 0 ;
FTM1_CNT = 0 ;
2022-01-27 01:36:50 +08:00
FTM1_MOD = ( F_PLL / 40000 ) - 1 ;
FTM1_C0V = 0 ;
FTM1_SC = FTM_SC_CLKS ( 1 ) | FTM_SC_PS ( 0 ) | FTM_SC_TOF | FTM_SC_TOIE ;
2021-03-06 20:47:47 +08:00
}
2022-01-27 01:36:50 +08:00
# if defined(SEND_PWM_BY_TIMER)
# define IR_SEND_PIN 16
2022-12-23 22:24:10 +08:00
void enableSendPWMByTimer ( ) {
FTM1_CNT = 0 ;
CORE_PIN16_CONFIG = PORT_PCR_MUX ( 3 ) | PORT_PCR_DSE | PORT_PCR_SRE ;
}
void disableSendPWMByTimer ( ) {
CORE_PIN16_CONFIG = PORT_PCR_MUX ( 1 ) | PORT_PCR_SRE ;
}
2022-01-27 01:36:50 +08:00
/*
* timerConfigForSend ( ) is used exclusively by IRsend : : enableIROut ( )
* Set output pin mode and disable receive interrupt if it uses the same resource
*/
2023-03-29 19:28:06 +08:00
void timerConfigForSend ( uint16_t aFrequencyKHz ) {
2022-12-23 22:24:10 +08:00
timerDisableReceiveInterrupt ( ) ;
2022-07-17 03:33:09 +08:00
# if defined(IR_SEND_PIN)
pinMode ( IR_SEND_PIN , OUTPUT ) ;
# else
pinMode ( IrSender . sendPin , OUTPUT ) ;
# endif
2022-01-27 01:36:50 +08:00
2021-03-06 20:47:47 +08:00
SIM_SCGC6 | = SIM_SCGC6_TPM1 ;
FTM1_SC = 0 ;
FTM1_CNT = 0 ;
2022-01-27 01:36:50 +08:00
FTM1_MOD = ( ( F_PLL / 2000 ) / aFrequencyKHz ) - 1 ;
FTM1_C0V = ( ( F_PLL / 6000 ) / aFrequencyKHz ) - 1 ;
FTM1_SC = FTM_SC_CLKS ( 1 ) | FTM_SC_PS ( 0 ) ;
2021-03-06 20:47:47 +08:00
}
2022-01-27 01:36:50 +08:00
# endif // defined(SEND_PWM_BY_TIMER)
2021-03-06 20:47:47 +08:00
2021-12-22 04:51:28 +08:00
/***************************************
* Teensy 4.0 , 4.1 , MicroMod boards
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# elif defined(__IMXRT1062__)
2023-03-16 06:01:55 +08:00
// forward declare ISR function (will be implemented by IRReceive.hpp)
void pwm1_3_isr ( ) ;
2021-12-22 04:51:28 +08:00
// defines for FlexPWM1 timer on Teensy 4
2022-12-23 22:24:10 +08:00
# define TIMER_REQUIRES_RESET_INTR_PENDING
void timerResetInterruptPending ( ) {
FLEXPWM1_SM3STS = FLEXPWM_SMSTS_RF ;
}
void timerEnableReceiveInterrupt ( ) {
attachInterruptVector ( IRQ_FLEXPWM1_3 , pwm1_3_isr ) ;
FLEXPWM1_SM3STS = FLEXPWM_SMSTS_RF ;
FLEXPWM1_SM3INTEN = FLEXPWM_SMINTEN_RIE ;
NVIC_ENABLE_IRQ ( IRQ_FLEXPWM1_3 ) , NVIC_SET_PRIORITY ( IRQ_FLEXPWM1_3 , 48 ) ;
}
void timerDisableReceiveInterrupt ( ) {
NVIC_DISABLE_IRQ ( IRQ_FLEXPWM1_3 ) ;
}
2021-12-22 04:51:28 +08:00
# define TIMER_INTR_NAME pwm1_3_isr
2022-04-05 10:47:32 +08:00
# if defined(ISR)
2021-12-22 04:51:28 +08:00
# undef ISR
# endif
# define ISR(f) void (f)(void)
2022-01-27 01:36:50 +08:00
void timerConfigForReceive ( ) {
2022-12-23 22:24:10 +08:00
uint32_t period = ( float ) F_BUS_ACTUAL * ( float ) ( MICROS_PER_TICK ) * 0.0000005f ;
2021-12-22 04:51:28 +08:00
uint32_t prescale = 0 ;
while ( period > 32767 ) {
period = period > > 1 ;
2022-12-23 22:24:10 +08:00
if ( prescale < 7 )
prescale + + ;
2021-12-22 04:51:28 +08:00
}
FLEXPWM1_FCTRL0 | = FLEXPWM_FCTRL0_FLVL ( 8 ) ;
FLEXPWM1_FSTS0 = 0x0008 ;
FLEXPWM1_MCTRL | = FLEXPWM_MCTRL_CLDOK ( 8 ) ;
FLEXPWM1_SM3CTRL2 = FLEXPWM_SMCTRL2_INDEP ;
FLEXPWM1_SM3CTRL = FLEXPWM_SMCTRL_HALF | FLEXPWM_SMCTRL_PRSC ( prescale ) ;
FLEXPWM1_SM3INIT = - period ;
FLEXPWM1_SM3VAL0 = 0 ;
FLEXPWM1_SM3VAL1 = period ;
2022-01-27 01:36:50 +08:00
FLEXPWM1_SM3VAL2 = 0 ;
FLEXPWM1_SM3VAL3 = 0 ;
2021-12-22 04:51:28 +08:00
FLEXPWM1_SM3VAL4 = 0 ;
FLEXPWM1_SM3VAL5 = 0 ;
FLEXPWM1_MCTRL | = FLEXPWM_MCTRL_LDOK ( 8 ) | FLEXPWM_MCTRL_RUN ( 8 ) ;
}
2022-01-27 01:36:50 +08:00
# if defined(SEND_PWM_BY_TIMER)
# define IR_SEND_PIN 7
2022-12-23 22:24:10 +08:00
void enableSendPWMByTimer ( ) {
FLEXPWM1_OUTEN | = FLEXPWM_OUTEN_PWMA_EN ( 8 ) ;
IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_00 = 6 ;
}
void disableSendPWMByTimer ( ) {
IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_00 = 5 ;
FLEXPWM1_OUTEN & = ~ FLEXPWM_OUTEN_PWMA_EN ( 8 ) ;
}
2022-01-27 01:36:50 +08:00
/*
* timerConfigForSend ( ) is used exclusively by IRsend : : enableIROut ( )
* Set output pin mode and disable receive interrupt if it uses the same resource
*/
2023-03-29 19:28:06 +08:00
void timerConfigForSend ( uint16_t aFrequencyKHz ) {
2022-12-23 22:24:10 +08:00
timerDisableReceiveInterrupt ( ) ;
2022-07-17 03:33:09 +08:00
# if defined(IR_SEND_PIN)
pinMode ( IR_SEND_PIN , OUTPUT ) ;
# else
pinMode ( IrSender . sendPin , OUTPUT ) ;
# endif
2022-01-27 01:36:50 +08:00
2022-12-23 22:24:10 +08:00
uint32_t period = ( float ) F_BUS_ACTUAL / ( float ) ( ( aFrequencyKHz ) * 2000 ) ;
2021-12-22 04:51:28 +08:00
uint32_t prescale = 0 ;
while ( period > 32767 ) {
period = period > > 1 ;
2022-12-23 22:24:10 +08:00
if ( prescale < 7 )
prescale + + ;
2021-12-22 04:51:28 +08:00
}
FLEXPWM1_FCTRL0 | = FLEXPWM_FCTRL0_FLVL ( 8 ) ;
FLEXPWM1_FSTS0 = 0x0008 ;
FLEXPWM1_MCTRL | = FLEXPWM_MCTRL_CLDOK ( 8 ) ;
FLEXPWM1_SM3CTRL2 = FLEXPWM_SMCTRL2_INDEP ;
FLEXPWM1_SM3CTRL = FLEXPWM_SMCTRL_HALF | FLEXPWM_SMCTRL_PRSC ( prescale ) ;
FLEXPWM1_SM3INIT = - period ;
FLEXPWM1_SM3VAL0 = 0 ;
FLEXPWM1_SM3VAL1 = period ;
2022-01-27 01:36:50 +08:00
FLEXPWM1_SM3VAL2 = - ( period / 3 ) ;
FLEXPWM1_SM3VAL3 = period / 3 ;
2021-12-22 04:51:28 +08:00
FLEXPWM1_SM3VAL4 = 0 ;
FLEXPWM1_SM3VAL5 = 0 ;
FLEXPWM1_MCTRL | = FLEXPWM_MCTRL_LDOK ( 8 ) | FLEXPWM_MCTRL_RUN ( 8 ) ;
}
2022-01-27 01:36:50 +08:00
# endif // defined(SEND_PWM_BY_TIMER)
2021-12-22 04:51:28 +08:00
2024-04-08 02:20:49 +08:00
/**********************************************************
* ESP8266 boards
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2021-04-11 08:03:27 +08:00
# elif defined(ESP8266)
2022-12-23 22:24:10 +08:00
# if defined(SEND_PWM_BY_TIMER)
# error "No support for hardware PWM generation for ESP8266"
# endif // defined(SEND_PWM_BY_TIMER)
2021-04-11 08:03:27 +08:00
2023-03-01 20:37:15 +08:00
// Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
2022-04-05 10:47:32 +08:00
# if defined(ISR)
2021-04-11 08:03:27 +08:00
# undef ISR
# endif
2022-12-23 22:24:10 +08:00
void timerEnableReceiveInterrupt ( ) {
2023-03-01 20:37:15 +08:00
timer1_attachInterrupt ( & IRReceiveTimerInterruptHandler ) ; // enables interrupt too
2022-12-23 22:24:10 +08:00
}
void timerDisableReceiveInterrupt ( ) {
timer1_detachInterrupt ( ) ; // disables interrupt too }
}
2021-04-11 08:03:27 +08:00
void timerConfigForReceive ( ) {
timer1_isr_init ( ) ;
/*
* TIM_DIV1 = 0 , //80MHz (80 ticks/us - 104857.588 us max)
* TIM_DIV16 = 1 , //5MHz (5 ticks/us - 1677721.4 us max)
* TIM_DIV256 = 3 //312.5Khz (1 tick = 3.2us - 26843542.4 us max)
*/
timer1_enable ( TIM_DIV16 , TIM_EDGE , TIM_LOOP ) ;
2021-04-19 20:06:29 +08:00
timer1_write ( ( 80 / 16 ) * MICROS_PER_TICK ) ; // 80 for 80 and 160! MHz clock, 16 for TIM_DIV16 above
2021-04-11 08:03:27 +08:00
}
2022-05-21 00:54:51 +08:00
/**********************************************************
2022-01-27 01:36:50 +08:00
* ESP32 boards - can use any pin for send PWM
2022-05-21 00:54:51 +08:00
* Receive timer and send generation are independent ,
* so it is recommended to always define SEND_PWM_BY_TIMER
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2021-03-06 20:47:47 +08:00
# elif defined(ESP32)
2022-12-23 22:24:10 +08:00
// Variables specific to the ESP32.
// the ledc functions behave like hardware timers for us :-), so we do not require our own soft PWM generation code.
2023-05-30 06:29:54 +08:00
hw_timer_t * s50usTimer = NULL ; // set by timerConfigForReceive()
2022-12-23 22:24:10 +08:00
2024-04-08 02:20:49 +08:00
# if ESP_ARDUINO_VERSION < ESP_ARDUINO_VERSION_VAL(3, 0, 0) && !defined(SEND_LEDC_CHANNEL)
# define SEND_LEDC_CHANNEL 0 // The channel used for PWM 0 to 7 are high speed PWM channels
2021-03-06 20:47:47 +08:00
# endif
2022-12-23 22:24:10 +08:00
void timerEnableReceiveInterrupt ( ) {
2023-05-30 06:29:54 +08:00
timerAlarmEnable ( s50usTimer ) ;
2022-12-23 22:24:10 +08:00
}
2023-03-25 16:31:20 +08:00
# if !defined(ESP_ARDUINO_VERSION)
# define ESP_ARDUINO_VERSION 0
# endif
# if !defined(ESP_ARDUINO_VERSION_VAL)
# define ESP_ARDUINO_VERSION_VAL(major, minor, patch) 202
# endif
2023-03-29 08:07:26 +08:00
# if ESP_ARDUINO_VERSION < ESP_ARDUINO_VERSION_VAL(2, 0, 2)
2022-12-23 22:24:10 +08:00
void timerDisableReceiveInterrupt ( ) {
if ( s50usTimer ! = NULL ) {
timerDetachInterrupt ( s50usTimer ) ;
2023-05-30 06:29:54 +08:00
timerEnd ( s50usTimer ) ;
2022-12-23 22:24:10 +08:00
}
}
2023-03-29 08:07:26 +08:00
# else
2022-12-23 22:24:10 +08:00
void timerDisableReceiveInterrupt ( ) {
if ( s50usTimer ! = NULL ) {
2023-05-30 06:29:54 +08:00
timerAlarmDisable ( s50usTimer ) ;
2022-12-23 22:24:10 +08:00
}
}
2023-03-29 08:07:26 +08:00
# endif
2023-03-25 16:31:20 +08:00
2023-03-01 20:37:15 +08:00
// Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
2022-04-05 10:47:32 +08:00
# if defined(ISR)
2021-03-06 20:47:47 +08:00
# undef ISR
# endif
2024-02-29 09:05:55 +08:00
# if !defined(DISABLE_CODE_FOR_RECEIVER) // &IRReceiveTimerInterruptHandler is referenced, but not available
2021-03-06 20:47:47 +08:00
void timerConfigForReceive ( ) {
// ESP32 has a proper API to setup timers, no weird chip macros needed
// simply call the readable API versions :)
// 3 timers, choose #1, 80 divider for microsecond precision @80MHz clock, count_up = true
2023-05-30 06:29:54 +08:00
if ( s50usTimer = = NULL ) {
s50usTimer = timerBegin ( 1 , 80 , true ) ;
timerAttachInterrupt ( s50usTimer , & IRReceiveTimerInterruptHandler , false ) ; // false -> level interrupt, true -> edge interrupt, but this is not supported :-(
timerAlarmWrite ( s50usTimer , MICROS_PER_TICK , true ) ;
}
2021-03-06 20:47:47 +08:00
// every 50 us, autoreload = true
}
2024-02-29 09:05:55 +08:00
# endif
2021-03-06 20:47:47 +08:00
2024-01-01 06:53:49 +08:00
# if !defined(IR_SEND_PIN)
uint8_t sLastSendPin = 0 ; // To detach before attach, if already attached
# endif
2022-01-27 01:36:50 +08:00
# if defined(SEND_PWM_BY_TIMER)
2022-12-23 22:24:10 +08:00
void enableSendPWMByTimer ( ) {
2024-01-01 06:53:49 +08:00
# if ESP_ARDUINO_VERSION < ESP_ARDUINO_VERSION_VAL(3, 0, 0)
2024-04-08 02:20:49 +08:00
ledcWrite ( SEND_LEDC_CHANNEL , ( IR_SEND_DUTY_CYCLE_PERCENT * 256 ) / 100 ) ; // * 256 since we have 8 bit resolution
2024-01-01 06:53:49 +08:00
# else
ledcWrite ( IrSender . sendPin , ( IR_SEND_DUTY_CYCLE_PERCENT * 256 ) / 100 ) ; // New API
# endif
2022-12-23 22:24:10 +08:00
}
void disableSendPWMByTimer ( ) {
2024-01-01 06:53:49 +08:00
# if ESP_ARDUINO_VERSION < ESP_ARDUINO_VERSION_VAL(3, 0, 0)
2024-04-08 02:20:49 +08:00
ledcWrite ( SEND_LEDC_CHANNEL , 0 ) ;
2024-01-01 06:53:49 +08:00
# else
ledcWrite ( IrSender . sendPin , 0 ) ; // New API
# endif
2022-12-23 22:24:10 +08:00
}
2022-01-27 01:36:50 +08:00
/*
2024-01-01 06:53:49 +08:00
* timerConfigForSend ( ) is used exclusively by IRsend : : enableIROut ( ) ( or enableHighFrequencyIROut ( ) )
* ledcWrite since ESP 2.0 .2 does not work if pin mode is set .
2022-01-27 01:36:50 +08:00
*/
2023-03-29 19:28:06 +08:00
void timerConfigForSend ( uint16_t aFrequencyKHz ) {
2024-01-01 06:53:49 +08:00
# if ESP_ARDUINO_VERSION < ESP_ARDUINO_VERSION_VAL(3, 0, 0)
2024-04-08 02:20:49 +08:00
ledcSetup ( SEND_LEDC_CHANNEL , aFrequencyKHz * 1000 , 8 ) ; // 8 bit PWM resolution
2024-01-01 06:53:49 +08:00
# if defined(IR_SEND_PIN)
2024-04-08 02:20:49 +08:00
ledcAttachPin ( IR_SEND_PIN , SEND_LEDC_CHANNEL ) ; // attach pin to channel
2024-01-01 06:53:49 +08:00
# else
if ( sLastSendPin ! = 0 & & sLastSendPin ! = IrSender . sendPin ) {
ledcDetachPin ( IrSender . sendPin ) ; // detach pin before new attaching see #1194
}
2024-04-08 02:20:49 +08:00
ledcAttachPin ( IrSender . sendPin , SEND_LEDC_CHANNEL ) ; // attach pin to channel
2024-01-01 06:53:49 +08:00
sLastSendPin = IrSender . sendPin ;
# endif
# else // New API here
# if defined(IR_SEND_PIN)
ledcAttach ( IR_SEND_PIN , aFrequencyKHz * 1000 , 8 ) ; // New API
# else
if ( sLastSendPin ! = 0 & & sLastSendPin ! = IrSender . sendPin ) {
ledcDetach ( IrSender . sendPin ) ; // detach pin before new attaching see #1194
}
ledcAttach ( IrSender . sendPin , aFrequencyKHz * 1000 , 8 ) ; // New API
sLastSendPin = IrSender . sendPin ;
# endif
2022-01-27 01:36:50 +08:00
# endif
}
# endif // defined(SEND_PWM_BY_TIMER)
2021-03-06 20:47:47 +08:00
/***************************************
* SAMD boards like DUE and Zero
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# elif defined(ARDUINO_ARCH_SAMD)
2021-04-11 19:16:53 +08:00
# if defined(SEND_PWM_BY_TIMER)
2022-07-29 21:05:17 +08:00
# error PWM generation by hardware is not yet implemented for SAMD
2021-03-06 20:47:47 +08:00
# endif
2021-09-06 23:19:51 +08:00
# if !defined(IR_SAMD_TIMER)
2022-07-29 21:05:17 +08:00
# if defined(__SAMD51__)
# define IR_SAMD_TIMER TC5
# define IR_SAMD_TIMER_IRQ TC5_IRQn
# else
// SAMD21
2021-09-06 23:19:51 +08:00
# define IR_SAMD_TIMER TC3
# define IR_SAMD_TIMER_ID GCLK_CLKCTRL_ID_TCC2_TC3
2022-07-29 21:05:17 +08:00
# define IR_SAMD_TIMER_IRQ TC3_IRQn
# endif
# endif
2021-09-06 23:19:51 +08:00
2022-12-23 22:24:10 +08:00
void timerEnableReceiveInterrupt ( ) {
NVIC_EnableIRQ ( IR_SAMD_TIMER_IRQ ) ;
}
void timerDisableReceiveInterrupt ( ) {
NVIC_DisableIRQ ( IR_SAMD_TIMER_IRQ ) ; // or TC5->INTENCLR.bit.MC0 = 1; or TC5->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE;
}
2023-03-01 20:37:15 +08:00
// Undefine ISR, because we call the plain function IRReceiveTimerInterruptHandler()
2022-11-14 22:53:29 +08:00
// The ISR is now TC3_Handler() or TC5_Handler() below
2022-04-05 10:47:32 +08:00
# if defined(ISR)
2021-03-06 20:47:47 +08:00
# undef ISR
# endif
2022-07-29 21:05:17 +08:00
/**
* Adafruit M4 code ( cores / arduino / startup . c ) configures these clock generators :
* GCLK0 = F_CPU
* GCLK2 = 100 MHz
* GCLK1 = 48 MHz // This Clock is present in SAMD21 and SAMD51
* GCLK4 = 12 MHz
* GCLK3 = XOSC32K
*/
2021-03-06 20:47:47 +08:00
void timerConfigForReceive ( ) {
2022-07-29 21:05:17 +08:00
TcCount16 * TC = ( TcCount16 * ) IR_SAMD_TIMER ;
# if defined(__SAMD51__)
// Enable the TC5 clock, use generic clock generator 0 (F_CPU) for TC5
GCLK - > PCHCTRL [ TC5_GCLK_ID ] . reg = GCLK_PCHCTRL_GEN_GCLK0_Val | ( 1 < < GCLK_PCHCTRL_CHEN_Pos ) ;
// The TC should be disabled before the TC is reset in order to avoid undefined behavior.
TC - > CTRLA . reg & = ~ TC_CTRLA_ENABLE ; // Disable the Timer
while ( TC - > SYNCBUSY . bit . ENABLE )
; // Wait for disabled
// Reset TCx
TC - > CTRLA . reg = TC_CTRLA_SWRST ;
// When writing a '1' to the CTRLA.SWRST bit it will immediately read as '1'.
while ( TC - > SYNCBUSY . bit . SWRST )
; // CTRL.SWRST will be cleared by hardware when the peripheral has been reset.
// SAMD51 has F_CPU = 120 MHz
TC - > CC [ 0 ] . reg = ( ( MICROS_PER_TICK * ( F_CPU / MICROS_IN_ONE_SECOND ) ) / 16 ) - 1 ; // (375 - 1);
/*
* Set timer counter mode to 16 bits , set mode as match frequency , prescaler is DIV16 = > 7.5 MHz clock , start counter
*/
TC - > CTRLA . reg | = TC_CTRLA_MODE_COUNT16 | TC_WAVE_WAVEGEN_MFRQ | TC_CTRLA_PRESCALER_DIV16 | TC_CTRLA_ENABLE ;
// while (TC5->COUNT16.STATUS.bit.SYNCBUSY == 1); // The next commands do an implicit wait :-)
# else
// Enable GCLK and select GCLK0 (F_CPU) as clock for TC4 and TC5
2022-12-23 22:24:10 +08:00
REG_GCLK_CLKCTRL = ( uint16_t ) ( GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | IR_SAMD_TIMER_ID ) ;
while ( GCLK - > STATUS . bit . SYNCBUSY = = 1 )
;
2021-03-06 20:47:47 +08:00
// The TC should be disabled before the TC is reset in order to avoid undefined behavior.
TC - > CTRLA . reg & = ~ TC_CTRLA_ENABLE ;
// When write-synchronization is ongoing for a register, any subsequent write attempts to this register will be discarded, and an error will be reported.
2022-12-23 22:24:10 +08:00
while ( TC - > STATUS . bit . SYNCBUSY = = 1 )
; // wait for sync to ensure that we can write again to COUNT16.CTRLA.reg
2022-07-29 21:05:17 +08:00
// Reset TCx
2021-03-06 20:47:47 +08:00
TC - > CTRLA . reg = TC_CTRLA_SWRST ;
2023-03-16 06:01:55 +08:00
// When writing a 1 to the CTRLA.SWRST bit it will immediately read as 1.
2022-12-23 22:24:10 +08:00
while ( TC - > CTRLA . bit . SWRST )
; // CTRL.SWRST will be cleared by hardware when the peripheral has been reset.
2021-03-06 20:47:47 +08:00
2022-07-29 21:05:17 +08:00
// SAMD51 has F_CPU = 48 MHz
TC - > CC [ 0 ] . reg = ( ( MICROS_PER_TICK * ( F_CPU / MICROS_IN_ONE_SECOND ) ) / 16 ) - 1 ; // (150 - 1);
2021-03-06 20:47:47 +08:00
2022-07-29 21:05:17 +08:00
/*
* Set timer counter mode to 16 bits , set mode as match frequency , prescaler is DIV16 = > 3 MHz clock , start counter
*/
TC - > CTRLA . reg | = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_WAVEGEN_MFRQ | TC_CTRLA_PRESCALER_DIV16 | TC_CTRLA_ENABLE ;
# endif
// Configure interrupt request
NVIC_DisableIRQ ( IR_SAMD_TIMER_IRQ ) ;
NVIC_ClearPendingIRQ ( IR_SAMD_TIMER_IRQ ) ;
NVIC_SetPriority ( IR_SAMD_TIMER_IRQ , 0 ) ;
NVIC_EnableIRQ ( IR_SAMD_TIMER_IRQ ) ;
2021-03-06 20:47:47 +08:00
// Enable the compare interrupt
TC - > INTENSET . bit . MC0 = 1 ;
}
2022-11-14 22:53:29 +08:00
# if !defined(DISABLE_CODE_FOR_RECEIVER)
# if defined(__SAMD51__)
2022-07-29 21:05:17 +08:00
void TC5_Handler ( void ) {
TcCount16 * TC = ( TcCount16 * ) IR_SAMD_TIMER ;
// Check for right interrupt bit
if ( TC - > INTFLAG . bit . MC0 = = 1 ) {
// reset bit for next turn
TC - > INTFLAG . bit . MC0 = 1 ;
2023-03-01 20:37:15 +08:00
IRReceiveTimerInterruptHandler ( ) ;
2022-07-29 21:05:17 +08:00
}
}
2022-11-14 22:53:29 +08:00
# else
2021-03-06 20:47:47 +08:00
void TC3_Handler ( void ) {
2021-09-06 23:19:51 +08:00
TcCount16 * TC = ( TcCount16 * ) IR_SAMD_TIMER ;
// Check for right interrupt bit
2021-03-06 20:47:47 +08:00
if ( TC - > INTFLAG . bit . MC0 = = 1 ) {
2021-09-06 23:19:51 +08:00
// reset bit for next turn
2021-03-06 20:47:47 +08:00
TC - > INTFLAG . bit . MC0 = 1 ;
2023-03-01 20:37:15 +08:00
IRReceiveTimerInterruptHandler ( ) ;
2021-03-06 20:47:47 +08:00
}
}
2022-11-14 22:53:29 +08:00
# endif // defined(__SAMD51__)
# endif // !defined(DISABLE_CODE_FOR_RECEIVER)
2021-03-06 20:47:47 +08:00
2021-10-03 02:17:30 +08:00
/***************************************
* Mbed based boards
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-01-27 01:36:50 +08:00
# elif defined(ARDUINO_ARCH_MBED) // Arduino Nano 33 BLE + Sparkfun Apollo3 + Nano RP2040 Connect
2021-10-03 02:17:30 +08:00
# include "mbed.h"
2022-12-23 22:24:10 +08:00
mbed : : Ticker s50usTimer ;
2021-10-03 02:17:30 +08:00
2023-03-01 20:37:15 +08:00
// Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
2022-04-05 10:47:32 +08:00
# if defined(ISR)
2021-10-03 02:17:30 +08:00
# undef ISR
# endif
2022-12-23 22:24:10 +08:00
void timerEnableReceiveInterrupt ( ) {
2023-03-01 20:37:15 +08:00
s50usTimer . attach ( IRReceiveTimerInterruptHandler , std : : chrono : : microseconds ( MICROS_PER_TICK ) ) ;
2022-12-23 22:24:10 +08:00
}
void timerDisableReceiveInterrupt ( ) {
s50usTimer . detach ( ) ;
}
2021-10-03 02:17:30 +08:00
void timerConfigForReceive ( ) {
2023-03-01 20:37:15 +08:00
s50usTimer . attach ( IRReceiveTimerInterruptHandler , std : : chrono : : microseconds ( MICROS_PER_TICK ) ) ;
2021-10-03 02:17:30 +08:00
}
2022-01-27 01:36:50 +08:00
# if defined(SEND_PWM_BY_TIMER)
# include "pins_arduino.h" // for digitalPinToPinName()
# if defined(IR_SEND_PIN)
mbed : : PwmOut sPwmOutForSendPWM ( digitalPinToPinName ( IR_SEND_PIN ) ) ;
# else
mbed : : PwmOut sPwmOutForSendPWM ( digitalPinToPinName ( IrSender . sendPin ) ) ;
# endif
uint8_t sIROutPuseWidth ;
2022-12-23 22:24:10 +08:00
void enableSendPWMByTimer ( ) {
sPwmOutForSendPWM . pulsewidth_us ( sIROutPuseWidth ) ;
}
//void enableSendPWMByTimer() { sPwmOutForSendPWM.resume(); sPwmOutForSendPWM.pulsewidth_us(sIROutPuseWidth);}
//void disableSendPWMByTimer() { sPwmOutForSendPWM.suspend();} // this kills pulsewidth_us value and does not set output level to LOW
void disableSendPWMByTimer ( ) {
sPwmOutForSendPWM . pulsewidth_us ( 0 ) ; // this also sets output level to LOW :-)
}
2022-01-27 01:36:50 +08:00
/*
* timerConfigForSend ( ) is used exclusively by IRsend : : enableIROut ( )
* Set output pin mode and disable receive interrupt if it uses the same resource
*/
2023-03-29 19:28:06 +08:00
void timerConfigForSend ( uint16_t aFrequencyKHz ) {
2022-01-27 01:36:50 +08:00
sPwmOutForSendPWM . period_us ( 1000 / aFrequencyKHz ) ; // 26.315 for 38 kHz
sIROutPuseWidth = ( 1000 * IR_SEND_DUTY_CYCLE_PERCENT ) / ( aFrequencyKHz * 100 ) ;
}
# endif // defined(SEND_PWM_BY_TIMER)
/*************************************************************************************************************************************
* RP2040 based boards for pico core
* https : //github.com/earlephilhower/arduino-pico
* https : //github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
* Can use any pin for PWM , no timer restrictions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-01-23 22:23:16 +08:00
# elif defined(ARDUINO_ARCH_RP2040) // Raspberry Pi Pico, Adafruit Feather RP2040, etc.
# include "pico/time.h"
2022-01-27 01:36:50 +08:00
2022-01-29 03:26:58 +08:00
repeating_timer_t s50usTimer ;
2022-01-23 22:23:16 +08:00
2023-03-01 20:37:15 +08:00
// Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
2022-04-05 10:47:32 +08:00
# if defined(ISR)
2022-01-23 22:23:16 +08:00
# undef ISR
# endif
2023-03-01 20:37:15 +08:00
2022-01-27 01:36:50 +08:00
// The timer callback has a parameter and a return value
bool IRTimerInterruptHandlerHelper ( repeating_timer_t * ) {
2023-03-01 20:37:15 +08:00
IRReceiveTimerInterruptHandler ( ) ;
2022-01-23 22:23:16 +08:00
return true ;
}
2022-12-23 22:24:10 +08:00
void timerEnableReceiveInterrupt ( ) {
add_repeating_timer_us ( - ( MICROS_PER_TICK ) , IRTimerInterruptHandlerHelper , NULL , & s50usTimer ) ;
}
void timerDisableReceiveInterrupt ( ) {
cancel_repeating_timer ( & s50usTimer ) ;
}
2022-01-27 01:36:50 +08:00
void timerConfigForReceive ( ) {
// no need for initializing timer at setup()
}
# if defined(SEND_PWM_BY_TIMER)
# include "hardware/pwm.h"
uint sSliceNumberForSendPWM ;
uint sChannelNumberForSendPWM ;
2022-01-27 20:18:08 +08:00
uint sIROutPuseWidth ;
2022-01-27 01:36:50 +08:00
/*
* If we just disable the PWM , the counter stops and the output stays at the state is currently has
*/
2022-12-23 22:24:10 +08:00
void enableSendPWMByTimer ( ) {
pwm_set_counter ( sSliceNumberForSendPWM , 0 ) ;
pwm_set_chan_level ( sSliceNumberForSendPWM , sChannelNumberForSendPWM , sIROutPuseWidth ) ;
}
void disableSendPWMByTimer ( ) {
pwm_set_chan_level ( sSliceNumberForSendPWM , sChannelNumberForSendPWM , 0 ) ; // this sets output also to LOW
}
2022-01-27 01:36:50 +08:00
/*
* timerConfigForSend ( ) is used exclusively by IRsend : : enableIROut ( )
* Set output pin mode and disable receive interrupt if it uses the same resource
*/
2023-03-29 19:28:06 +08:00
void timerConfigForSend ( uint16_t aFrequencyKHz ) {
2022-01-27 01:36:50 +08:00
# if defined(IR_SEND_PIN)
gpio_set_function ( IR_SEND_PIN , GPIO_FUNC_PWM ) ;
// Find out which PWM slice is connected to IR_SEND_PIN
sSliceNumberForSendPWM = pwm_gpio_to_slice_num ( IR_SEND_PIN ) ;
sChannelNumberForSendPWM = pwm_gpio_to_channel ( IR_SEND_PIN ) ;
# else
gpio_set_function ( IrSender . sendPin , GPIO_FUNC_PWM ) ;
// Find out which PWM slice is connected to IR_SEND_PIN
sSliceNumberForSendPWM = pwm_gpio_to_slice_num ( IrSender . sendPin ) ;
sChannelNumberForSendPWM = pwm_gpio_to_channel ( IrSender . sendPin ) ;
# endif
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)
2022-07-16 16:03:01 +08:00
2022-01-27 01:36:50 +08:00
pwm_config tPWMConfig = pwm_get_default_config ( ) ;
pwm_config_set_wrap ( & tPWMConfig , tPWMWrapValue - 1 ) ;
pwm_init ( sSliceNumberForSendPWM , & tPWMConfig , false ) ; // we do not want to send now
2022-01-27 20:18:08 +08:00
sIROutPuseWidth = ( ( tPWMWrapValue * IR_SEND_DUTY_CYCLE_PERCENT ) / 100 ) - 1 ; // 985.84 for 38 kHz
pwm_set_chan_level ( sSliceNumberForSendPWM , sChannelNumberForSendPWM , 0 ) ;
pwm_set_enabled ( sSliceNumberForSendPWM , true ) ;
2022-01-27 01:36:50 +08:00
}
# endif // defined(SEND_PWM_BY_TIMER)
2022-01-23 22:23:16 +08:00
2021-03-06 20:47:47 +08:00
/***************************************
* NRF5 boards like the BBC : Micro
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2023-07-25 17:05:59 +08:00
# elif defined(NRF5) || defined(ARDUINO_ARCH_NRF52840) || defined(ARDUINO_ARCH_NRF52)
2021-04-11 19:16:53 +08:00
# if defined(SEND_PWM_BY_TIMER)
2021-03-06 20:47:47 +08:00
# error PWM generation by hardware not implemented for NRF5
# endif
2022-12-23 22:24:10 +08:00
void timerEnableReceiveInterrupt ( ) {
NVIC_EnableIRQ ( TIMER2_IRQn ) ;
}
void timerDisableReceiveInterrupt ( ) {
NVIC_DisableIRQ ( TIMER2_IRQn ) ;
}
2023-03-01 20:37:15 +08:00
// Undefine ISR, because we call the plain function IRReceiveTimerInterruptHandler()
2022-04-05 10:47:32 +08:00
# if defined(ISR)
2021-03-06 20:47:47 +08:00
# undef ISR
# endif
void timerConfigForReceive ( ) {
NRF_TIMER2 - > MODE = TIMER_MODE_MODE_Timer ; // Set the timer in Timer Mode
2022-12-23 22:24:10 +08:00
NRF_TIMER2 - > TASKS_CLEAR = 1 ; // clear the task first to be usable for later
NRF_TIMER2 - > PRESCALER = 4 ; // f TIMER = 16 MHz / (2 ^ PRESCALER ) : 4 -> 1 MHz, 1 uS
NRF_TIMER2 - > BITMODE = TIMER_BITMODE_BITMODE_16Bit ; //Set counter to 16 bit resolution
NRF_TIMER2 - > CC [ 0 ] = MICROS_PER_TICK ; //Set value for TIMER2 compare register 0, to trigger every 50 uS
NRF_TIMER2 - > CC [ 1 ] = 0 ; //Set value for TIMER2 compare register 1
2021-03-06 20:47:47 +08:00
// Enable interrupt on Timer 2, for CC[0] compare match events
NRF_TIMER2 - > INTENSET = ( TIMER_INTENSET_COMPARE0_Enabled < < TIMER_INTENSET_COMPARE0_Pos ) ;
2022-12-23 22:24:10 +08:00
NRF_TIMER2 - > TASKS_START = 1 ; // Start TIMER2
2021-03-06 20:47:47 +08:00
// timerAttachInterrupt(timer, &IRTimerInterruptHandler, 1);
}
2022-11-14 22:53:29 +08:00
# if !defined(DISABLE_CODE_FOR_RECEIVER)
2021-03-06 20:47:47 +08:00
/** TIMTER2 peripheral interrupt handler. This interrupt handler is called whenever there it a TIMER2 interrupt
* Don ' t mess with this line . really .
*/
extern " C " {
2022-12-23 22:24:10 +08:00
void TIMER2_IRQHandler ( void ) {
// Interrupt Service Routine - Fires every 50uS
if ( ( NRF_TIMER2 - > EVENTS_COMPARE [ 0 ] ! = 0 ) & & ( ( NRF_TIMER2 - > INTENSET & TIMER_INTENSET_COMPARE0_Msk ) ! = 0 ) ) {
NRF_TIMER2 - > EVENTS_COMPARE [ 0 ] = 0 ; //Clear compare register 0 event
2023-03-01 20:37:15 +08:00
IRReceiveTimerInterruptHandler ( ) ; // call the IR-receive function
2022-12-23 22:24:10 +08:00
NRF_TIMER2 - > CC [ 0 ] + = 50 ;
2021-03-06 20:47:47 +08:00
}
}
2022-12-23 22:24:10 +08:00
}
2022-11-14 22:53:29 +08:00
# endif
2021-03-06 20:47:47 +08:00
/**********************************************************************************************************************
* BluePill in 2 flavors see https : //samuelpinches.com.au/3d-printer/cutting-through-some-confusion-on-stm32-and-arduino/
*
* Recommended original Arduino_STM32 by Roger Clark .
* http : //dan.drown.org/stm32duino/package_STM32duino_index.json
* STM32F1 architecture for " Generic STM32F103C series " from " STM32F1 Boards (Arduino_STM32) " of Arduino Board manager
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# elif defined(__STM32F1__) || defined(ARDUINO_ARCH_STM32F1)
# include <HardwareTimer.h> // 4 timers and 4. timer (4.channel) is used for tone()
2021-04-11 19:16:53 +08:00
# if defined(SEND_PWM_BY_TIMER)
2021-03-06 20:47:47 +08:00
# error PWM generation by hardware not implemented for STM32
# endif
2022-12-23 22:24:10 +08:00
/*
* Use timer 3 as IR timer .
* Timer 3 blocks PA6 , PA7 , PB0 , PB1 , so if you require one of them as tone ( ) or Servo output , you must choose another timer .
*/
HardwareTimer s50usTimer ( 3 ) ;
void timerEnableReceiveInterrupt ( ) {
s50usTimer . resume ( ) ;
}
void timerDisableReceiveInterrupt ( ) {
s50usTimer . pause ( ) ;
}
2021-03-06 20:47:47 +08:00
2023-03-01 20:37:15 +08:00
// Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
2022-04-05 10:47:32 +08:00
# if defined(ISR)
2021-03-06 20:47:47 +08:00
# undef ISR
# endif
void timerConfigForReceive ( ) {
2022-01-29 03:26:58 +08:00
s50usTimer . setMode ( TIMER_CH1 , TIMER_OUTPUT_COMPARE ) ;
s50usTimer . setPrescaleFactor ( 1 ) ;
s50usTimer . setOverflow ( ( F_CPU / MICROS_IN_ONE_SECOND ) * MICROS_PER_TICK ) ;
2023-03-01 20:37:15 +08:00
s50usTimer . attachInterrupt ( TIMER_CH1 , IRReceiveTimerInterruptHandler ) ;
2022-01-29 03:26:58 +08:00
s50usTimer . refresh ( ) ;
2021-03-06 20:47:47 +08:00
}
/**********************************************************************************************************************
* STM32duino by ST Microsystems .
2022-01-27 01:36:50 +08:00
* https : //github.com/stm32duino/Arduino_Core_STM32
2021-03-06 20:47:47 +08:00
* https : //github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json
* stm32 architecture for " Generic STM32F1 series " from " STM32 Boards (selected from submenu) " of Arduino Board manager
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# elif defined(STM32F1xx) || defined(ARDUINO_ARCH_STM32)
# include <HardwareTimer.h> // 4 timers and 3. timer is used for tone(), 2. for Servo
2021-04-11 19:16:53 +08:00
# if defined(SEND_PWM_BY_TIMER)
2021-03-06 20:47:47 +08:00
# error PWM generation by hardware not implemented for STM32
# endif
/*
2021-10-30 15:50:38 +08:00
* Use timer 4 as IR timer .
2021-04-13 03:41:07 +08:00
* Timer 4 blocks PB6 , PB7 , PB8 , PB9 , so if you need one them as tone ( ) or Servo output , you must choose another timer .
2021-03-06 20:47:47 +08:00
*/
# if defined(TIM4)
2022-01-29 03:26:58 +08:00
HardwareTimer s50usTimer ( TIM4 ) ;
2021-03-06 20:47:47 +08:00
# else
2022-01-29 03:26:58 +08:00
HardwareTimer s50usTimer ( TIM2 ) ;
2021-03-06 20:47:47 +08:00
# endif
2021-03-18 04:52:41 +08:00
2022-12-23 22:24:10 +08:00
void timerEnableReceiveInterrupt ( ) {
s50usTimer . resume ( ) ;
}
void timerDisableReceiveInterrupt ( ) {
s50usTimer . pause ( ) ;
}
2023-03-01 20:37:15 +08:00
// Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
2022-12-23 22:24:10 +08:00
# if defined(ISR)
# undef ISR
# endif
2021-03-06 20:47:47 +08:00
void timerConfigForReceive ( ) {
2022-01-29 03:26:58 +08:00
s50usTimer . setOverflow ( MICROS_PER_TICK , MICROSEC_FORMAT ) ; // 50 uS
2023-03-01 20:37:15 +08:00
s50usTimer . attachInterrupt ( IRReceiveTimerInterruptHandler ) ;
2022-01-29 03:26:58 +08:00
s50usTimer . resume ( ) ;
2021-03-06 20:47:47 +08:00
}
/***************************************
* Particle special IntervalTimer
* ! ! ! UNTESTED ! ! !
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# elif defined(PARTICLE)
# ifndef __INTERVALTIMER_H__
# include "SparkIntervalTimer.h" // SparkIntervalTimer.h is required if PARTICLE is defined.
# endif
extern IntervalTimer timer ;
2022-12-23 22:24:10 +08:00
extern int ir_out_kHz ;
2021-03-06 20:47:47 +08:00
2022-12-23 22:24:10 +08:00
void timerEnableReceiveInterrupt ( ) {
2023-03-01 20:37:15 +08:00
timer . begin ( IRReceiveTimerInterruptHandler , MICROS_PER_TICK , uSec ) ;
2022-12-23 22:24:10 +08:00
}
void timerDisableReceiveInterrupt ( ) {
timer . end ( ) ;
}
2021-03-06 20:47:47 +08:00
2023-03-01 20:37:15 +08:00
// Undefine ISR, because we register/call the plain function IRReceiveTimerInterruptHandler()
2022-04-05 10:47:32 +08:00
# if defined(ISR)
2021-03-06 20:47:47 +08:00
# undef ISR
# endif
2022-01-27 01:36:50 +08:00
void timerConfigForReceive ( ) {
2021-03-06 20:47:47 +08:00
}
2022-01-27 01:36:50 +08:00
# if defined(SEND_PWM_BY_TIMER)
# if defined(IR_SEND_PIN)
2022-12-23 22:24:10 +08:00
void enableSendPWMByTimer ( ) {
analogWrite ( IR_SEND_PIN , ( ( 256L * 100 ) / IR_SEND_DUTY_CYCLE_PERCENT ) ) , ir_out_kHz * 1000 ) ;
}
void disableSendPWMByTimer ( ) {
analogWrite ( IR_SEND_PIN , 0 , ir_out_kHz * 1000 ) ;
}
2022-01-27 01:36:50 +08:00
# else
2022-12-23 22:24:10 +08:00
void enableSendPWMByTimer ( ) {
analogWrite ( IrSender . sendPin , ( ( 256L * 100 ) / IR_SEND_DUTY_CYCLE_PERCENT ) , ir_out_kHz * 1000 ) ;
}
void disableSendPWMByTimer ( ) {
analogWrite ( IrSender . sendPin , 0 , ir_out_kHz * 1000 ) ;
}
2022-01-27 01:36:50 +08:00
# endif
2022-12-23 22:24:10 +08:00
2022-01-27 01:36:50 +08:00
/*
* timerConfigForSend ( ) is used exclusively by IRsend : : enableIROut ( )
* Set output pin mode and disable receive interrupt if it uses the same resource
*/
2023-03-29 19:28:06 +08:00
void timerConfigForSend ( uint16_t aFrequencyKHz ) {
2022-12-23 22:24:10 +08:00
timerDisableReceiveInterrupt ( ) ;
2022-07-17 03:33:09 +08:00
# if defined(IR_SEND_PIN)
pinMode ( IR_SEND_PIN , OUTPUT ) ;
# else
pinMode ( IrSender . sendPin , OUTPUT ) ;
# endif
2022-01-27 01:36:50 +08:00
ir_out_kHz = aFrequencyKHz ;
2021-03-06 20:47:47 +08:00
}
2022-01-27 01:36:50 +08:00
# endif // defined(SEND_PWM_BY_TIMER)
2021-03-06 20:47:47 +08:00
2022-12-23 22:24:10 +08:00
/***************************************
* Unknown CPU board
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2021-03-06 20:47:47 +08:00
# else
# error Internal code configuration error, no timer functions implemented for this CPU / board
/*
* Dummy definitions to avoid more irritating compile errors
*/
2022-01-27 01:36:50 +08:00
2022-12-23 22:24:10 +08:00
void timerEnableReceiveInterrupt ( ) { } ;
void timerDisableReceiveInterrupt ( ) { } ;
2021-03-06 20:47:47 +08:00
2022-04-05 10:47:32 +08:00
# if defined(ISR)
2021-03-06 20:47:47 +08:00
# undef ISR
# endif
# define ISR() void notImplemented(void)
2022-01-27 01:36:50 +08:00
void timerConfigForReceive ( ) {
}
# if defined(SEND_PWM_BY_TIMER)
2022-12-23 22:24:10 +08:00
void enableSendPWMByTimer ( ) {
}
void disableSendPWMByTimer ( ) {
}
2022-01-27 01:36:50 +08:00
2023-03-29 19:28:06 +08:00
void timerConfigForSend ( uint16_t aFrequencyKHz ) {
2022-12-23 22:24:10 +08:00
timerDisableReceiveInterrupt ( ) ;
2022-07-17 03:33:09 +08:00
# if defined(IR_SEND_PIN)
pinMode ( IR_SEND_PIN , OUTPUT ) ;
# else
pinMode ( IrSender . sendPin , OUTPUT ) ;
# endif
2021-03-06 20:47:47 +08:00
( void ) aFrequencyKHz ;
}
2022-01-27 01:36:50 +08:00
# endif // defined(SEND_PWM_BY_TIMER)
2021-04-09 05:30:49 +08:00
# endif // defined(DOXYGEN / CPU_TYPES)
2021-03-18 04:52:41 +08:00
/** @}*/
/** @}*/
2022-04-05 10:47:32 +08:00
# endif // _IR_TIMER_HPP