From 6a33cbf71016c544d4e123b24b7fa4edd13ad994 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Sun, 9 Apr 2017 14:22:07 -0700 Subject: [PATCH] Initial support for Ws2813 (#170) --- keywords.txt | 7 +++ src/internal/NeoArmMethod.h | 89 ++++++++++++++++++++++++++--- src/internal/NeoAvrMethod.h | 20 ++++++- src/internal/NeoEsp8266DmaMethod.h | 14 ++++- src/internal/NeoEsp8266UartMethod.h | 16 +++++- src/internal/NeoEspBitBangMethod.h | 17 +++++- 6 files changed, 150 insertions(+), 13 deletions(-) diff --git a/keywords.txt b/keywords.txt index 0016e15..75771ef 100644 --- a/keywords.txt +++ b/keywords.txt @@ -20,18 +20,25 @@ NeoBrgFeature KEYWORD1 NeoRbgFeature KEYWORD1 DotStarBgrFeature KEYWORD1 DotStarLbgrFeature KEYWORD1 +NeoWs2813Method KEYWORD1 Neo800KbpsMethod KEYWORD1 Neo400KbpsMethod KEYWORD1 +NeoAvrWs2813Method KEYWORD1 NeoAvr800KbpsMethod KEYWORD1 NeoAvr400KbpsMethod KEYWORD1 +NeoEsp8266DmaWs2813Method KEYWORD1 NeoEsp8266Dma800KbpsMethod KEYWORD1 NeoEsp8266Dma400KbpsMethod KEYWORD1 +NeoEsp8266UartWs2813Method KEYWORD1 NeoEsp8266Uart800KbpsMethod KEYWORD1 NeoEsp8266Uart400KbpsMethod KEYWORD1 +NeoEsp8266AsyncUartWs2813Method KEYWORD1 NeoEsp8266AsyncUart800KbpsMethod KEYWORD1 NeoEsp8266AsyncUart400KbpsMethod KEYWORD1 +NeoEsp8266BitBangWs2813Method KEYWORD1 NeoEsp8266BitBang800KbpsMethod KEYWORD1 NeoEsp8266BitBang400KbpsMethod KEYWORD1 +NeoEsp32BitBangWs2813Method KEYWORD1 NeoEsp32BitBang800KbpsMethod KEYWORD1 NeoEsp32BitBang400KbpsMethod KEYWORD1 DotStarMethod KEYWORD1 diff --git a/src/internal/NeoArmMethod.h b/src/internal/NeoArmMethod.h index 08cb52e..34b42a8 100644 --- a/src/internal/NeoArmMethod.h +++ b/src/internal/NeoArmMethod.h @@ -56,7 +56,7 @@ public: { uint32_t delta = micros() - _endTime; - return (delta >= 50L); + return (delta >= T_SPEED::ResetTimeUs); } void Initialize() @@ -109,12 +109,22 @@ private: #if defined(__MK20DX128__) || defined(__MK20DX256__) // Teensy 3.0 & 3.1 +class NeoArmMk20dxSpeedPropsWs2813 +{ +public: + static const uint32_t CyclesT0h = (F_CPU / 4000000); + static const uint32_t CyclesT1h = (F_CPU / 1250000); + static const uint32_t Cycles = (F_CPU / 800000); + static const uint32_t ResetTimeUs = 250; +}; + class NeoArmMk20dxSpeedProps800Kbps { public: static const uint32_t CyclesT0h = (F_CPU / 4000000); static const uint32_t CyclesT1h = (F_CPU / 1250000); static const uint32_t Cycles = (F_CPU / 800000); + static const uint32_t ResetTimeUs = 50; }; class NeoArmMk20dxSpeedProps400Kbps @@ -123,11 +133,14 @@ public: static const uint32_t CyclesT0h = (F_CPU / 2000000); static const uint32_t CyclesT1h = (F_CPU / 833333); static const uint32_t Cycles = (F_CPU / 400000); + static const uint32_t ResetTimeUs = 50; }; template class NeoArmMk20dxSpeedBase { public: + static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs; + static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin) { uint8_t* p = pixels; @@ -167,6 +180,7 @@ public: } }; +typedef NeoArmMethodBase> NeoArmWs2813Method; typedef NeoArmMethodBase> NeoArm800KbpsMethod; typedef NeoArmMethodBase> NeoArm400KbpsMethod; @@ -176,7 +190,7 @@ typedef NeoArmMethodBase> N -class NeoArmMk26z64Speed800Kbps +class NeoArmMk26z64Speed800KbpsBase { public: static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin) @@ -266,6 +280,19 @@ public: } }; +class NeoArmMk26z64SpeedWs2813 : public NeoArmMk26z64Speed800KbpsBase +{ +public: + const static uint32_t ResetTimeUs = 250; +}; + +class NeoArmMk26z64Speed800Kbps : public NeoArmMk26z64Speed800KbpsBase +{ +public: + const static uint32_t ResetTimeUs = 50; +} + +typedef NeoArmMethodBase NeoArmWs2813Method; typedef NeoArmMethodBase NeoArm800KbpsMethod; #else @@ -275,7 +302,7 @@ typedef NeoArmMethodBase NeoArm800KbpsMethod; #elif defined(__SAMD21G18A__) // Arduino Zero -class NeoArmSamd21g18aSpeedProps800Kbps +class NeoArmSamd21g18aSpeedProps800KbpsBase { public: static void BitPreWait() @@ -300,6 +327,19 @@ public: } }; +class NeoArmSamd21g18aSpeedPropsWs2813 : public NeoArmSamd21g18aSpeedProps800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 250; +}; + +class NeoArmSamd21g18aSpeedProps800Kbps : public NeoArmSamd21g18aSpeedProps800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 50; +}; + + class NeoArmSamd21g18aSpeedProps400Kbps { public: @@ -325,11 +365,14 @@ public: { asm("nop; nop; nop; nop; nop; nop; nop;"); } + static const uint32_t ResetTimeUs = 50; }; template class NeoArmSamd21g18aSpeedBase { public: + static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs; + static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin) { // Tried this with a timer/counter, couldn't quite get adequate @@ -376,15 +419,15 @@ public: } }; +typedef NeoArmMethodBase> NeoArmWs2813Method; typedef NeoArmMethodBase> NeoArm800KbpsMethod; typedef NeoArmMethodBase> NeoArm400KbpsMethod; #elif defined (ARDUINO_STM32_FEATHER) // FEATHER WICED (120MHz) - - -class NeoArmStm32SpeedProps800Kbps +class NeoArmStm32SpeedProps800KbpsBase { +public: static void BitT1hWait() { asm("nop; nop; nop; nop; nop; nop; nop; nop;" @@ -432,9 +475,20 @@ class NeoArmStm32SpeedProps800Kbps "nop; nop; nop; nop; nop; nop; nop; nop;" "nop; nop; nop; nop;"); } - - }; + +class NeoArmStm32SpeedProps800Kbps : public NeoArmStm32SpeedProps800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 50; +}; + +class NeoArmStm32SpeedPropsWs2813 : public NeoArmStm32SpeedProps800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 250; +}; + /* TODO - not found in Adafruit library class NeoArmStm32SpeedProps400Kbps { @@ -455,6 +509,9 @@ static void BitT0lWait() template class NeoArmStm32SpeedBase { +public: + static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs; + static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin) { // Tried this with a timer/counter, couldn't quite get adequate @@ -510,6 +567,7 @@ template class NeoArmStm32SpeedBase } }; +typedef NeoArmMethodBase> NeoArmWs2813Method; typedef NeoArmMethodBase> NeoArm800KbpsMethod; #else // Other ARM architecture -- Presumed Arduino Due @@ -518,12 +576,22 @@ typedef NeoArmMethodBase> Neo #define ARM_OTHER_SCALE VARIANT_MCK / 2UL / 1000000UL #define ARM_OTHER_INST (2UL * F_CPU / VARIANT_MCK) +class NeoArmOtherSpeedPropsWs2813 +{ +public: + static const uint32_t CyclesT0h = ((uint32_t)(0.40 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST)); + static const uint32_t CyclesT1h = ((uint32_t)(0.80 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST)); + static const uint32_t Cycles = ((uint32_t)(1.25 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST)); + static const uint32_t ResetTimeUs = 250; +}; + class NeoArmOtherSpeedProps800Kbps { public: static const uint32_t CyclesT0h = ((uint32_t)(0.40 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST)); static const uint32_t CyclesT1h = ((uint32_t)(0.80 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST)); static const uint32_t Cycles = ((uint32_t)(1.25 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST)); + static const uint32_t ResetTimeUs = 50; }; class NeoArmOtherSpeedProps400Kbps @@ -532,11 +600,14 @@ public: static const uint32_t CyclesT0h = ((uint32_t)(0.50 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST)); static const uint32_t CyclesT1h = ((uint32_t)(1.20 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST)); static const uint32_t Cycles = ((uint32_t)(2.50 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST)); + static const uint32_t ResetTimeUs = 50; }; template class NeoArmOtherSpeedBase { public: + static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs; + static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin) { uint32_t pinMask; @@ -608,6 +679,7 @@ public: } }; +typedef NeoArmMethodBase> NeoArmWs2813Method; typedef NeoArmMethodBase> NeoArm800KbpsMethod; typedef NeoArmMethodBase> NeoArm400KbpsMethod; @@ -615,6 +687,7 @@ typedef NeoArmMethodBase> Neo // Arm doesn't have alternatives methods yet, so only one to make the default +typedef NeoArmWs2813Method NeoWs2813Method; typedef NeoArm800KbpsMethod Neo800KbpsMethod; #ifdef NeoArm400KbpsMethod // this is needed due to missing 400Kbps for some platforms typedef NeoArm400KbpsMethod Neo400KbpsMethod; diff --git a/src/internal/NeoAvrMethod.h b/src/internal/NeoAvrMethod.h index 408e881..9843816 100644 --- a/src/internal/NeoAvrMethod.h +++ b/src/internal/NeoAvrMethod.h @@ -41,7 +41,7 @@ extern "C" void send_pixels_16mhz_400(uint8_t* pixels, size_t sizePixels, volatile uint8_t* port, uint8_t pinMask); } -class NeoAvrSpeed800Kbps +class NeoAvrSpeed800KbpsBase { public: static void send_pixels(uint8_t* pixels, size_t sizePixels, volatile uint8_t* port, uint8_t pinMask) @@ -68,6 +68,19 @@ public: #error "CPU SPEED NOT SUPPORTED" #endif } + +}; + +class NeoAvrSpeedWs2813 : public NeoAvrSpeed800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 250; +}; + +class NeoAvrSpeed800Kbps: public NeoAvrSpeed800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 50; }; class NeoAvrSpeed400Kbps @@ -87,6 +100,7 @@ public: #error "CPU SPEED NOT SUPPORTED" #endif } + static const uint32_t ResetTimeUs = 50; }; template class NeoAvrMethodBase @@ -118,7 +132,7 @@ public: { uint32_t delta = micros() - _endTime; - return (delta >= 50L); + return (delta >= T_SPEED::ResetTimeUs); } void Initialize() @@ -173,10 +187,12 @@ private: uint8_t _pinMask; // Output PORT bitmask }; +typedef NeoAvrMethodBase NeoAvrWs2813Method; typedef NeoAvrMethodBase NeoAvr800KbpsMethod; typedef NeoAvrMethodBase NeoAvr400KbpsMethod; // AVR doesn't have alternatives yet, so there is just the default +typedef NeoAvrWs2813Method NeoWs2813Method; typedef NeoAvr800KbpsMethod Neo800KbpsMethod; typedef NeoAvr400KbpsMethod Neo400KbpsMethod; diff --git a/src/internal/NeoEsp8266DmaMethod.h b/src/internal/NeoEsp8266DmaMethod.h index d11cc2b..af11e1a 100644 --- a/src/internal/NeoEsp8266DmaMethod.h +++ b/src/internal/NeoEsp8266DmaMethod.h @@ -63,12 +63,20 @@ struct slc_queue_item uint32 next_link_ptr; }; +class NeoEsp8266DmaSpeedWs2813 +{ +public: + const static uint32_t I2sClockDivisor = 3; + const static uint32_t I2sBaseClockDivisor = 16; + const static uint32_t ResetTimeUs = 250; +}; class NeoEsp8266DmaSpeed800Kbps { public: const static uint32_t I2sClockDivisor = 3; const static uint32_t I2sBaseClockDivisor = 16; + const static uint32_t ResetTimeUs = 50; }; class NeoEsp8266DmaSpeed400Kbps @@ -76,6 +84,7 @@ class NeoEsp8266DmaSpeed400Kbps public: const static uint32_t I2sClockDivisor = 6; const static uint32_t I2sBaseClockDivisor = 16; + const static uint32_t ResetTimeUs = 50; }; enum NeoDmaState @@ -268,7 +277,8 @@ private: // normally 24 bytes creates the minimum 50us latch per spec, but // with the new logic, this latch is used to space between three states - uint8_t _i2sZeroes[8]; + // buffer size = (24 * (speed / 50)) / 3 + uint8_t _i2sZeroes[(24L * (T_SPEED::ResetTimeUs / 50L)) / 3L]; slc_queue_item* _i2sBufDesc; // dma block descriptors uint16_t _i2sBufDescCount; // count of block descriptors in _i2sBufDesc @@ -360,10 +370,12 @@ private: template NeoEsp8266DmaMethodBase* NeoEsp8266DmaMethodBase::s_this; +typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaWs2813Method; typedef NeoEsp8266DmaMethodBase NeoEsp8266Dma800KbpsMethod; typedef NeoEsp8266DmaMethodBase NeoEsp8266Dma400KbpsMethod; // Dma method is the default method for Esp8266 +typedef NeoEsp8266DmaWs2813Method NeoWs2813Method; typedef NeoEsp8266Dma800KbpsMethod Neo800KbpsMethod; typedef NeoEsp8266Dma400KbpsMethod Neo400KbpsMethod; diff --git a/src/internal/NeoEsp8266UartMethod.h b/src/internal/NeoEsp8266UartMethod.h index c14b9b0..a92d566 100644 --- a/src/internal/NeoEsp8266UartMethod.h +++ b/src/internal/NeoEsp8266UartMethod.h @@ -75,12 +75,22 @@ private: uint8_t* _asyncPixels; // Holds a copy of LED color values taken when UpdateUart began }; +// NeoEsp8266UartSpeedWs2813 contains the timing constants used to get NeoPixelBus running with the Ws2813 +class NeoEsp8266UartSpeedWs2813 +{ +public: + static const uint32_t ByteSendTimeUs = 10; // us it takes to send a single pixel element at 800khz speed + static const uint32_t UartBaud = 3200000; // 800mhz, 4 serial bytes per NeoByte + static const uint32_t ResetTimeUs = 250; // us between data send bursts to reset for next update +}; + // NeoEsp8266UartSpeed800Kbps contains the timing constant used to get NeoPixelBus running at 800Khz class NeoEsp8266UartSpeed800Kbps { public: static const uint32_t ByteSendTimeUs = 10; // us it takes to send a single pixel element at 800khz speed static const uint32_t UartBaud = 3200000; // 800mhz, 4 serial bytes per NeoByte + static const uint32_t ResetTimeUs = 50; // us between data send bursts to reset for next update }; // NeoEsp8266UartSpeed800Kbps contains the timing constant used to get NeoPixelBus running at 400Khz @@ -89,6 +99,7 @@ class NeoEsp8266UartSpeed400Kbps public: static const uint32_t ByteSendTimeUs = 20; // us it takes to send a single pixel element at 400khz speed static const uint32_t UartBaud = 1600000; // 400mhz, 4 serial bytes per NeoByte + static const uint32_t ResetTimeUs = 50; // us between data send bursts to reset for next update }; // NeoEsp8266UartMethodBase is a light shell arround NeoEsp8266Uart or NeoEsp8266AsyncUart that @@ -109,7 +120,7 @@ public: bool IsReadyToUpdate() const { uint32_t delta = micros() - this->_startTime; - return delta >= getPixelTime() + 50; + return delta >= getPixelTime() + T_SPEED::ResetTimeUs; } void Initialize() @@ -155,8 +166,11 @@ private: }; }; +typedef NeoEsp8266UartMethodBase NeoEsp8266UartWs2813Method; typedef NeoEsp8266UartMethodBase NeoEsp8266Uart800KbpsMethod; typedef NeoEsp8266UartMethodBase NeoEsp8266Uart400KbpsMethod; + +typedef NeoEsp8266UartMethodBase NeoEsp8266AsyncUartWs2813Method; typedef NeoEsp8266UartMethodBase NeoEsp8266AsyncUart800KbpsMethod; typedef NeoEsp8266UartMethodBase NeoEsp8266AsyncUart400KbpsMethod; diff --git a/src/internal/NeoEspBitBangMethod.h b/src/internal/NeoEspBitBangMethod.h index 6f5a8a8..499f1c3 100644 --- a/src/internal/NeoEspBitBangMethod.h +++ b/src/internal/NeoEspBitBangMethod.h @@ -39,6 +39,16 @@ License along with NeoPixel. If not, see 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); +class NeoEspBitBangSpeedWs2813 +{ +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 = 250; +}; + class NeoEspBitBangSpeed800Kbps { public: @@ -46,6 +56,7 @@ public: { bitbang_send_pixels_800(pixels, end, pin); } + static const uint32_t ResetTimeUs = 50; }; class NeoEspBitBangSpeed400Kbps @@ -55,6 +66,7 @@ public: { bitbang_send_pixels_400(pixels, end, pin); } + static const uint32_t ResetTimeUs = 50; }; template class NeoEspBitBangMethodBase @@ -81,7 +93,7 @@ public: { uint32_t delta = micros() - _endTime; - return (delta >= 50L); + return (delta >= T_SPEED::ResetTimeUs); } void Initialize() @@ -134,15 +146,18 @@ private: #if defined(ARDUINO_ARCH_ESP32) +typedef NeoEspBitBangMethodBase NeoEsp32BitBangWs2813Method; typedef NeoEspBitBangMethodBase NeoEsp32BitBang800KbpsMethod; typedef NeoEspBitBangMethodBase NeoEsp32BitBang400KbpsMethod; // Bitbang method is the default method for Esp32 +typedef NeoEsp32BitBangWs2813Method NeoWs2813Method; typedef NeoEsp32BitBang800KbpsMethod Neo800KbpsMethod; typedef NeoEsp32BitBang400KbpsMethod Neo400KbpsMethod; #else +typedef NeoEspBitBangMethodBase NeoEsp8266BitBangWs2813Method; typedef NeoEspBitBangMethodBase NeoEsp8266BitBang800KbpsMethod; typedef NeoEspBitBangMethodBase NeoEsp8266BitBang400KbpsMethod;