Enable Bang&Olufsen 455 kHz if SEND_PWM_BY_TIMER is defined.
This commit is contained in:
parent
a73851300a
commit
c8c7110ca0
|
@ -484,8 +484,8 @@ For sending, the **default software generated PWM has problems on AVR running wi
|
|||
## Bang & Olufsen protocol
|
||||
The Bang & Olufsen protocol decoder is not enabled by default, i.e if no protocol is enabled explicitly by #define `DECODE_<XYZ>`. It must always be enabled explicitly by `#define DECODE_BEO`.
|
||||
This is because it has an **IR transmit frequency of 455 kHz** and therefore requires a different receiver hardware (TSOP7000).<br/>
|
||||
And because **generating a 455 kHz PWM signal is currently not implemented**, sending only works if `USE_NO_SEND_PWM` is defined, i.e. data is transferred by cable and not by IR!<br/>
|
||||
For more info, see [ir_BangOlufsen.hpp](https://github.com/Arduino-IRremote/Arduino-IRremote/blob/master/src/ir_BangOlufsen.hpp#L42).
|
||||
And because **generating a 455 kHz PWM signal is currently only implemented for `SEND_PWM_BY_TIMER`**, sending only works if `SEND_PWM_BY_TIMER` or `USE_NO_SEND_PWM` is defined.<br/>
|
||||
For more info, see [ir_BangOlufsen.hpp](https://github.com/Arduino-IRremote/Arduino-IRremote/blob/master/src/ir_BangOlufsen.hpp#L44).
|
||||
|
||||
# Handling unknown Protocols
|
||||
## Disclaimer
|
||||
|
|
|
@ -5,6 +5,7 @@ See also the commit log at github: https://github.com/Arduino-IRremote/Arduino-I
|
|||
# 4.2.0
|
||||
- The old decode function is renamed to decode_old(decode_results *aResults). decode (decode_results *aResults) is only available in IRremote.h and prints a message.
|
||||
- Added DECODE_ONKYO, to force 16 bit command and data decoding.
|
||||
- Enable Bang&Olufsen 455 kHz if SEND_PWM_BY_TIMER is defined.
|
||||
|
||||
## 4.1.2
|
||||
- Workaround for ESP32 RTOS delay() timing bug influencing the mark() function.
|
||||
|
|
|
@ -950,7 +950,7 @@ void IRsend::mark(uint16_t aMarkMicros) {
|
|||
*/
|
||||
enableSendPWMByTimer(); // Enable timer or ledcWrite() generated PWM output
|
||||
customDelayMicroseconds(aMarkMicros);
|
||||
IRLedOff();// disables hardware PWM and manages feedback LED
|
||||
IRLedOff(); // disables hardware PWM and manages feedback LED
|
||||
return;
|
||||
|
||||
#elif defined(USE_NO_SEND_PWM)
|
||||
|
@ -1167,15 +1167,15 @@ void IRsend::customDelayMicroseconds(unsigned long aMicroseconds) {
|
|||
*/
|
||||
void IRsend::enableIROut(uint_fast8_t aFrequencyKHz) {
|
||||
#if defined(SEND_PWM_BY_TIMER)
|
||||
timerConfigForSend(aFrequencyKHz); // must set output pin mode and disable receive interrupt if required, e.g. uses the same resource
|
||||
timerConfigForSend(aFrequencyKHz); // must set output pin mode and disable receive interrupt if required, e.g. uses the same resource
|
||||
|
||||
#elif defined(USE_NO_SEND_PWM)
|
||||
(void) aFrequencyKHz;
|
||||
(void) aFrequencyKHz;
|
||||
|
||||
#else
|
||||
periodTimeMicros = (1000U + (aFrequencyKHz / 2)) / aFrequencyKHz; // rounded value -> 26 for 38.46 kHz, 27 for 37.04 kHz, 25 for 40 kHz.
|
||||
# if defined(IR_SEND_PIN)
|
||||
periodOnTimeMicros = (((periodTimeMicros * IR_SEND_DUTY_CYCLE_PERCENT) + 50) / 100U); // +50 for rounding -> 830/100 for 30% and 16 MHz
|
||||
periodOnTimeMicros = (((periodTimeMicros * IR_SEND_DUTY_CYCLE_PERCENT) + 50) / 100U); // +50 for rounding -> 830/100 for 30% and 16 MHz
|
||||
# else
|
||||
// Heuristics! We require a nanosecond correction for "slow" digitalWrite() functions
|
||||
periodOnTimeMicros = (((periodTimeMicros * IR_SEND_DUTY_CYCLE_PERCENT) + 50 - (PULSE_CORRECTION_NANOS / 10)) / 100U); // +50 for rounding -> 530/100 for 30% and 16 MHz
|
||||
|
@ -1184,9 +1184,9 @@ void IRsend::enableIROut(uint_fast8_t aFrequencyKHz) {
|
|||
|
||||
#if defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN) && defined(OUTPUT_OPEN_DRAIN) // the mode INPUT for mimicking open drain is set at IRLedOff()
|
||||
# if defined(IR_SEND_PIN)
|
||||
pinModeFast(IR_SEND_PIN, OUTPUT_OPEN_DRAIN);
|
||||
pinModeFast(IR_SEND_PIN, OUTPUT_OPEN_DRAIN);
|
||||
# else
|
||||
pinModeFast(sendPin, OUTPUT_OPEN_DRAIN);
|
||||
pinModeFast(sendPin, OUTPUT_OPEN_DRAIN);
|
||||
# endif
|
||||
#else
|
||||
|
||||
|
@ -1194,7 +1194,7 @@ void IRsend::enableIROut(uint_fast8_t aFrequencyKHz) {
|
|||
// because ESP 2.0.2 ledcWrite does not work if pin mode is set, and RP2040 requires gpio_set_function(IR_SEND_PIN, GPIO_FUNC_PWM);
|
||||
# if defined(__AVR__) || !defined(SEND_PWM_BY_TIMER)
|
||||
# if defined(IR_SEND_PIN)
|
||||
pinModeFast(IR_SEND_PIN, OUTPUT);
|
||||
pinModeFast(IR_SEND_PIN, OUTPUT);
|
||||
# else
|
||||
pinModeFast(sendPin, OUTPUT);
|
||||
# endif
|
||||
|
@ -1202,6 +1202,22 @@ void IRsend::enableIROut(uint_fast8_t aFrequencyKHz) {
|
|||
#endif // defined(USE_OPEN_DRAIN_OUTPUT_FOR_SEND_PIN)
|
||||
}
|
||||
|
||||
#if defined(SEND_PWM_BY_TIMER)
|
||||
// Used for Bang&Olufsen
|
||||
void IRsend::enableHighFrequencyIROut(uint_fast16_t aFrequencyKHz) {
|
||||
timerConfigForSend(aFrequencyKHz); // must set output pin mode and disable receive interrupt if required, e.g. uses the same resource
|
||||
// For Non AVR platforms pin mode for SEND_PWM_BY_TIMER must be handled by the timerConfigForSend() function
|
||||
// because ESP 2.0.2 ledcWrite does not work if pin mode is set, and RP2040 requires gpio_set_function(IR_SEND_PIN, GPIO_FUNC_PWM);
|
||||
# if defined(__AVR__)
|
||||
# if defined(IR_SEND_PIN)
|
||||
pinModeFast(IR_SEND_PIN, OUTPUT);
|
||||
# else
|
||||
pinModeFast(sendPin, OUTPUT);
|
||||
# endif
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t IRsend::getPulseCorrectionNanos() {
|
||||
return PULSE_CORRECTION_NANOS;
|
||||
}
|
||||
|
|
|
@ -437,6 +437,9 @@ public:
|
|||
size_t write(decode_type_t aProtocol, uint16_t aAddress, uint16_t aCommand, int_fast8_t aNumberOfRepeats = NO_REPEATS);
|
||||
|
||||
void enableIROut(uint_fast8_t aFrequencyKHz);
|
||||
#if defined(SEND_PWM_BY_TIMER)
|
||||
void enableHighFrequencyIROut(uint_fast16_t aFrequencyKHz); // Used for Bang&Olufsen
|
||||
#endif
|
||||
|
||||
void sendPulseDistanceWidthFromArray(uint_fast8_t aFrequencyKHz, uint16_t aHeaderMarkMicros, uint16_t aHeaderSpaceMicros,
|
||||
uint16_t aOneMarkMicros, uint16_t aOneSpaceMicros, uint16_t aZeroMarkMicros, uint16_t aZeroSpaceMicros,
|
||||
|
|
|
@ -160,13 +160,17 @@ void IRsend::sendBangOlufsenDataLink(uint32_t aHeader, uint8_t aData, int_fast8_
|
|||
* @param aBackToBack If true send data back to back, which cannot be decoded if ENABLE_BEO_WITHOUT_FRAME_GAP is NOT defined
|
||||
*/
|
||||
void IRsend::sendBangOlufsenRaw(uint32_t aRawData, int_fast8_t aBits, bool aBackToBack) {
|
||||
#if defined(USE_NO_SEND_PWM) || BEO_KHZ == 38 // BEO_KHZ == 38 is for unit test which runs the B&O protocol with 38 kHz
|
||||
#if defined(USE_NO_SEND_PWM) || defined(SEND_PWM_BY_TIMER) || BEO_KHZ == 38 // BEO_KHZ == 38 is for unit test which runs the B&O protocol with 38 kHz
|
||||
|
||||
/*
|
||||
* 455 kHz PWM is currently not supported, maximum is 180 kHz
|
||||
* 455 kHz PWM is currently only supported with SEND_PWM_BY_TIMER defined, otherwise maximum is 180 kHz
|
||||
*/
|
||||
# if !defined(USE_NO_SEND_PWM)
|
||||
# if defined(SEND_PWM_BY_TIMER)
|
||||
enableHighFrequencyIROut (BEO_KHZ);
|
||||
# elif (BEO_KHZ == 38)
|
||||
enableIROut (BEO_KHZ); // currently only for unit test
|
||||
# endif
|
||||
# endif
|
||||
|
||||
// AGC / Start - 3 bits + first constant 0 header bit described in the official documentation
|
||||
|
|
|
@ -50,7 +50,7 @@ void timerDisableReceiveInterrupt();
|
|||
void timerConfigForReceive();
|
||||
void enableSendPWMByTimer();
|
||||
void disableSendPWMByTimer();
|
||||
void timerConfigForSend(uint8_t aFrequencyKHz);
|
||||
void timerConfigForSend(uint16_t aFrequencyKHz);
|
||||
|
||||
#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 are independent, so it is recommended to always define SEND_PWM_BY_TIMER
|
||||
|
@ -122,7 +122,7 @@ void timerDisableReceiveInterrupt() {
|
|||
* 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 :-).
|
||||
*/
|
||||
void timerConfigForSend(uint8_t aFrequencyKHz) {
|
||||
void timerConfigForSend(uint16_t aFrequencyKHz) {
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -427,7 +427,7 @@ void disableSendPWMByTimer() {
|
|||
* timerConfigForSend() is used exclusively by IRsend::enableIROut()
|
||||
* Set output pin mode and disable receive interrupt if it uses the same resource
|
||||
*/
|
||||
void timerConfigForSend(uint8_t aFrequencyKHz) {
|
||||
void timerConfigForSend(uint16_t aFrequencyKHz) {
|
||||
timerDisableReceiveInterrupt();
|
||||
|
||||
# if (((F_CPU / 2000) / 38) < 256)
|
||||
|
@ -517,14 +517,19 @@ void disableSendPWMByTimer() {
|
|||
* timerConfigForSend() is used exclusively by IRsend::enableIROut()
|
||||
* Set output pin mode and disable receive interrupt if it uses the same resource
|
||||
*/
|
||||
void timerConfigForSend(uint8_t aFrequencyKHz) {
|
||||
void timerConfigForSend(uint16_t aFrequencyKHz) {
|
||||
timerDisableReceiveInterrupt();
|
||||
|
||||
# if (((F_CPU / 2000) / 38) < 256)
|
||||
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
|
||||
/*
|
||||
* 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);
|
||||
TCCR2A = _BV(WGM20); // PWM, Phase Correct, Top is OCR2A
|
||||
TCCR2B = _BV(WGM22) | _BV(CS20); // CS20 -> no prescaling
|
||||
OCR2A = tPWMWrapValue - 1; // The top value for the timer. The modulation frequency will be F_CPU / 2 / OCR2A.
|
||||
OCR2A = tPWMWrapValue - 1; // The top value for the timer. The modulation frequency will be F_CPU / 2 / (OCR2A + 1).
|
||||
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
|
||||
# else
|
||||
|
@ -586,7 +591,7 @@ void disableSendPWMByTimer() {
|
|||
* timerConfigForSend() is used exclusively by IRsend::enableIROut()
|
||||
* Set output pin mode and disable receive interrupt if it uses the same resource
|
||||
*/
|
||||
void timerConfigForSend(uint8_t aFrequencyKHz) {
|
||||
void timerConfigForSend(uint16_t aFrequencyKHz) {
|
||||
#if F_CPU > 16000000
|
||||
#error "Creating timer PWM with timer 3 is not supported for F_CPU > 16 MHz"
|
||||
#endif
|
||||
|
@ -637,7 +642,7 @@ void disableSendPWMByTimer() {
|
|||
TCCR4A &= ~(_BV(COM4A1));
|
||||
}
|
||||
|
||||
void timerConfigForSend(uint8_t aFrequencyKHz) {
|
||||
void timerConfigForSend(uint16_t aFrequencyKHz) {
|
||||
#if F_CPU > 16000000
|
||||
#error "Creating timer PWM with timer 4 is not supported for F_CPU > 16 MHz"
|
||||
#endif
|
||||
|
@ -706,7 +711,7 @@ void disableSendPWMByTimer() {
|
|||
* timerConfigForSend() is used exclusively by IRsend::enableIROut()
|
||||
* Set output pin mode and disable receive interrupt if it uses the same resource
|
||||
*/
|
||||
void timerConfigForSend(uint8_t aFrequencyKHz) {
|
||||
void timerConfigForSend(uint16_t aFrequencyKHz) {
|
||||
#if F_CPU > 16000000
|
||||
#error "Creating timer PWM with timer 4 HS is not supported for F_CPU > 16 MHz"
|
||||
#endif
|
||||
|
@ -767,7 +772,7 @@ void disableSendPWMByTimer() {
|
|||
* timerConfigForSend() is used exclusively by IRsend::enableIROut()
|
||||
* Set output pin mode and disable receive interrupt if it uses the same resource
|
||||
*/
|
||||
void timerConfigForSend(uint8_t aFrequencyKHz) {
|
||||
void timerConfigForSend(uint16_t aFrequencyKHz) {
|
||||
#if F_CPU > 16000000
|
||||
#error "Creating timer PWM with timer 5 is not supported for F_CPU > 16 MHz"
|
||||
#endif
|
||||
|
@ -826,7 +831,7 @@ void disableSendPWMByTimer() {
|
|||
* timerConfigForSend() is used exclusively by IRsend::enableIROut()
|
||||
* Set output pin mode and disable receive interrupt if it uses the same resource
|
||||
*/
|
||||
void timerConfigForSend(uint8_t aFrequencyKHz) {
|
||||
void timerConfigForSend(uint16_t aFrequencyKHz) {
|
||||
#if F_CPU > 16000000
|
||||
#error "Creating timer PWM with timer TINY0 is not supported for F_CPU > 16 MHz"
|
||||
#endif
|
||||
|
@ -885,7 +890,7 @@ void disableSendPWMByTimer() {
|
|||
* timerConfigForSend() is used exclusively by IRsend::enableIROut()
|
||||
* Set output pin mode and disable receive interrupt if it uses the same resource
|
||||
*/
|
||||
void timerConfigForSend(uint8_t aFrequencyKHz) {
|
||||
void timerConfigForSend(uint16_t aFrequencyKHz) {
|
||||
timerDisableReceiveInterrupt();
|
||||
|
||||
# if (((F_CPU / 1000) / 38) < 256)
|
||||
|
@ -981,7 +986,7 @@ void disableSendPWMByTimer() {
|
|||
* timerConfigForSend() is used exclusively by IRsend::enableIROut()
|
||||
* Set output pin mode and disable receive interrupt if it uses the same resource
|
||||
*/
|
||||
void timerConfigForSend(uint8_t aFrequencyKHz) {
|
||||
void timerConfigForSend(uint16_t aFrequencyKHz) {
|
||||
#if F_CPU > 16000000
|
||||
// we have only prescaler 2 or must take clock of timer A (which is non deterministic)
|
||||
#error "Creating timer PWM with timer TCB0 is not possible for F_CPU > 16 MHz"
|
||||
|
@ -1050,7 +1055,7 @@ void disableSendPWMByTimer() {
|
|||
* timerConfigForSend() is used exclusively by IRsend::enableIROut()
|
||||
* Set output pin mode and disable receive interrupt if it uses the same resource
|
||||
*/
|
||||
void timerConfigForSend(uint8_t aFrequencyKHz) {
|
||||
void timerConfigForSend(uint16_t aFrequencyKHz) {
|
||||
timerDisableReceiveInterrupt();
|
||||
|
||||
const uint16_t tPWMWrapValue = (F_CPU / 1000) / (aFrequencyKHz); // 526,31 for 38 kHz @20 MHz clock
|
||||
|
@ -1140,7 +1145,7 @@ void disableSendPWMByTimer() {
|
|||
* timerConfigForSend() is used exclusively by IRsend::enableIROut()
|
||||
* Set output pin mode and disable receive interrupt if it uses the same resource
|
||||
*/
|
||||
void timerConfigForSend(uint8_t aFrequencyKHz) {
|
||||
void timerConfigForSend(uint16_t aFrequencyKHz) {
|
||||
timerDisableReceiveInterrupt(); // TODO really required here? Do we have a common resource for Teensy3.0, 3.1
|
||||
# if defined(IR_SEND_PIN)
|
||||
pinMode(IR_SEND_PIN, OUTPUT);
|
||||
|
@ -1209,7 +1214,7 @@ void disableSendPWMByTimer() {
|
|||
* timerConfigForSend() is used exclusively by IRsend::enableIROut()
|
||||
* Set output pin mode and disable receive interrupt if it uses the same resource
|
||||
*/
|
||||
void timerConfigForSend(uint8_t aFrequencyKHz) {
|
||||
void timerConfigForSend(uint16_t aFrequencyKHz) {
|
||||
timerDisableReceiveInterrupt();
|
||||
# if defined(IR_SEND_PIN)
|
||||
pinMode(IR_SEND_PIN, OUTPUT);
|
||||
|
@ -1292,7 +1297,7 @@ void disableSendPWMByTimer() {
|
|||
* timerConfigForSend() is used exclusively by IRsend::enableIROut()
|
||||
* Set output pin mode and disable receive interrupt if it uses the same resource
|
||||
*/
|
||||
void timerConfigForSend(uint8_t aFrequencyKHz) {
|
||||
void timerConfigForSend(uint16_t aFrequencyKHz) {
|
||||
timerDisableReceiveInterrupt();
|
||||
# if defined(IR_SEND_PIN)
|
||||
pinMode(IR_SEND_PIN, OUTPUT);
|
||||
|
@ -1418,7 +1423,7 @@ void disableSendPWMByTimer() {
|
|||
* timerConfigForSend() is used exclusively by IRsend::enableIROut()
|
||||
* ledcWrite since ESP 2.0.2 does not work if pin mode is set. Disable receive interrupt if it uses the same resource
|
||||
*/
|
||||
void timerConfigForSend(uint8_t aFrequencyKHz) {
|
||||
void timerConfigForSend(uint16_t aFrequencyKHz) {
|
||||
ledcSetup(SEND_AND_RECEIVE_TIMER_LEDC_CHANNEL, aFrequencyKHz * 1000, 8); // 8 bit PWM resolution
|
||||
# if defined(IR_SEND_PIN)
|
||||
ledcAttachPin(IR_SEND_PIN, SEND_AND_RECEIVE_TIMER_LEDC_CHANNEL); // bind pin to channel
|
||||
|
@ -1601,7 +1606,7 @@ void disableSendPWMByTimer() {
|
|||
* timerConfigForSend() is used exclusively by IRsend::enableIROut()
|
||||
* Set output pin mode and disable receive interrupt if it uses the same resource
|
||||
*/
|
||||
void timerConfigForSend(uint8_t aFrequencyKHz) {
|
||||
void timerConfigForSend(uint16_t aFrequencyKHz) {
|
||||
sPwmOutForSendPWM.period_us(1000 / aFrequencyKHz); // 26.315 for 38 kHz
|
||||
sIROutPuseWidth = (1000 * IR_SEND_DUTY_CYCLE_PERCENT) / (aFrequencyKHz * 100);
|
||||
}
|
||||
|
@ -1662,7 +1667,7 @@ void disableSendPWMByTimer() {
|
|||
* timerConfigForSend() is used exclusively by IRsend::enableIROut()
|
||||
* Set output pin mode and disable receive interrupt if it uses the same resource
|
||||
*/
|
||||
void timerConfigForSend(uint8_t aFrequencyKHz) {
|
||||
void timerConfigForSend(uint16_t aFrequencyKHz) {
|
||||
# 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
|
||||
|
@ -1864,7 +1869,7 @@ void disableSendPWMByTimer() {
|
|||
* timerConfigForSend() is used exclusively by IRsend::enableIROut()
|
||||
* Set output pin mode and disable receive interrupt if it uses the same resource
|
||||
*/
|
||||
void timerConfigForSend(uint8_t aFrequencyKHz) {
|
||||
void timerConfigForSend(uint16_t aFrequencyKHz) {
|
||||
timerDisableReceiveInterrupt();
|
||||
# if defined(IR_SEND_PIN)
|
||||
pinMode(IR_SEND_PIN, OUTPUT);
|
||||
|
@ -1901,7 +1906,7 @@ void enableSendPWMByTimer() {
|
|||
void disableSendPWMByTimer() {
|
||||
}
|
||||
|
||||
void timerConfigForSend(uint8_t aFrequencyKHz) {
|
||||
void timerConfigForSend(uint16_t aFrequencyKHz) {
|
||||
timerDisableReceiveInterrupt();
|
||||
# if defined(IR_SEND_PIN)
|
||||
pinMode(IR_SEND_PIN, OUTPUT);
|
||||
|
|
Loading…
Reference in New Issue