From 5ca0d58dceef2861ffd5078c457c667a0d2a6975 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Sat, 28 Sep 2019 10:34:52 -0700 Subject: [PATCH] Invert support (#296) * Esp8266Dma and Esp32Rmt * EspBitBang * Esp21I2s Invert Support * esp8266 uart --- ReadMe.md | 2 +- keywords.txt | 121 +++++++++++++++ src/internal/Esp32_i2s.c | 22 +-- src/internal/Esp32_i2s.h | 2 +- src/internal/NeoEsp32I2sMethod.h | 57 +++++-- src/internal/NeoEsp32RmtMethod.h | 129 ++++++++++++++-- src/internal/NeoEsp8266DmaMethod.h | 123 +++++++++++++-- src/internal/NeoEsp8266UartMethod.h | 132 +++++++++++----- src/internal/NeoEspBitBangMethod.h | 227 +++++++++++++++++++++++----- src/internal/NeoPixelEsp.c | 170 --------------------- 10 files changed, 696 insertions(+), 289 deletions(-) delete mode 100644 src/internal/NeoPixelEsp.c diff --git a/ReadMe.md b/ReadMe.md index 00e2ca6..b48ec57 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -12,7 +12,7 @@ This is the most functional library for the Esp8266 as it provides solutions for Please read this best practices link before connecting your NeoPixels, it will save you a lot of time and effort. [Adafruit NeoPixel Best Practices](https://learn.adafruit.com/adafruit-neopixel-uberguide/best-practices) -For quick questions jump on Gitter and ask away. +For quick questions and support jump on Gitter and ask away. [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Makuna/NeoPixelBus?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) For bugs, make sure there isn't an active issue and then create one. diff --git a/keywords.txt b/keywords.txt index b66a17f..3ea0344 100644 --- a/keywords.txt +++ b/keywords.txt @@ -31,11 +31,24 @@ NeoWs2812Method KEYWORD1 NeoSk6812Method KEYWORD1 NeoLc8812Method KEYWORD1 NeoApa106Method KEYWORD1 +Neo800KbpsInvertedMethod KEYWORD1 +Neo400KbpsInvertedMethod KEYWORD1 +NeoWs2813InvertedMethod KEYWORD1 +NeoWs2812xInvertedMethod KEYWORD1 +NeoWs2812InvertedMethod KEYWORD1 +NeoSk6812InvertedMethod KEYWORD1 +NeoLc8812InvertedMethod KEYWORD1 +NeoApa106InvertedMethod KEYWORD1 NeoEsp8266DmaWs2812xMethod KEYWORD1 NeoEsp8266DmaSk6812Method KEYWORD1 NeoEsp8266DmaApa106Method KEYWORD1 NeoEsp8266Dma800KbpsMethod KEYWORD1 NeoEsp8266Dma400KbpsMethod KEYWORD1 +NeoEsp8266DmaInvertedWs2812xMethod KEYWORD1 +NeoEsp8266DmaInvertedSk6812Method KEYWORD1 +NeoEsp8266DmaInvertedApa106Method KEYWORD1 +NeoEsp8266DmaInverted800KbpsMethod KEYWORD1 +NeoEsp8266DmaInverted400KbpsMethod KEYWORD1 NeoEsp8266Uart0Ws2813Method KEYWORD1 NeoEsp8266Uart0Ws2812xMethod KEYWORD1 NeoEsp8266Uart0Ws2812Method KEYWORD1 @@ -68,6 +81,38 @@ NeoEsp8266AsyncUart1Lc8812Method KEYWORD1 NeoEsp8266AsyncUart1Apa106Method KEYWORD1 NeoEsp8266AsyncUart1800KbpsMethod KEYWORD1 NeoEsp8266AsyncUart1400KbpsMethod KEYWORD1 +NeoEsp8266Uart0Ws2813InvertedMethod KEYWORD1 +NeoEsp8266Uart0Ws2812xInvertedMethod KEYWORD1 +NeoEsp8266Uart0Ws2812InvertedMethod KEYWORD1 +NeoEsp8266Uart0Sk6812InvertedMethod KEYWORD1 +NeoEsp8266Uart0Lc8812InvertedMethod KEYWORD1 +NeoEsp8266Uart0Apa106InvertedMethod KEYWORD1 +NeoEsp8266Uart0800KbpsInvertedMethod KEYWORD1 +NeoEsp8266Uart0400KbpsInvertedMethod KEYWORD1 +NeoEsp8266AsyncUart0Ws2813InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart0Ws2812xInvertedMethod KEYWORD1 +NeoEsp8266AsyncUart0Ws2812InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart0Sk6812InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart0Lc8812InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart0Apa106InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart0800KbpsInvertedMethod KEYWORD1 +NeoEsp8266AsyncUart0400KbpsInvertedMethod KEYWORD1 +NeoEsp8266Uart1Ws2813InvertedMethod KEYWORD1 +NeoEsp8266Uart1Ws2812xInvertedMethod KEYWORD1 +NeoEsp8266Uart1Ws2812InvertedMethod KEYWORD1 +NeoEsp8266Uart1Sk6812InvertedMethod KEYWORD1 +NeoEsp8266Uart1Lc8812InvertedMethod KEYWORD1 +NeoEsp8266Uart1Apa106InvertedMethod KEYWORD1 +NeoEsp8266Uart1800KbpsInvertedMethod KEYWORD1 +NeoEsp8266Uart1400KbpsInvertedMethod KEYWORD1 +NeoEsp8266AsyncUart1Ws2813InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart1Ws2812xInvertedMethod KEYWORD1 +NeoEsp8266AsyncUart1Ws2812InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart1Sk6812InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart1Lc8812InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart1Apa106InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart1800KbpsInvertedMethod KEYWORD1 +NeoEsp8266AsyncUart1400KbpsInvertedMethod KEYWORD1 NeoEsp8266BitBangWs2813Method KEYWORD1 NeoEsp8266BitBangWs2812xMethod KEYWORD1 NeoEsp8266BitBangWs2812Method KEYWORD1 @@ -76,6 +121,34 @@ NeoEsp8266BitBangLc8812Method KEYWORD1 NeoEsp8266BitBangApa106Method KEYWORD1 NeoEsp8266BitBang800KbpsMethod KEYWORD1 NeoEsp8266BitBang400KbpsMethod KEYWORD1 +NeoEsp8266BitBangWs2813InvertedMethod KEYWORD1 +NeoEsp8266BitBangWs2812xInvertedMethod KEYWORD1 +NeoEsp8266BitBangWs2812InvertedMethod KEYWORD1 +NeoEsp8266BitBangSk6812InvertedMethod KEYWORD1 +NeoEsp8266BitBangLc8812InvertedMethod KEYWORD1 +NeoEsp8266BitBangApa106InvertedMethod KEYWORD1 +NeoEsp8266BitBang800KbpsInvertedMethod KEYWORD1 +NeoEsp8266BitBang400KbpsInvertedMethod KEYWORD1 +NeoEsp32I2s0Ws2812xMethod KEYWORD1 +NeoEsp32I2s0Sk6812Method KEYWORD1 +NeoEsp32I2s0800KbpsMethod KEYWORD1 +NeoEsp32I2s0400KbpsMethod KEYWORD1 +NeoEsp32I2s0Apa106Method KEYWORD1 +NeoEsp32I2s1Ws2812xMethod KEYWORD1 +NeoEsp32I2s1Sk6812Method KEYWORD1 +NeoEsp32I2s1800KbpsMethod KEYWORD1 +NeoEsp32I2s1400KbpsMethod KEYWORD1 +NeoEsp32I2s1Apa106Method KEYWORD1 +NeoEsp32I2s0Ws2812xInvertdMethod KEYWORD1 +NeoEsp32I2s0Sk6812InvertdMethod KEYWORD1 +NeoEsp32I2s0800KbpsInvertdMethod KEYWORD1 +NeoEsp32I2s0400KbpsInvertdMethod KEYWORD1 +NeoEsp32I2s0Apa106InvertdMethod KEYWORD1 +NeoEsp32I2s1Ws2812xInvertdMethod KEYWORD1 +NeoEsp32I2s1Sk6812InvertdMethod KEYWORD1 +NeoEsp32I2s1800KbpsInvertdMethod KEYWORD1 +NeoEsp32I2s1400KbpsInvertdMethod KEYWORD1 +NeoEsp32I2s1Apa106InvertdMethod KEYWORD1 NeoEsp32Rmt0Ws2812xMethod KEYWORD1 NeoEsp32Rmt0Sk6812Method KEYWORD1 NeoEsp32Rmt0Apa106Method KEYWORD1 @@ -116,6 +189,46 @@ NeoEsp32Rmt7Sk6812Method KEYWORD1 NeoEsp32Rmt7Apa106Method KEYWORD1 NeoEsp32Rmt7800KbpsMethod KEYWORD1 NeoEsp32Rmt7400KbpsMethod KEYWORD1 +NeoEsp32Rmt0Ws2812xInvertedMethod KEYWORD1 +NeoEsp32Rmt0Sk6812InvertedMethod KEYWORD1 +NeoEsp32Rmt0Apa106InvertedMethod KEYWORD1 +NeoEsp32Rmt0800KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt0400KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt1Ws2812xInvertedMethod KEYWORD1 +NeoEsp32Rmt1Sk6812InvertedMethod KEYWORD1 +NeoEsp32Rmt1Apa106InvertedMethod KEYWORD1 +NeoEsp32Rmt1800KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt1400KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt2Ws2812xInvertedMethod KEYWORD1 +NeoEsp32Rmt2Sk6812InvertedMethod KEYWORD1 +NeoEsp32Rmt2Apa106InvertedMethod KEYWORD1 +NeoEsp32Rmt2800KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt2400KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt3Ws2812xInvertedMethod KEYWORD1 +NeoEsp32Rmt3Sk6812InvertedMethod KEYWORD1 +NeoEsp32Rmt3Apa106InvertedMethod KEYWORD1 +NeoEsp32Rmt3800KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt3400KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt4Ws2812xInvertedMethod KEYWORD1 +NeoEsp32Rmt4Sk6812InvertedMethod KEYWORD1 +NeoEsp32Rmt4Apa106InvertedMethod KEYWORD1 +NeoEsp32Rmt4800KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt4400KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt5Ws2812xInvertedMethod KEYWORD1 +NeoEsp32Rmt5Sk6812InvertedMethod KEYWORD1 +NeoEsp32Rmt5Apa106InvertedMethod KEYWORD1 +NeoEsp32Rmt5800KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt5400KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt6Ws2812xInvertedMethod KEYWORD1 +NeoEsp32Rmt6Sk6812InvertedMethod KEYWORD1 +NeoEsp32Rmt6Apa106InvertedMethod KEYWORD1 +NeoEsp32Rmt6800KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt6400KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt7Ws2812xInvertedMethod KEYWORD1 +NeoEsp32Rmt7Sk6812InvertedMethod KEYWORD1 +NeoEsp32Rmt7Apa106InvertedMethod KEYWORD1 +NeoEsp32Rmt7800KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt7400KbpsInvertedMethod KEYWORD1 NeoEsp32BitBangWs2813Method KEYWORD1 NeoEsp32BitBangWs2812xMethod KEYWORD1 NeoEsp32BitBangWs2812Method KEYWORD1 @@ -124,6 +237,14 @@ NeoEsp32BitBangLc8812Method KEYWORD1 NeoEsp32BitBangApa106Method KEYWORD1 NeoEsp32BitBang800KbpsMethod KEYWORD1 NeoEsp32BitBang400KbpsMethod KEYWORD1 +NeoEsp32BitBangWs2813InvertedMethod KEYWORD1 +NeoEsp32BitBangWs2812xInvertedMethod KEYWORD1 +NeoEsp32BitBangWs2812InvertedMethod KEYWORD1 +NeoEsp32BitBangSk6812InvertedMethod KEYWORD1 +NeoEsp32BitBangLc8812InvertedMethod KEYWORD1 +NeoEsp32BitBangApa106InvertedMethod KEYWORD1 +NeoEsp32BitBang800KbpsInvertedMethod KEYWORD1 +NeoEsp32BitBang400KbpsInvertedMethod KEYWORD1 DotStarMethod KEYWORD1 DotStarSpiMethod KEYWORD1 DotStarSpi20MhzMethod KEYWORD1 diff --git a/src/internal/Esp32_i2s.c b/src/internal/Esp32_i2s.c index 092170e..6e29213 100644 --- a/src/internal/Esp32_i2s.c +++ b/src/internal/Esp32_i2s.c @@ -201,7 +201,7 @@ void i2sSetDac(uint8_t bus_num, bool right, bool left) { return; } - i2sSetPins(bus_num, -1, -1, -1, -1); + i2sSetPins(bus_num, -1, -1, -1, -1, false); I2S[bus_num].bus->conf2.lcd_en = 1; I2S[bus_num].bus->conf.tx_right_first = 0; I2S[bus_num].bus->conf2.camera_en = 0; @@ -216,7 +216,7 @@ void i2sSetDac(uint8_t bus_num, bool right, bool left) { } } -void i2sSetPins(uint8_t bus_num, int8_t out, int8_t ws, int8_t bck, int8_t in) { +void i2sSetPins(uint8_t bus_num, int8_t out, int8_t ws, int8_t bck, int8_t in, bool invert) { if (bus_num > 1) { return; } @@ -228,42 +228,42 @@ void i2sSetPins(uint8_t bus_num, int8_t out, int8_t ws, int8_t bck, int8_t in) { if (ws >= 0) { if (I2S[bus_num].ws != ws) { if (I2S[bus_num].ws >= 0) { - gpio_matrix_out(I2S[bus_num].ws, 0x100, false, false); + gpio_matrix_out(I2S[bus_num].ws, 0x100, invert, false); } I2S[bus_num].ws = ws; pinMode(ws, OUTPUT); - gpio_matrix_out(ws, bus_num?I2S1O_WS_OUT_IDX:I2S0O_WS_OUT_IDX, false, false); + gpio_matrix_out(ws, bus_num?I2S1O_WS_OUT_IDX:I2S0O_WS_OUT_IDX, invert, false); } } else if (I2S[bus_num].ws >= 0) { - gpio_matrix_out(I2S[bus_num].ws, 0x100, false, false); + gpio_matrix_out(I2S[bus_num].ws, 0x100, invert, false); I2S[bus_num].ws = -1; } if (bck >= 0) { if (I2S[bus_num].bck != bck) { if (I2S[bus_num].bck >= 0) { - gpio_matrix_out(I2S[bus_num].bck, 0x100, false, false); + gpio_matrix_out(I2S[bus_num].bck, 0x100, invert, false); } I2S[bus_num].bck = bck; pinMode(bck, OUTPUT); - gpio_matrix_out(bck, bus_num?I2S1O_BCK_OUT_IDX:I2S0O_BCK_OUT_IDX, false, false); + gpio_matrix_out(bck, bus_num?I2S1O_BCK_OUT_IDX:I2S0O_BCK_OUT_IDX, invert, false); } } else if (I2S[bus_num].bck >= 0) { - gpio_matrix_out(I2S[bus_num].bck, 0x100, false, false); + gpio_matrix_out(I2S[bus_num].bck, 0x100, invert, false); I2S[bus_num].bck = -1; } if (out >= 0) { if (I2S[bus_num].out != out) { if (I2S[bus_num].out >= 0) { - gpio_matrix_out(I2S[bus_num].out, 0x100, false, false); + gpio_matrix_out(I2S[bus_num].out, 0x100, invert, false); } I2S[bus_num].out = out; pinMode(out, OUTPUT); - gpio_matrix_out(out, bus_num?I2S1O_DATA_OUT23_IDX:I2S0O_DATA_OUT23_IDX, false, false); + gpio_matrix_out(out, bus_num?I2S1O_DATA_OUT23_IDX:I2S0O_DATA_OUT23_IDX, invert, false); } } else if (I2S[bus_num].out >= 0) { - gpio_matrix_out(I2S[bus_num].out, 0x100, false, false); + gpio_matrix_out(I2S[bus_num].out, 0x100, invert, false); I2S[bus_num].out = -1; } diff --git a/src/internal/Esp32_i2s.h b/src/internal/Esp32_i2s.h index 0027369..589f234 100644 --- a/src/internal/Esp32_i2s.h +++ b/src/internal/Esp32_i2s.h @@ -20,7 +20,7 @@ typedef enum { void i2sInit(uint8_t bus_num, uint32_t bits_per_sample, uint32_t sample_rate, i2s_tx_chan_mod_t chan_mod, i2s_tx_fifo_mod_t fifo_mod, size_t dma_count, size_t dma_len); -void i2sSetPins(uint8_t bus_num, int8_t out, int8_t ws, int8_t bck, int8_t in); +void i2sSetPins(uint8_t bus_num, int8_t out, int8_t ws, int8_t bck, int8_t in, bool invert); void i2sSetDac(uint8_t bus_num, bool right, bool left); esp_err_t i2sSetClock(uint8_t bus_num, uint8_t div_num, uint8_t div_b, uint8_t div_a, uint8_t bck, uint8_t bits_per_sample); diff --git a/src/internal/NeoEsp32I2sMethod.h b/src/internal/NeoEsp32I2sMethod.h index d7856a1..15e9b20 100644 --- a/src/internal/NeoEsp32I2sMethod.h +++ b/src/internal/NeoEsp32I2sMethod.h @@ -88,7 +88,19 @@ public: const static uint8_t I2sBusNumber = 1; }; -template class NeoEsp32I2sMethodBase +class NeoEsp32I2sNotInverted +{ +public: + const static bool Inverted = false; +}; + +class NeoEsp32I2sInverted +{ +public: + const static bool Inverted = true; +}; + +template class NeoEsp32I2sMethodBase { public: NeoEsp32I2sMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize) : @@ -136,7 +148,7 @@ public: { size_t dmaCount = (_i2sBufferSize + I2S_DMA_MAX_DATA_LEN - 1) / I2S_DMA_MAX_DATA_LEN; i2sInit(T_BUS::I2sBusNumber, 16, T_SPEED::I2sSampleRate, I2S_CHAN_STEREO, I2S_FIFO_16BIT_DUAL, dmaCount, 0); - i2sSetPins(T_BUS::I2sBusNumber, _pin, -1, -1, -1); + i2sSetPins(T_BUS::I2sBusNumber, _pin, -1, -1, -1, T_INVERT::Inverted); } void Update(bool) @@ -191,17 +203,29 @@ private: } }; -typedef NeoEsp32I2sMethodBase NeoEsp32I2s0Ws2812xMethod; -typedef NeoEsp32I2sMethodBase NeoEsp32I2s0Sk6812Method; -typedef NeoEsp32I2sMethodBase NeoEsp32I2s0800KbpsMethod; -typedef NeoEsp32I2sMethodBase NeoEsp32I2s0400KbpsMethod; -typedef NeoEsp32I2sMethodBase NeoEsp32I2s0Apa106Method; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0Ws2812xMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0Sk6812Method; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0800KbpsMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0400KbpsMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0Apa106Method; -typedef NeoEsp32I2sMethodBase NeoEsp32I2s1Ws2812xMethod; -typedef NeoEsp32I2sMethodBase NeoEsp32I2s1Sk6812Method; -typedef NeoEsp32I2sMethodBase NeoEsp32I2s1800KbpsMethod; -typedef NeoEsp32I2sMethodBase NeoEsp32I2s1400KbpsMethod; -typedef NeoEsp32I2sMethodBase NeoEsp32I2s1Apa106Method; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1Ws2812xMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1Sk6812Method; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1800KbpsMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1400KbpsMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1Apa106Method; + +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0Ws2812xInvertedMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0Sk6812InvertedMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0800KbpsInvertedMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0400KbpsInvertedMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0Apa106InvertedMethod; + +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1Ws2812xInvertedMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1Sk6812InvertedMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1800KbpsInvertedMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1400KbpsInvertedMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1Apa106InvertedMethod; // I2s Bus 1 method is the default method for Esp32 typedef NeoEsp32I2s1Ws2812xMethod NeoWs2813Method; @@ -214,4 +238,13 @@ typedef NeoEsp32I2s1Apa106Method NeoApa106Method; typedef NeoEsp32I2s1Ws2812xMethod Neo800KbpsMethod; typedef NeoEsp32I2s1400KbpsMethod Neo400KbpsMethod; +typedef NeoEsp32I2s1Ws2812xInvertedMethod NeoWs2813InvertedMethod; +typedef NeoEsp32I2s1Ws2812xInvertedMethod NeoWs2812xInvertedMethod; +typedef NeoEsp32I2s1800KbpsInvertedMethod NeoWs2812InvertedMethod; +typedef NeoEsp32I2s1Sk6812InvertedMethod NeoSk6812InvertedMethod; +typedef NeoEsp32I2s1Sk6812InvertedMethod NeoLc8812InvertedMethod; +typedef NeoEsp32I2s1Apa106InvertedMethod NeoApa106InvertedMethod; + +typedef NeoEsp32I2s1Ws2812xInvertedMethod Neo800KbpsInvertedMethod; +typedef NeoEsp32I2s1400KbpsInvertedMethod Neo400KbpsInvertedMethod; #endif \ No newline at end of file diff --git a/src/internal/NeoEsp32RmtMethod.h b/src/internal/NeoEsp32RmtMethod.h index 7da8b57..35a3255 100644 --- a/src/internal/NeoEsp32RmtMethod.h +++ b/src/internal/NeoEsp32RmtMethod.h @@ -46,7 +46,7 @@ extern "C" #include } -class NeoEsp32RmtSpeedBase +class NeoEsp32RmtSpeed { public: // ClkDiv of 2 provides for good resolution and plenty of reset resolution; but @@ -58,20 +58,41 @@ public: { return ns / NsPerRmtTick; } - // this is used rather than the rmt_item32_t as you can't correctly initialize - // it as a static constexpr within the template - inline constexpr static uint32_t Item32Val(uint16_t nsHigh, uint16_t nsLow) - { - return (FromNs(nsLow) << 16) | (1 << 15) | (FromNs(nsHigh)); - } -public: + +protected: const static uint32_t RmtCpu = 80000000L; // 80 mhz RMT clock const static uint32_t NsPerSecond = 1000000000L; const static uint32_t RmtTicksPerSecond = (RmtCpu / RmtClockDivider); const static uint32_t NsPerRmtTick = (NsPerSecond / RmtTicksPerSecond); // about 25 }; +class NeoEsp32RmtSpeedBase : public NeoEsp32RmtSpeed +{ +public: + // this is used rather than the rmt_item32_t as you can't correctly initialize + // it as a static constexpr within the template + inline constexpr static uint32_t Item32Val(uint16_t nsHigh, uint16_t nsLow) + { + return (FromNs(nsLow) << 16) | (1 << 15) | (FromNs(nsHigh)); + } + + const static rmt_idle_level_t IdleLevel = RMT_IDLE_LEVEL_LOW; +}; + +class NeoEsp32RmtInvertedSpeedBase : public NeoEsp32RmtSpeed +{ +public: + // this is used rather than the rmt_item32_t as you can't correctly initialize + // it as a static constexpr within the template + inline constexpr static uint32_t Item32Val(uint16_t nsHigh, uint16_t nsLow) + { + return (FromNs(nsLow) << 16) | (1 << 31) | (FromNs(nsHigh)); + } + + const static rmt_idle_level_t IdleLevel = RMT_IDLE_LEVEL_HIGH; +}; + class NeoEsp32RmtSpeedWs2812x : public NeoEsp32RmtSpeedBase { public: @@ -112,6 +133,46 @@ public: const static uint16_t RmtDurationReset = FromNs(50000); // 50us }; +class NeoEsp32RmtInvertedSpeedWs2812x : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static uint32_t RmtBit0 = Item32Val(400, 850); + const static uint32_t RmtBit1 = Item32Val(800, 450); + const static uint16_t RmtDurationReset = FromNs(300000); // 300us +}; + +class NeoEsp32RmtInvertedSpeedSk6812 : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static uint32_t RmtBit0 = Item32Val(400, 850); + const static uint32_t RmtBit1 = Item32Val(800, 450); + const static uint16_t RmtDurationReset = FromNs(80000); // 80us +}; + +class NeoEsp32RmtInvertedSpeed800Kbps : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static uint32_t RmtBit0 = Item32Val(400, 850); + const static uint32_t RmtBit1 = Item32Val(800, 450); + const static uint16_t RmtDurationReset = FromNs(50000); // 50us +}; + +class NeoEsp32RmtInvertedSpeed400Kbps : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static uint32_t RmtBit0 = Item32Val(800, 1700); + const static uint32_t RmtBit1 = Item32Val(1600, 900); + const static uint16_t RmtDurationReset = FromNs(50000); // 50us +}; + +class NeoEsp32RmtInvertedSpeedApa106 : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static uint32_t RmtBit0 = Item32Val(400, 1250); + const static uint32_t RmtBit1 = Item32Val(1250, 400); + const static uint16_t RmtDurationReset = FromNs(50000); // 50us +}; + class NeoEsp32RmtChannel0 { public: @@ -204,7 +265,7 @@ public: config.tx_config.loop_en = false; config.tx_config.idle_output_en = true; - config.tx_config.idle_level = RMT_IDLE_LEVEL_LOW; + config.tx_config.idle_level = T_SPEED::IdleLevel; config.tx_config.carrier_en = false; config.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW; @@ -316,6 +377,7 @@ private: } }; +// normal typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Ws2812xMethod; typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Sk6812Method; typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Apa106Method; @@ -364,6 +426,55 @@ typedef NeoEsp32RmtMethodBase NeoEs typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7800KbpsMethod; typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7400KbpsMethod; +// inverted +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0400KbpsInvertedMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1400KbpsInvertedMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2400KbpsInvertedMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3400KbpsInvertedMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4400KbpsInvertedMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5400KbpsInvertedMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6400KbpsInvertedMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7400KbpsInvertedMethod; + // RMT is NOT the default method for Esp32, // you are required to use a specific channel listed above diff --git a/src/internal/NeoEsp8266DmaMethod.h b/src/internal/NeoEsp8266DmaMethod.h index 402c9ae..fa6e6bb 100644 --- a/src/internal/NeoEsp8266DmaMethod.h +++ b/src/internal/NeoEsp8266DmaMethod.h @@ -65,7 +65,43 @@ struct slc_queue_item uint32 next_link_ptr; }; -class NeoEsp8266DmaSpeed800KbpsBase +class NeoEsp8266DmaSpeedBase +{ +public: + static const uint8_t Level = 0x00; + static uint16_t Convert(uint8_t value) + { + const uint16_t bitpatterns[16] = + { + 0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110, + 0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110, + 0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110, + 0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110, + }; + + return bitpatterns[value]; + } +}; + +class NeoEsp8266DmaInvertedSpeedBase +{ +public: + static const uint8_t Level = 0xFF; + static uint16_t Convert(uint8_t value) + { + const uint16_t bitpatterns[16] = + { + 0b0111011101110111, 0b0111011101110001, 0b0111011100010111, 0b0111011100010001, + 0b0111000101110111, 0b0111000101110001, 0b0111000100010111, 0b0111000100010001, + 0b0001011101110111, 0b0001011101110001, 0b0001011100010111, 0b0001011100010001, + 0b0001000101110111, 0b0001000101110001, 0b0001000100010111, 0b0001000100010001, + }; + + return bitpatterns[value]; + } +}; + +class NeoEsp8266DmaSpeed800KbpsBase : public NeoEsp8266DmaSpeedBase { public: const static uint32_t I2sClockDivisor = 3; @@ -91,7 +127,7 @@ public: const static uint32_t ResetTimeUs = 50; }; -class NeoEsp8266DmaSpeed400Kbps +class NeoEsp8266DmaSpeed400Kbps : public NeoEsp8266DmaSpeedBase { public: const static uint32_t I2sClockDivisor = 6; @@ -100,7 +136,7 @@ public: const static uint32_t ResetTimeUs = 50; }; -class NeoEsp8266DmaSpeedApa106 +class NeoEsp8266DmaSpeedApa106 : public NeoEsp8266DmaSpeedBase { public: const static uint32_t I2sClockDivisor = 4; @@ -109,6 +145,52 @@ public: const static uint32_t ResetTimeUs = 50; }; + + +class NeoEsp8266DmaInvertedSpeed800KbpsBase : public NeoEsp8266DmaInvertedSpeedBase +{ +public: + const static uint32_t I2sClockDivisor = 3; + const static uint32_t I2sBaseClockDivisor = 16; + const static uint32_t ByteSendTimeUs = 10; // us it takes to send a single pixel element at 800khz speed +}; + +class NeoEsp8266DmaInvertedSpeedWs2812x : public NeoEsp8266DmaInvertedSpeed800KbpsBase +{ +public: + const static uint32_t ResetTimeUs = 300; +}; + +class NeoEsp8266DmaInvertedSpeedSk6812 : public NeoEsp8266DmaInvertedSpeed800KbpsBase +{ +public: + const static uint32_t ResetTimeUs = 80; +}; + +class NeoEsp8266DmaInvertedSpeed800Kbps : public NeoEsp8266DmaInvertedSpeed800KbpsBase +{ +public: + const static uint32_t ResetTimeUs = 50; +}; + +class NeoEsp8266DmaInvertedSpeed400Kbps : public NeoEsp8266DmaInvertedSpeedBase +{ +public: + const static uint32_t I2sClockDivisor = 6; + const static uint32_t I2sBaseClockDivisor = 16; + const static uint32_t ByteSendTimeUs = 20; // us it takes to send a single pixel element at 400khz speed + const static uint32_t ResetTimeUs = 50; +}; + +class NeoEsp8266DmaInvertedSpeedApa106 : public NeoEsp8266DmaInvertedSpeedBase +{ +public: + const static uint32_t I2sClockDivisor = 4; + const static uint32_t I2sBaseClockDivisor = 16; + const static uint32_t ByteSendTimeUs = 17; // us it takes to send a single pixel element + const static uint32_t ResetTimeUs = 50; +}; + enum NeoDmaState { NeoDmaState_Idle, @@ -134,11 +216,11 @@ public: memset(_pixels, 0x00, _pixelsSize); _i2sBuffer = (uint8_t*)malloc(_i2sBufferSize); - memset(_i2sBuffer, 0x00, _i2sBufferSize); + memset(_i2sBuffer, T_SPEED::Level, _i2sBufferSize); // _i2sBuffer[0] = 0b11101000; // debug, 1 bit then 0 bit - memset(_i2sZeroes, 0x00, sizeof(_i2sZeroes)); + memset(_i2sZeroes, T_SPEED::Level, sizeof(_i2sZeroes)); _is2BufMaxBlockSize = (c_maxDmaBlockSize / dmaPixelSize) * dmaPixelSize; @@ -392,20 +474,12 @@ private: void FillBuffers() { - const uint16_t bitpatterns[16] = - { - 0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110, - 0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110, - 0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110, - 0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110, - }; - uint16_t* pDma = (uint16_t*)_i2sBuffer; uint8_t* pPixelsEnd = _pixels + _pixelsSize; for (uint8_t* pPixel = _pixels; pPixel < pPixelsEnd; pPixel++) { - *(pDma++) = bitpatterns[((*pPixel) & 0x0f)]; - *(pDma++) = bitpatterns[((*pPixel) >> 4) & 0x0f]; + *(pDma++) = T_SPEED::Convert(((*pPixel) & 0x0f)); + *(pDma++) = T_SPEED::Convert(((*pPixel) >> 4) & 0x0f); } } @@ -437,15 +511,24 @@ private: }; + template NeoEsp8266DmaMethodBase* NeoEsp8266DmaMethodBase::s_this; +// normal typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaWs2812xMethod; typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaSk6812Method; typedef NeoEsp8266DmaMethodBase NeoEsp8266Dma800KbpsMethod; typedef NeoEsp8266DmaMethodBase NeoEsp8266Dma400KbpsMethod; typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaApa106Method; +// inverted +typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaInvertedWs2812xMethod; +typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaInvertedSk6812Method; +typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaInverted800KbpsMethod; +typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaInverted400KbpsMethod; +typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaInvertedApa106Method; + // Dma method is the default method for Esp8266 typedef NeoEsp8266DmaWs2812xMethod NeoWs2813Method; typedef NeoEsp8266DmaWs2812xMethod NeoWs2812xMethod; @@ -457,4 +540,14 @@ typedef NeoEsp8266DmaApa106Method NeoApa106Method; typedef NeoEsp8266DmaWs2812xMethod Neo800KbpsMethod; typedef NeoEsp8266Dma400KbpsMethod Neo400KbpsMethod; +// inverted +typedef NeoEsp8266DmaInvertedWs2812xMethod NeoWs2813InvertedMethod; +typedef NeoEsp8266DmaInvertedWs2812xMethod NeoWs2812xInvertedMethod; +typedef NeoEsp8266DmaInverted800KbpsMethod NeoWs2812InvertedMethod; +typedef NeoEsp8266DmaInvertedSk6812Method NeoSk6812InvertedMethod; +typedef NeoEsp8266DmaInvertedSk6812Method NeoLc8812InvertedMethod; +typedef NeoEsp8266DmaInvertedApa106Method NeoApa106InvertedMethod; + +typedef NeoEsp8266DmaInvertedWs2812xMethod Neo800KbpsInvertedMethod; +typedef NeoEsp8266DmaInverted400KbpsMethod Neo400KbpsInvertedMethod; #endif diff --git a/src/internal/NeoEsp8266UartMethod.h b/src/internal/NeoEsp8266UartMethod.h index d45436b..8756df3 100644 --- a/src/internal/NeoEsp8266UartMethod.h +++ b/src/internal/NeoEsp8266UartMethod.h @@ -88,14 +88,19 @@ private: class UartFeatureBase { protected: - static void ConfigUart(uint8_t uartNum) + static void ConfigUart(uint8_t uartNum, bool invert) { // clear all invert bits USC0(uartNum) &= ~((1 << UCDTRI) | (1 << UCRTSI) | (1 << UCTXI) | (1 << UCDSRI) | (1 << UCCTSI) | (1 << UCRXI)); - // Invert the TX voltage associated with logic level so: - // - A logic level 0 will generate a Vcc signal - // - A logic level 1 will generate a Gnd signal - USC0(uartNum) |= (1 << UCTXI); + + if (!invert) + { + // For normal operations, + // Invert the TX voltage associated with logic level so: + // - A logic level 0 will generate a Vcc signal + // - A logic level 1 will generate a Gnd signal + USC0(uartNum) |= (1 << UCTXI); + } } }; @@ -106,11 +111,11 @@ class UartFeature0 : UartFeatureBase { public: static const uint32_t Index = 0; - static void Init(uint32_t baud) + static void Init(uint32_t baud, bool invert) { // Configure the serial line with 1 start bit (0), 6 data bits and 1 stop bit (1) Serial.begin(baud, SERIAL_6N1, SERIAL_TX_ONLY); - ConfigUart(Index); + ConfigUart(Index, invert); } }; @@ -121,11 +126,11 @@ class UartFeature1 : UartFeatureBase { public: static const uint32_t Index = 1; - static void Init(uint32_t baud) + static void Init(uint32_t baud, bool invert) { // Configure the serial line with 1 start bit (0), 6 data bits and 1 stop bit (1) Serial1.begin(baud, SERIAL_6N1, SERIAL_TX_ONLY); - ConfigUart(Index); + ConfigUart(Index, invert); } }; @@ -179,9 +184,9 @@ protected: } } - void InitializeUart(uint32_t uartBaud) + void InitializeUart(uint32_t uartBaud, bool invert) { - T_UARTFEATURE::Init(uartBaud); + T_UARTFEATURE::Init(uartBaud, invert); } void UpdateUart(bool) @@ -237,9 +242,9 @@ protected: free(_pixelsSending); } - void ICACHE_RAM_ATTR InitializeUart(uint32_t uartBaud) + void ICACHE_RAM_ATTR InitializeUart(uint32_t uartBaud, bool invert) { - T_UARTFEATURE::Init(uartBaud); + T_UARTFEATURE::Init(uartBaud, invert); // attach the context, which will enable the ISR _context.Attach(T_UARTFEATURE::Index); @@ -319,9 +324,21 @@ public: static const uint32_t ResetTimeUs = 50; // us between data send bursts to reset for next update }; +class NeoEsp8266UartNotInverted +{ +public: + const static bool Inverted = false; +}; + +class NeoEsp8266UartInverted +{ +public: + const static bool Inverted = true; +}; + // NeoEsp8266UartMethodBase is a light shell arround NeoEsp8266Uart or NeoEsp8266AsyncUart that // implements the methods needed to operate as a NeoPixelBus method. -template +template class NeoEsp8266UartMethodBase: public T_BASE { public: @@ -342,7 +359,7 @@ public: void Initialize() { - this->InitializeUart(T_SPEED::UartBaud); + this->InitializeUart(T_SPEED::UartBaud, T_INVERT::Inverted); // Inverting logic levels can generate a phantom bit in the led strip bus // We need to delay 50+ microseconds the output stream to force a data @@ -384,48 +401,93 @@ private: }; // uart 0 -typedef NeoEsp8266UartMethodBase> NeoEsp8266Uart0Ws2812xMethod; -typedef NeoEsp8266UartMethodBase> NeoEsp8266Uart0Sk6812Method; -typedef NeoEsp8266UartMethodBase> NeoEsp8266Uart0Apa106Method; -typedef NeoEsp8266UartMethodBase> NeoEsp8266Uart0800KbpsMethod; -typedef NeoEsp8266UartMethodBase> NeoEsp8266Uart0400KbpsMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart0Ws2812xMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart0Sk6812Method; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart0Apa106Method; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart0800KbpsMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart0400KbpsMethod; typedef NeoEsp8266Uart0Ws2812xMethod NeoEsp8266Uart0Ws2813Method; typedef NeoEsp8266Uart0800KbpsMethod NeoEsp8266Uart0Ws2812Method; typedef NeoEsp8266Uart0Sk6812Method NeoEsp8266Uart0Lc8812Method; // uart 1 -typedef NeoEsp8266UartMethodBase> NeoEsp8266Uart1Ws2812xMethod; -typedef NeoEsp8266UartMethodBase> NeoEsp8266Uart1Sk6812Method; -typedef NeoEsp8266UartMethodBase> NeoEsp8266Uart1Apa106Method; -typedef NeoEsp8266UartMethodBase> NeoEsp8266Uart1800KbpsMethod; -typedef NeoEsp8266UartMethodBase> NeoEsp8266Uart1400KbpsMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart1Ws2812xMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart1Sk6812Method; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart1Apa106Method; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart1800KbpsMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart1400KbpsMethod; typedef NeoEsp8266Uart1Ws2812xMethod NeoEsp8266Uart1Ws2813Method; typedef NeoEsp8266Uart1800KbpsMethod NeoEsp8266Uart1Ws2812Method; typedef NeoEsp8266Uart1Sk6812Method NeoEsp8266Uart1Lc8812Method; // uart 0 async -typedef NeoEsp8266UartMethodBase> NeoEsp8266AsyncUart0Ws2812xMethod; -typedef NeoEsp8266UartMethodBase> NeoEsp8266AsyncUart0Sk6812Method; -typedef NeoEsp8266UartMethodBase> NeoEsp8266AsyncUart0Apa106Method; -typedef NeoEsp8266UartMethodBase> NeoEsp8266AsyncUart0800KbpsMethod; -typedef NeoEsp8266UartMethodBase> NeoEsp8266AsyncUart0400KbpsMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0Ws2812xMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0Sk6812Method; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0Apa106Method; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0800KbpsMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0400KbpsMethod; typedef NeoEsp8266AsyncUart0Ws2812xMethod NeoEsp8266AsyncUart0Ws2813Method; typedef NeoEsp8266AsyncUart0800KbpsMethod NeoEsp8266AsyncUart0Ws2812Method; typedef NeoEsp8266AsyncUart0Sk6812Method NeoEsp8266AsyncUart0Lc8812Method; // uart 1 async -typedef NeoEsp8266UartMethodBase> NeoEsp8266AsyncUart1Ws2812xMethod; -typedef NeoEsp8266UartMethodBase> NeoEsp8266AsyncUart1Sk6812Method; -typedef NeoEsp8266UartMethodBase> NeoEsp8266AsyncUart1Apa106Method; -typedef NeoEsp8266UartMethodBase> NeoEsp8266AsyncUart1800KbpsMethod; -typedef NeoEsp8266UartMethodBase> NeoEsp8266AsyncUart1400KbpsMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1Ws2812xMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1Sk6812Method; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1Apa106Method; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1800KbpsMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1400KbpsMethod; typedef NeoEsp8266AsyncUart1Ws2812xMethod NeoEsp8266AsyncUart1Ws2813Method; typedef NeoEsp8266AsyncUart1800KbpsMethod NeoEsp8266AsyncUart1Ws2812Method; typedef NeoEsp8266AsyncUart1Sk6812Method NeoEsp8266AsyncUart1Lc8812Method; +// inverted +// +// uart 0 +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart0Ws2812xInvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart0Sk6812InvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart0Apa106InvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart0800KbpsInvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart0400KbpsInvertedMethod; + +typedef NeoEsp8266Uart0Ws2812xInvertedMethod NeoEsp8266Uart0Ws2813InvertedMethod; +typedef NeoEsp8266Uart0800KbpsInvertedMethod NeoEsp8266Uart0Ws2812InvertedMethod; +typedef NeoEsp8266Uart0Sk6812InvertedMethod NeoEsp8266Uart0Lc8812InvertedMethod; + +// uart 1 +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart1Ws2812xInvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart1Sk6812InvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart1Apa106InvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart1800KbpsInvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart1400KbpsInvertedMethod; + +typedef NeoEsp8266Uart1Ws2812xInvertedMethod NeoEsp8266Uart1Ws2813InvertedMethod; +typedef NeoEsp8266Uart1800KbpsInvertedMethod NeoEsp8266Uart1Ws2812InvertedMethod; +typedef NeoEsp8266Uart1Sk6812InvertedMethod NeoEsp8266Uart1Lc8812InvertedMethod; + +// uart 0 async +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0Ws2812xInvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0Sk6812InvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0Apa106InvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0800KbpsInvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0400KbpsInvertedMethod; + +typedef NeoEsp8266AsyncUart0Ws2812xInvertedMethod NeoEsp8266AsyncUart0Ws2813InvertedMethod; +typedef NeoEsp8266AsyncUart0800KbpsInvertedMethod NeoEsp8266AsyncUart0Ws2812InvertedMethod; +typedef NeoEsp8266AsyncUart0Sk6812InvertedMethod NeoEsp8266AsyncUart0Lc8812InvertedMethod; + +// uart 1 async +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1Ws2812xInvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1Sk6812InvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1Apa106InvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1800KbpsInvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1400KbpsInvertedMethod; + +typedef NeoEsp8266AsyncUart1Ws2812xInvertedMethod NeoEsp8266AsyncUart1Ws2813InvertedMethod; +typedef NeoEsp8266AsyncUart1800KbpsInvertedMethod NeoEsp8266AsyncUart1Ws2812InvertedMethod; +typedef NeoEsp8266AsyncUart1Sk6812InvertedMethod NeoEsp8266AsyncUart1Lc8812InvertedMethod; #endif diff --git a/src/internal/NeoEspBitBangMethod.h b/src/internal/NeoEspBitBangMethod.h index 3615602..c941675 100644 --- a/src/internal/NeoEspBitBangMethod.h +++ b/src/internal/NeoEspBitBangMethod.h @@ -28,58 +28,195 @@ License along with NeoPixel. If not, see #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) +#if defined(ARDUINO_ARCH_ESP8266) +#include +#endif + // ESP32 doesn't define ICACHE_RAM_ATTR #ifndef ICACHE_RAM_ATTR #define ICACHE_RAM_ATTR IRAM_ATTR #endif -// for esp8266, due to linker overriding the ICACHE_RAM_ATTR for cpp files, these methods are -// moved into a C file so the attribute will be applied correctly -// >> this may have been fixed and is no longer a requirement << -extern "C" void ICACHE_RAM_ATTR bitbang_send_pixels_800(uint8_t* pixels, uint8_t* end, uint8_t pin); -extern "C" void ICACHE_RAM_ATTR bitbang_send_pixels_400(uint8_t* pixels, uint8_t* end, uint8_t pin); +static uint32_t _getCycleCount(void) __attribute__((always_inline)); -class NeoEspBitBangSpeedWs2812x +static inline uint32_t _getCycleCount(void) +{ + uint32_t ccount; + __asm__ __volatile__("rsr %0,ccount":"=a" (ccount)); + return ccount; +} + +#define CYCLES_LOOPTEST (4) // adjustment due to loop exit test instruction cycles + +class NeoEspSpeed800Mhz +{ +public: + const static uint32_t T0H = (F_CPU / 2500000 - CYCLES_LOOPTEST); // 0.4us + const static uint32_t T1H = (F_CPU / 1250000 - CYCLES_LOOPTEST); // 0.8us + const static uint32_t Period = (F_CPU / 800000 - CYCLES_LOOPTEST); // 1.25us per bit +}; + +class NeoEspSpeed400Mhz +{ +public: + const static uint32_t T0H = (F_CPU / 2000000 - CYCLES_LOOPTEST); + const static uint32_t T1H = (F_CPU / 833333 - CYCLES_LOOPTEST); + const static uint32_t Period = (F_CPU / 400000 - CYCLES_LOOPTEST); +}; + +class NeoEspPinset +{ +public: + const static uint8_t IdleLevel = LOW; + + inline const static void setPin(const uint32_t pinRegister) + { +#if defined(ARDUINO_ARCH_ESP32) + GPIO.out_w1ts = pinRegister; +#else + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinRegister); +#endif + } + + inline const static void resetPin(const uint32_t pinRegister) + { +#if defined(ARDUINO_ARCH_ESP32) + GPIO.out_w1tc = pinRegister; +#else + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinRegister); +#endif + } +}; + +class NeoEspPinsetInverted +{ +public: + const static uint8_t IdleLevel = HIGH; + + inline const static void setPin(const uint32_t pinRegister) + { +#if defined(ARDUINO_ARCH_ESP32) + GPIO.out_w1tc = pinRegister; +#else + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinRegister); +#endif + } + + inline const static void resetPin(const uint32_t pinRegister) + { +#if defined(ARDUINO_ARCH_ESP32) + GPIO.out_w1ts = pinRegister; +#else + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinRegister); +#endif + } +}; + +template class NeoEspBitBangBase +{ +public: + static void ICACHE_RAM_ATTR 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 = T_SPEED::T0H; + if (subpix & mask) + { + cyclesBit = T_SPEED::T1H; + } + + // after we have done as much work as needed for this next bit + // now wait for the HIGH + while (((cyclesStart = _getCycleCount()) - cyclesNext) < T_SPEED::Period); + + // set pin state + T_PINSET::setPin(pinRegister); + + // wait for the LOW + while ((_getCycleCount() - cyclesStart) < cyclesBit); + + // reset pin start + T_PINSET::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++; + } + } + } + +}; + +class NeoEspBitBangSpeedWs2812x : public NeoEspBitBangBase { public: - static void send_pixels(uint8_t* pixels, uint8_t* end, uint8_t pin) - { - bitbang_send_pixels_800(pixels, end, pin); - } static const uint32_t ResetTimeUs = 300; }; -class NeoEspBitBangSpeedSk6812 +class NeoEspBitBangSpeedSk6812 : public NeoEspBitBangBase { public: - static void send_pixels(uint8_t* pixels, uint8_t* end, uint8_t pin) - { - bitbang_send_pixels_800(pixels, end, pin); - } static const uint32_t ResetTimeUs = 80; }; -class NeoEspBitBangSpeed800Kbps +class NeoEspBitBangSpeed800Kbps : public NeoEspBitBangBase { public: - static void send_pixels(uint8_t* pixels, uint8_t* end, uint8_t pin) - { - bitbang_send_pixels_800(pixels, end, pin); - } static const uint32_t ResetTimeUs = 50; }; -class NeoEspBitBangSpeed400Kbps +class NeoEspBitBangSpeed400Kbps : public NeoEspBitBangBase { public: - static void send_pixels(uint8_t* pixels, uint8_t* end, uint8_t pin) - { - bitbang_send_pixels_400(pixels, end, pin); - } static const uint32_t ResetTimeUs = 50; }; -template class NeoEspBitBangMethodBase + +class NeoEspBitBangInvertedSpeedWs2812x : public NeoEspBitBangBase +{ +public: + static const uint32_t ResetTimeUs = 300; +}; + +class NeoEspBitBangInvertedSpeedSk6812 : public NeoEspBitBangBase +{ +public: + static const uint32_t ResetTimeUs = 80; +}; + +class NeoEspBitBangInvertedSpeed800Kbps : public NeoEspBitBangBase +{ +public: + static const uint32_t ResetTimeUs = 50; +}; + +class NeoEspBitBangInvertedSpeed400Kbps : public NeoEspBitBangBase +{ +public: + static const uint32_t ResetTimeUs = 50; +}; + +template class NeoEspBitBangMethodBase { public: NeoEspBitBangMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize) : @@ -108,7 +245,7 @@ public: void Initialize() { - digitalWrite(_pin, LOW); + digitalWrite(_pin, T_PINSET::IdleLevel); _endTime = micros(); } @@ -168,27 +305,47 @@ private: #if defined(ARDUINO_ARCH_ESP32) -typedef NeoEspBitBangMethodBase NeoEsp32BitBangWs2812xMethod; -typedef NeoEspBitBangMethodBase NeoEsp32BitBangSk6812Method; -typedef NeoEspBitBangMethodBase NeoEsp32BitBang800KbpsMethod; -typedef NeoEspBitBangMethodBase NeoEsp32BitBang400KbpsMethod; +typedef NeoEspBitBangMethodBase NeoEsp32BitBangWs2812xMethod; +typedef NeoEspBitBangMethodBase NeoEsp32BitBangSk6812Method; +typedef NeoEspBitBangMethodBase NeoEsp32BitBang800KbpsMethod; +typedef NeoEspBitBangMethodBase NeoEsp32BitBang400KbpsMethod; typedef NeoEsp32BitBangWs2812xMethod NeoEsp32BitBangWs2813Method; typedef NeoEsp32BitBang800KbpsMethod NeoEsp32BitBangWs2812Method; typedef NeoEsp32BitBangSk6812Method NeoEsp32BitBangLc8812Method; typedef NeoEsp32BitBang400KbpsMethod NeoEsp32BitBangApa106Method; +typedef NeoEspBitBangMethodBase NeoEsp32BitBangWs2812xInvertedMethod; +typedef NeoEspBitBangMethodBase NeoEsp32BitBangSk6812InvertedMethod; +typedef NeoEspBitBangMethodBase NeoEsp32BitBang800KbpsInvertedMethod; +typedef NeoEspBitBangMethodBase NeoEsp32BitBang400KbpsInvertedMethod; + +typedef NeoEsp32BitBangWs2812xInvertedMethod NeoEsp32BitBangWs2813InvertedMethod; +typedef NeoEsp32BitBang800KbpsInvertedMethod NeoEsp32BitBangWs2812InvertedMethod; +typedef NeoEsp32BitBangSk6812InvertedMethod NeoEsp32BitBangLc8812InvertedMethod; +typedef NeoEsp32BitBang400KbpsInvertedMethod NeoEsp32BitBangApa106InvertedMethod; + #else -typedef NeoEspBitBangMethodBase NeoEsp8266BitBangWs2812xMethod; -typedef NeoEspBitBangMethodBase NeoEsp8266BitBangSk6812Method; -typedef NeoEspBitBangMethodBase NeoEsp8266BitBang800KbpsMethod; -typedef NeoEspBitBangMethodBase NeoEsp8266BitBang400KbpsMethod; +typedef NeoEspBitBangMethodBase NeoEsp8266BitBangWs2812xMethod; +typedef NeoEspBitBangMethodBase NeoEsp8266BitBangSk6812Method; +typedef NeoEspBitBangMethodBase NeoEsp8266BitBang800KbpsMethod; +typedef NeoEspBitBangMethodBase NeoEsp8266BitBang400KbpsMethod; typedef NeoEsp8266BitBangWs2812xMethod NeoEsp8266BitBangWs2813Method; typedef NeoEsp8266BitBang800KbpsMethod NeoEsp8266BitBangWs2812Method; typedef NeoEsp8266BitBangSk6812Method NeoEsp8266BitBangLc8812Method; typedef NeoEsp8266BitBang400KbpsMethod NeoEsp8266BitBangApa106Method; + +typedef NeoEspBitBangMethodBase NeoEsp8266BitBangWs2812xInvertedMethod; +typedef NeoEspBitBangMethodBase NeoEsp8266BitBangSk6812InvertedMethod; +typedef NeoEspBitBangMethodBase NeoEsp8266BitBang800KbpsInvertedMethod; +typedef NeoEspBitBangMethodBase NeoEsp8266BitBang400KbpsInvertedMethod; + +typedef NeoEsp8266BitBangWs2812xInvertedMethod NeoEsp8266BitBangWs2813InvertedMethod; +typedef NeoEsp8266BitBang800KbpsInvertedMethod NeoEsp8266BitBangWs2812InvertedMethod; +typedef NeoEsp8266BitBangSk6812InvertedMethod NeoEsp8266BitBangLc8812InvertedMethod; +typedef NeoEsp8266BitBang400KbpsInvertedMethod NeoEsp8266BitBangApa106InvertedMethod; #endif // ESP bitbang doesn't have defaults and should avoided except for testing diff --git a/src/internal/NeoPixelEsp.c b/src/internal/NeoPixelEsp.c deleted file mode 100644 index 0837073..0000000 --- a/src/internal/NeoPixelEsp.c +++ /dev/null @@ -1,170 +0,0 @@ -/*------------------------------------------------------------------------- -NeoPixel library helper functions for Esp8266 and Esp32. - -Written by Michael C. Miller. - -I invest time and resources providing this open source code, -please support me by dontating (see https://github.com/Makuna/NeoPixelBus) - -------------------------------------------------------------------------- -This file is part of the Makuna/NeoPixelBus library. - -NeoPixelBus is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as -published by the Free Software Foundation, either version 3 of -the License, or (at your option) any later version. - -NeoPixelBus is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with NeoPixel. If not, see -. --------------------------------------------------------------------------*/ - -#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) - -#include -#if defined(ARDUINO_ARCH_ESP8266) -#include -#endif - -// ESP32 doesn't define ICACHE_RAM_ATTR -#ifndef ICACHE_RAM_ATTR -#define ICACHE_RAM_ATTR IRAM_ATTR -#endif - -static uint32_t _getCycleCount(void) __attribute__((always_inline)); - -static inline uint32_t _getCycleCount(void) -{ - uint32_t ccount; - __asm__ __volatile__("rsr %0,ccount":"=a" (ccount)); - return ccount; -} - -#define CYCLES_LOOPTEST (4) // adjustment due to loop exit test instruction cycles -#define CYCLES_800_T0H (F_CPU / 2500000 - CYCLES_LOOPTEST) // 0.4us -#define CYCLES_800_T1H (F_CPU / 1250000 - CYCLES_LOOPTEST) // 0.8us -#define CYCLES_800 (F_CPU / 800000 - CYCLES_LOOPTEST) // 1.25us per bit -#define CYCLES_400_T0H (F_CPU / 2000000 - CYCLES_LOOPTEST) -#define CYCLES_400_T1H (F_CPU / 833333 - CYCLES_LOOPTEST) -#define CYCLES_400 (F_CPU / 400000 - CYCLES_LOOPTEST) - -void ICACHE_RAM_ATTR bitbang_send_pixels_800(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 = CYCLES_800_T0H; - if (subpix & mask) - { - cyclesBit = CYCLES_800_T1H; - } - - // after we have done as much work as needed for this next bit - // now wait for the HIGH - while (((cyclesStart = _getCycleCount()) - cyclesNext) < CYCLES_800); - - // set high -#if defined(ARDUINO_ARCH_ESP32) - GPIO.out_w1ts = pinRegister; -#else - GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinRegister); -#endif - - // wait for the LOW - while ((_getCycleCount() - cyclesStart) < cyclesBit); - - // set low -#if defined(ARDUINO_ARCH_ESP32) - GPIO.out_w1tc = pinRegister; -#else - GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinRegister); -#endif - 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++; - } - } -} - -void ICACHE_RAM_ATTR bitbang_send_pixels_400(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 = CYCLES_400_T0H; - if (subpix & mask) - { - cyclesBit = CYCLES_400_T1H; - } - - // after we have done as much work as needed for this next bit - // now wait for the HIGH - while (((cyclesStart = _getCycleCount()) - cyclesNext) < CYCLES_400); - - // set high -#if defined(ARDUINO_ARCH_ESP32) - GPIO.out_w1ts = pinRegister; -#else - GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinRegister); -#endif - - // wait for the LOW - while ((_getCycleCount() - cyclesStart) < cyclesBit); - - // set low -#if defined(ARDUINO_ARCH_ESP32) - GPIO.out_w1tc = pinRegister; -#else - GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinRegister); -#endif - 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