From 46b18ea41e0f033d02afbcc2a4562c140a766e62 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sat, 6 Mar 2021 18:43:32 +0100 Subject: [PATCH] Fix WS2812 ESP32 --- tasmota/xlgt_01_ws2812.ino | 107 +++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/tasmota/xlgt_01_ws2812.ino b/tasmota/xlgt_01_ws2812.ino index fcd685931..eaea82135 100644 --- a/tasmota/xlgt_01_ws2812.ino +++ b/tasmota/xlgt_01_ws2812.ino @@ -123,6 +123,113 @@ void (* const Ws2812Command[])(void) PROGMEM = { #endif // No USE_WS2812_DMA +#ifdef ESP32 +// +// Below is a quick work-around to ESP32 gcc that prevents templated methods to be in IRAM unless explicitly marked per specialization +// It will work only for the default WS2812 (800KHz) and inverted and non-inverted +// +template <> +void IRAM_ATTR NeoEspBitBangBase::send_pixels(uint8_t* pixels, uint8_t* end, uint8_t pin) +{ + const uint32_t pinRegister = _BV(pin); + uint8_t mask = 0x80; + uint8_t subpix = *pixels++; + uint32_t cyclesStart = 0; // trigger emediately + uint32_t cyclesNext = 0; + + for (;;) + { + // do the checks here while we are waiting on time to pass + uint32_t cyclesBit = NeoEspSpeed800Mhz::T0H; + if (subpix & mask) + { + cyclesBit = NeoEspSpeed800Mhz::T1H; + } + + // after we have done as much work as needed for this next bit + // now wait for the HIGH + while (((cyclesStart = getCycleCount()) - cyclesNext) < NeoEspSpeed800Mhz::Period); + + // set pin state + NeoEspPinset::setPin(pinRegister); + + // wait for the LOW + while ((getCycleCount() - cyclesStart) < cyclesBit); + + // reset pin start + NeoEspPinset::resetPin(pinRegister); + + cyclesNext = cyclesStart; + + // next bit + mask >>= 1; + if (mask == 0) + { + // no more bits to send in this byte + // check for another byte + if (pixels >= end) + { + // no more bytes to send so stop + break; + } + // reset mask to first bit and get the next byte + mask = 0x80; + subpix = *pixels++; + } + } +} +template <> +void IRAM_ATTR NeoEspBitBangBase::send_pixels(uint8_t* pixels, uint8_t* end, uint8_t pin) +{ + const uint32_t pinRegister = _BV(pin); + uint8_t mask = 0x80; + uint8_t subpix = *pixels++; + uint32_t cyclesStart = 0; // trigger emediately + uint32_t cyclesNext = 0; + + for (;;) + { + // do the checks here while we are waiting on time to pass + uint32_t cyclesBit = NeoEspSpeed800Mhz::T0H; + if (subpix & mask) + { + cyclesBit = NeoEspSpeed800Mhz::T1H; + } + + // after we have done as much work as needed for this next bit + // now wait for the HIGH + while (((cyclesStart = getCycleCount()) - cyclesNext) < NeoEspSpeed800Mhz::Period); + + // set pin state + NeoEspPinsetInverted::setPin(pinRegister); + + // wait for the LOW + while ((getCycleCount() - cyclesStart) < cyclesBit); + + // reset pin start + NeoEspPinsetInverted::resetPin(pinRegister); + + cyclesNext = cyclesStart; + + // next bit + mask >>= 1; + if (mask == 0) + { + // no more bits to send in this byte + // check for another byte + if (pixels >= end) + { + // no more bytes to send so stop + break; + } + // reset mask to first bit and get the next byte + mask = 0x80; + subpix = *pixels++; + } + } +} +#endif // ESP32 + NeoPixelBus *strip = nullptr; struct WsColor {