diff --git a/NeoPixelBus.cpp b/NeoPixelBus.cpp index 1bba22f..a244c8d 100644 --- a/NeoPixelBus.cpp +++ b/NeoPixelBus.cpp @@ -32,12 +32,31 @@ License along with NeoPixel. If not, see #include "NeoPixelBus.h" #if defined(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 -extern "C" void ICACHE_RAM_ATTR send_pixels_800(uint8_t* pixels, uint8_t* end, uint8_t pin); -extern "C" void ICACHE_RAM_ATTR send_pixels_400(uint8_t* pixels, uint8_t* end, uint8_t pin); + + #ifdef ESPUARTWS2812 + extern "C" { + #include "eagle_soc.h" + #include "uart_register.h" + #include + } + #define UART_INV_MASK (0x3f<<19) + #define UART 1 + + extern void ICACHE_RAM_ATTR send_pixels_UART(uint8_t* pixels, uint8_t* end, bool force); + + #else + // 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 + extern "C" void ICACHE_RAM_ATTR send_pixels_800(uint8_t* pixels, uint8_t* end, uint8_t pin); + extern "C" void ICACHE_RAM_ATTR send_pixels_400(uint8_t* pixels, uint8_t* end, uint8_t pin); + + #endif + #endif + + + NeoPixelBus::NeoPixelBus(uint16_t n, uint8_t p, uint8_t t) : _countPixels(n), _sizePixels(n * 3), @@ -46,7 +65,11 @@ NeoPixelBus::NeoPixelBus(uint16_t n, uint8_t p, uint8_t t) : _activeAnimations(0), _flagsPixels(t) { + +#ifndef ESPUARTWS2812 setPin(p); +#endif + _pixels = (uint8_t *)malloc(_sizePixels); if (_pixels) @@ -69,17 +92,58 @@ NeoPixelBus::~NeoPixelBus() if (_animations) free(_animations); +#ifndef ESPUARTWS2812 pinMode(_pin, INPUT); +#endif + } -void NeoPixelBus::Begin(void) -{ - pinMode(_pin, OUTPUT); - digitalWrite(_pin, LOW); - Dirty(); +void NeoPixelBus::FillUart(void) { + + uint8_t* p = _pixels; + uint8_t* end = p + _sizePixels; + + send_pixels_UART(p, end, false); + } + + void NeoPixelBus::Begin(void) + { + +#ifdef ESPUARTWS2812 + /* Serial rate is 4x 800KHz for WS2811 */ + +#ifdef INCLUDE_NEO_KHZ400_SUPPORT + + + if ((_flagsPixels & NEO_SPDMASK) == NEO_KHZ800) + { + // 800 Support + Serial1.begin(3200000, SERIAL_6N1, SERIAL_TX_ONLY); + } else { + // 400 Support + Serial1.begin(1600000, SERIAL_6N1, SERIAL_TX_ONLY); + } + +#else + + Serial1.begin(3200000, SERIAL_6N1, SERIAL_TX_ONLY); + +#endif + + CLEAR_PERI_REG_MASK(UART_CONF0(UART), UART_INV_MASK); + //SET_PERI_REG_MASK(UART_CONF0(UART), UART_TXD_INV); + SET_PERI_REG_MASK(UART_CONF0(UART), (BIT(22))); +#else + pinMode(_pin, OUTPUT); + digitalWrite(_pin, LOW); +#endif + Dirty(); + } + + void NeoPixelBus::Show(void) { if (!_pixels) @@ -111,7 +175,9 @@ void NeoPixelBus::Show(void) // state, computes 'pin high' and 'pin low' values, and writes these back // to the PORT register as needed. +#ifndef ESPUARTWS2812 noInterrupts(); // Need 100% focus on instruction timing +#endif #ifdef __AVR__ @@ -724,15 +790,55 @@ void NeoPixelBus::Show(void) if ((_flagsPixels & NEO_SPDMASK) == NEO_KHZ800) { #endif + +#ifndef ESPUARTWS2812 // 800 KHz bitstream send_pixels_800(p, end, _pin); +#else + + send_pixels_UART(p, end, true); + + // char buff[4]; + + // do + // { + // uint8_t subpix = *p++; + + // buff[0] = data[(subpix >> 6) & 3]; + // buff[1] = data[(subpix >> 4) & 3]; + // buff[2] = data[(subpix >> 2) & 3]; + // buff[3] = data[subpix & 3]; + // Serial1.write(buff, sizeof(buff)); + + // } while (p < end); + +#endif #ifdef INCLUDE_NEO_KHZ400_SUPPORT } else { - // 400 kHz bitstream + +#ifndef ESPUARTWS2812 + // 800 KHz bitstream send_pixels_400(p, end, _pin); +#else + + char buff[4]; + + do + { + uint8_t subpix = *p++; + + buff[0] = data[(subpix >> 6) & 3]; + buff[1] = data[(subpix >> 4) & 3]; + buff[2] = data[(subpix >> 2) & 3]; + buff[3] = data[subpix & 3]; + Serial1.write(buff, sizeof(buff)); + + } while (p < end); + +#endif } #endif @@ -973,7 +1079,10 @@ void NeoPixelBus::Show(void) #endif // end Architecture select +#ifndef ESPUARTWS2812 interrupts(); +#endif + ResetDirty(); _endTime = micros(); // Save EOD time for latch on next call } diff --git a/NeoPixelBus.h b/NeoPixelBus.h index bbb778a..f0b2f79 100644 --- a/NeoPixelBus.h +++ b/NeoPixelBus.h @@ -20,6 +20,8 @@ License along with NeoPixel. If not, see #include #include "RgbColor.h" +#define ESPUARTWS2812 // drive neopixels by UART on GPIO2 on ESP8266 thanks to Forkineye. https://github.com/forkineye/ESPixelStick + // '_flagsPixels' flags for LED _pixels (third parameter to constructor): #define NEO_RGB 0x00 // Wired for RGB data order #define NEO_GRB 0x01 // Wired for GRB data order @@ -35,6 +37,7 @@ License along with NeoPixel. If not, see // NeoPixelBus library include to support the slower bus speeds //#define INCLUDE_NEO_KHZ400_SUPPORT + class NeoPixelBus { public: @@ -58,7 +61,7 @@ public: { ClearTo(c.R, c.G, c.B); } - + void FillUart(); bool IsDirty() { return (_flagsPixels & NEO_DIRTY); @@ -120,6 +123,12 @@ private: uint8_t _pinMask; // Output PORT bitmask #endif +#ifdef ESPUARTWS2812 + /* 6 bit UART lookup table, first 2 bits ignored. Start and stop bits are part of the pixel stream. */ +const char data[4] = { 0b00110111, 0b00000111, 0b00110100, 0b00000100 }; +#endif + + struct FadeAnimation { uint16_t time; diff --git a/NeoPixelesp8266.c b/NeoPixelesp8266.c index 3766067..4a2cbae 100644 --- a/NeoPixelesp8266.c +++ b/NeoPixelesp8266.c @@ -36,6 +36,12 @@ inline uint32_t _getCycleCount() #define CYCLES_400_T1H (F_CPU / 833333) #define CYCLES_400 (F_CPU / 400000) + +#include "eagle_soc.h" +#include "uart_register.h" + + + void ICACHE_RAM_ATTR send_pixels_800(uint8_t* pixels, uint8_t* end, uint8_t pin) { const uint32_t pinRegister = _BV(pin); diff --git a/NeoPixelesp8266uart.cpp b/NeoPixelesp8266uart.cpp new file mode 100644 index 0000000..038478a --- /dev/null +++ b/NeoPixelesp8266uart.cpp @@ -0,0 +1,64 @@ +/* +NeoPixelEsp8266.h - NeoPixel library helper functions for Esp8266 using cycle count +Copyright (c) 2015 Michael C. Miller. All right reserved. + +This library 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 2.1 of the License, or (at your option) any later version. + +This library 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 this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include "uart_register.h" + + +#if defined(ESP8266) + + +#define UART_INV_MASK (0x3f<<19) +#define UART 1 + + +const char data[4] = { 0b00110111, 0b00000111, 0b00110100, 0b00000100 }; + +void ICACHE_RAM_ATTR send_pixels_UART(uint8_t* pixels, uint8_t* end, bool force) +{ + char buff[4]; + //uint8_t count = 0; + // static uint8_t* position = NULL; + + + // if (position != NULL && !force ) { + // pixels = position; + // } else if (position == NULL && !force ) { + // return; + // } + + do + { + uint8_t subpix = *pixels++; + // position = pixels; + // count++; + buff[0] = data[(subpix >> 6) & 3]; + buff[1] = data[(subpix >> 4) & 3]; + buff[2] = data[(subpix >> 2) & 3]; + buff[3] = data[subpix & 3]; + Serial1.write(buff, sizeof(buff)); + + } while (pixels < end ); + + // if ( pixels == end) { position = NULL; } + +} + +#endif \ No newline at end of file diff --git a/examples/NeoPixelFun/NeoPixelFun.pde b/examples/NeoPixelFun/NeoPixelFun.pde index b97ec40..89a2afe 100644 --- a/examples/NeoPixelFun/NeoPixelFun.pde +++ b/examples/NeoPixelFun/NeoPixelFun.pde @@ -1,8 +1,8 @@ #include -#define pixelCount 4 +#define pixelCount 300 -NeoPixelBus strip = NeoPixelBus(pixelCount, 8); +NeoPixelBus strip = NeoPixelBus(pixelCount, 2); uint16_t effectState = 0; @@ -13,6 +13,7 @@ void setup() SetRandomSeed(); } +uint32_t update_strip_time; void loop() { @@ -33,6 +34,18 @@ void loop() strip.Show(); delay(31); // ~30hz change cycle } + + if ( (millis() - update_strip_time > 30) ) { + + strip.UpdateAnimations(); + + strip.Show(); // takes 6ms with 200, take 12ms with 400 ----> so 100 takes 3ms. + // one LED takes 30uS of nointeruppts, 100 takes 3ms. + update_strip_time = millis(); + + } + + strip.FillUart(); }