From 46299ffa4bedfb2fe8f4a9262aae6c36151d0a14 Mon Sep 17 00:00:00 2001 From: Paul Kendall Date: Sun, 16 Jan 2022 10:12:31 +1300 Subject: [PATCH] Support for GPIO16 on ESP8266 (#557) * Support for GPIO16 on ESP8266 * Seperate functions for pin16 on esp8266 --- src/internal/NeoEspBitBangMethod.cpp | 124 +++++++++++++++++++++++++++ src/internal/NeoEspBitBangMethod.h | 20 ++++- 2 files changed, 143 insertions(+), 1 deletion(-) diff --git a/src/internal/NeoEspBitBangMethod.cpp b/src/internal/NeoEspBitBangMethod.cpp index 32c069f..7cb9003 100644 --- a/src/internal/NeoEspBitBangMethod.cpp +++ b/src/internal/NeoEspBitBangMethod.cpp @@ -96,6 +96,61 @@ void IRAM_ATTR NeoEspBitBangBase_send_pixels(uint8_t* pixels, uint8_t* end, uint } } +#if defined(ARDUINO_ARCH_ESP8266) +void IRAM_ATTR NeoEspBitBangBase_send_pixels_pin16(uint8_t *pixels, uint8_t *end, uint32_t t0h, uint32_t t1h, uint32_t period) +{ + uint8_t mask = 0x80; + uint8_t subpix = *pixels++; + uint32_t cyclesStart = 0; // trigger emediately + uint32_t cyclesNext = 0; + + // reading and writing RTC_GPIO_OUT is too slow inside the loop + uint32_t gpio_clear = (READ_PERI_REG(RTC_GPIO_OUT) & (uint32)0xfffffffe); + uint32_t gpio_set = gpio_clear | 1; + + for (;;) + { + // do the checks here while we are waiting on time to pass + uint32_t cyclesBit = t0h; + if (subpix & mask) + { + cyclesBit = t1h; + } + + // after we have done as much work as needed for this next bit + // now wait for the HIGH + while (((cyclesStart = getCycleCount()) - cyclesNext) < period); + + // set pin state + WRITE_PERI_REG(RTC_GPIO_OUT, gpio_set); + + // wait for the LOW + while ((getCycleCount() - cyclesStart) < cyclesBit); + + // reset pin start + WRITE_PERI_REG(RTC_GPIO_OUT, gpio_clear); + + 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 // defined(ARDUINO_ARCH_ESP8266) + void IRAM_ATTR NeoEspBitBangBase_send_pixels_inv(uint8_t* pixels, uint8_t* end, uint8_t pin, uint32_t t0h, uint32_t t1h, uint32_t period) { const uint32_t pinRegister = _BV(pin); @@ -104,6 +159,21 @@ void IRAM_ATTR NeoEspBitBangBase_send_pixels_inv(uint8_t* pixels, uint8_t* end, uint32_t cyclesStart = 0; // trigger emediately uint32_t cyclesNext = 0; +#if defined(ARDUINO_ARCH_ESP8266) + // compensation for if (pin == ...) + t0h -= 3; + t1h -= 3; + + uint32_t gpio_clear = 0; + uint32_t gpio_set = 0; + if (pin == 16) + { + // reading and writing RTC_GPIO_OUT is too slow inside the loop + gpio_clear = (READ_PERI_REG(RTC_GPIO_OUT) & (uint32)0xfffffffe); + gpio_set = gpio_clear | 1; + } +#endif + for (;;) { // do the checks here while we are waiting on time to pass @@ -154,5 +224,59 @@ void IRAM_ATTR NeoEspBitBangBase_send_pixels_inv(uint8_t* pixels, uint8_t* end, } } +#if defined(ARDUINO_ARCH_ESP8266) +void IRAM_ATTR NeoEspBitBangBase_send_pixels_inv_pin16(uint8_t *pixels, uint8_t *end, uint32_t t0h, uint32_t t1h, uint32_t period) +{ + uint8_t mask = 0x80; + uint8_t subpix = *pixels++; + uint32_t cyclesStart = 0; // trigger emediately + uint32_t cyclesNext = 0; + + // reading and writing RTC_GPIO_OUT is too slow inside the loop + uint32_t gpio_clear = (READ_PERI_REG(RTC_GPIO_OUT) & (uint32)0xfffffffe); + uint32_t gpio_set = gpio_clear | 1; + + for (;;) + { + // do the checks here while we are waiting on time to pass + uint32_t cyclesBit = t0h; + if (subpix & mask) + { + cyclesBit = t1h; + } + + // after we have done as much work as needed for this next bit + // now wait for the HIGH + while (((cyclesStart = getCycleCount()) - cyclesNext) < period); + + // set pin state + WRITE_PERI_REG(RTC_GPIO_OUT, gpio_clear); + + // wait for the LOW + while ((getCycleCount() - cyclesStart) < cyclesBit); + + // reset pin start + WRITE_PERI_REG(RTC_GPIO_OUT, gpio_set); + + 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 // defined(ARDUINO_ARCH_ESP8266) #endif // !defined(CONFIG_IDF_TARGET_ESP32C3) #endif // defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) diff --git a/src/internal/NeoEspBitBangMethod.h b/src/internal/NeoEspBitBangMethod.h index bfbd135..6667119 100644 --- a/src/internal/NeoEspBitBangMethod.h +++ b/src/internal/NeoEspBitBangMethod.h @@ -86,7 +86,11 @@ public: }; extern void NeoEspBitBangBase_send_pixels(uint8_t* pixels, uint8_t* end, uint8_t pin, uint32_t t0h, uint32_t t1h, uint32_t period); -extern void NeoEspBitBangBase_send_pixels_inv(uint8_t* pixels, uint8_t* end, uint8_t pin, uint32_t t0h, uint32_t t1h, uint32_t period); +extern void NeoEspBitBangBase_send_pixels_inv(uint8_t *pixels, uint8_t *end, uint8_t pin, uint32_t t0h, uint32_t t1h, uint32_t period); +#if defined(ARDUINO_ARCH_ESP8266) +extern void NeoEspBitBangBase_send_pixels_pin16(uint8_t *pixels, uint8_t *end, uint32_t t0h, uint32_t t1h, uint32_t period); +extern void NeoEspBitBangBase_send_pixels_inv_pin16(uint8_t *pixels, uint8_t *end, uint32_t t0h, uint32_t t1h, uint32_t period); +#endif class NeoEspPinset { @@ -95,7 +99,14 @@ public: inline static void send_pixels_impl(uint8_t* pixels, uint8_t* end, uint8_t pin, uint32_t t0h, uint32_t t1h, uint32_t period) { +#if defined(ARDUINO_ARCH_ESP8266) + if (pin == 16) + NeoEspBitBangBase_send_pixels_pin16(pixels, end, t0h, t1h, period); + else + NeoEspBitBangBase_send_pixels(pixels, end, pin, t0h, t1h, period); +#else NeoEspBitBangBase_send_pixels(pixels, end, pin, t0h, t1h, period); +#endif } }; @@ -106,7 +117,14 @@ public: inline static void send_pixels_impl(uint8_t* pixels, uint8_t* end, uint8_t pin, uint32_t t0h, uint32_t t1h, uint32_t period) { +#if defined(ARDUINO_ARCH_ESP8266) + if (pin == 16) + NeoEspBitBangBase_send_pixels_inv_pin16(pixels, end, t0h, t1h, period); + else + NeoEspBitBangBase_send_pixels_inv(pixels, end, pin, t0h, t1h, period); +#else NeoEspBitBangBase_send_pixels_inv(pixels, end, pin, t0h, t1h, period); +#endif } };