diff --git a/src/NeoPixelBus.h b/src/NeoPixelBus.h index 708a37d..f514430 100644 --- a/src/NeoPixelBus.h +++ b/src/NeoPixelBus.h @@ -42,6 +42,26 @@ const uint16_t PixelIndex_OutOfBounds = 0xffff; #include "internal/NeoBusChannel.h" #include "internal/NeoMethods.h" + +struct BusView +{ + BusView(uint16_t stripCount) : + PixelCount(stripCount), + StripCount(stripCount) + { + } + + BusView(uint16_t repeatedPixelsCount, + uint16_t stripCount ) : + PixelCount(repeatedPixelsCount), + StripCount(stripCount) + { + } + + const uint16_t PixelCount; // exposed count of pixels that will be repeated to fill strip + const uint16_t StripCount; // actual data stream count of pixels +}; + // T_COLOR_FEATURE - // The color feature object that defines bit depth, order, and any settings related // to them @@ -61,57 +81,61 @@ template(_pixels, _countPixels); } + void Begin() { _method.Initialize(); @@ -331,7 +356,11 @@ protected: void _initialize() { +#if defined(NEOPIXEBUS_NO_ARRAY_NEW) + _pixels = static_cast(malloc(_countPixels * sizeof(T_EXPOSED_COLOR_OBJECT))); +#else _pixels = new T_EXPOSED_COLOR_OBJECT[_countPixels]; +#endif ClearTo(0); } diff --git a/src/NeoPixelBusLg.h b/src/NeoPixelBusLg.h index d39c7e9..a6b1bb6 100644 --- a/src/NeoPixelBusLg.h +++ b/src/NeoPixelBusLg.h @@ -97,51 +97,51 @@ class NeoPixelBusLg : LuminanceShader> { public: - NeoPixelBusLg(uint16_t countPixels, uint8_t pin) : + NeoPixelBusLg(const BusView& busView, uint8_t pin) : NeoPixelBus>(countPixels, pin) + LuminanceShader>(busView, pin) { } - NeoPixelBusLg(uint16_t countPixels, uint8_t pin, NeoBusChannel channel) : + NeoPixelBusLg(const BusView& busView, uint8_t pin, NeoBusChannel channel) : NeoPixelBus>(countPixels, pin, channel) + LuminanceShader>(busView, pin, channel) { } - NeoPixelBusLg(uint16_t countPixels, uint8_t pinClock, uint8_t pinData) : + NeoPixelBusLg(const BusView& busView, uint8_t pinClock, uint8_t pinData) : NeoPixelBus>(countPixels, pinClock, pinData) + LuminanceShader>(busView, pinClock, pinData) { } - NeoPixelBusLg(uint16_t countPixels, uint8_t pinClock, uint8_t pinData, uint8_t pinLatch, uint8_t pinOutputEnable = NOT_A_PIN) : + NeoPixelBusLg(const BusView& busView, uint8_t pinClock, uint8_t pinData, uint8_t pinLatch, uint8_t pinOutputEnable = NOT_A_PIN) : NeoPixelBus>(countPixels, pinClock, pinData, pinLatch, pinOutputEnable) + LuminanceShader>(busView, pinClock, pinData, pinLatch, pinOutputEnable) { } - NeoPixelBusLg(uint16_t countPixels) : + NeoPixelBusLg(const BusView& busView) : NeoPixelBus>(countPixels) + LuminanceShader>(busView) { } - NeoPixelBusLg(uint16_t countPixels, Stream* pixieStream) : + NeoPixelBusLg(const BusView& busView, Stream* pixieStream) : NeoPixelBus>(countPixels, pixieStream) + LuminanceShader>(busView, pixieStream) { } diff --git a/src/internal/NeoUtil.h b/src/internal/NeoUtil.h index 575f9fc..9033ec9 100644 --- a/src/internal/NeoUtil.h +++ b/src/internal/NeoUtil.h @@ -32,10 +32,33 @@ License along with NeoPixel. If not, see // ...then you can either add the platform symbol to the list so NEOPIXEBUS_NO_STL gets defined or // go to boards.txt and enable c++ by adding (teensy31.build.flags.libs=-lstdc++) and set to "smallest code" option in Arduino // -#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) || defined(STM32L432xx) || defined(STM32L476xx) || defined(ARDUINO_ARCH_SAM) +#if defined(ARDUINO_ARCH_AVR) || \ + defined(ARDUINO_ARCH_MEGAAVR) || \ + defined(STM32L432xx) || \ + defined(STM32L476xx) || \ + defined(ARDUINO_ARCH_SAM) #define NEOPIXEBUS_NO_STL 1 #endif +// some platforms do not support a yield statement +#if defined(ARDUINO_TEEONARDU_LEO) || \ + defined(ARDUINO_TEEONARDU_FLORA) || \ + defined(ARDUINO_AVR_DIGISPARK) || \ + defined(ARDUINO_AVR_DIGISPARKPRO) +#define NEOPIXEBUS_NO_YIELD 1 +#endif + +// some platforms do not support String +#if defined(ARDUINO_AVR_DIGISPARK) +#define NEOPIXEBUS_NO_STRING 1 +#endif + +// some platforms do not support new []!? +#if defined(ARDUINO_AVR_DIGISPARK) || \ + defined(ARDUINO_AVR_DIGISPARKPRO) +#define NEOPIXEBUS_NO_ARRAY_NEW 1 +#endif + // some platforms do not define this standard progmem type for some reason // #ifndef PGM_VOID_P diff --git a/src/internal/colors/HsbColor.cpp b/src/internal/colors/HsbColor.cpp index b45f511..bbe81b9 100644 --- a/src/internal/colors/HsbColor.cpp +++ b/src/internal/colors/HsbColor.cpp @@ -25,6 +25,7 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #include +#include "../NeoUtil.h" #include "../NeoSettings.h" #include "RgbColorBase.h" #include "RgbColor.h" diff --git a/src/internal/colors/HslColor.cpp b/src/internal/colors/HslColor.cpp index bd6c3f4..2bb7f50 100644 --- a/src/internal/colors/HslColor.cpp +++ b/src/internal/colors/HslColor.cpp @@ -26,6 +26,7 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #include +#include "../NeoUtil.h" #include "../NeoSettings.h" #include "RgbColorBase.h" #include "RgbColor.h" diff --git a/src/internal/colors/HtmlColor.cpp b/src/internal/colors/HtmlColor.cpp index 1840e73..1031d6e 100644 --- a/src/internal/colors/HtmlColor.cpp +++ b/src/internal/colors/HtmlColor.cpp @@ -25,6 +25,7 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #include +#include "../NeoUtil.h" #include "../NeoSettings.h" #include "RgbColorBase.h" #include "RgbColor.h" diff --git a/src/internal/colors/HtmlColor.h b/src/internal/colors/HtmlColor.h index 1eecd83..8ada076 100644 --- a/src/internal/colors/HtmlColor.h +++ b/src/internal/colors/HtmlColor.h @@ -249,7 +249,7 @@ struct HtmlColor return Parse(name, MAX_HTML_COLOR_NAME_LEN + 1); } -#if !defined(ARDUINO_AVR_DIGISPARK) +#if !defined(NEOPIXEBUS_NO_STRING) template size_t Parse(String const &name) { return Parse(name.c_str(), name.length() + 1); diff --git a/src/internal/colors/Rgb48Color.cpp b/src/internal/colors/Rgb48Color.cpp index a64605c..57bcdf9 100644 --- a/src/internal/colors/Rgb48Color.cpp +++ b/src/internal/colors/Rgb48Color.cpp @@ -25,6 +25,7 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #include +#include "../NeoUtil.h" #include "../NeoSettings.h" #include "RgbColorBase.h" #include "RgbColor.h" diff --git a/src/internal/colors/RgbColor.cpp b/src/internal/colors/RgbColor.cpp index b6e7c0f..9327757 100644 --- a/src/internal/colors/RgbColor.cpp +++ b/src/internal/colors/RgbColor.cpp @@ -25,6 +25,7 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #include +#include "../NeoUtil.h" #include "../NeoSettings.h" #include "RgbColorBase.h" #include "RgbColor.h" diff --git a/src/internal/colors/RgbColorBase.cpp b/src/internal/colors/RgbColorBase.cpp index 92c43f9..3f5357e 100644 --- a/src/internal/colors/RgbColorBase.cpp +++ b/src/internal/colors/RgbColorBase.cpp @@ -25,6 +25,7 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #include +#include "../NeoUtil.h" #include "../NeoSettings.h" #include "RgbColorBase.h" #include "RgbColor.h" diff --git a/src/internal/colors/Rgbw64Color.cpp b/src/internal/colors/Rgbw64Color.cpp index c77ae33..9dd1816 100644 --- a/src/internal/colors/Rgbw64Color.cpp +++ b/src/internal/colors/Rgbw64Color.cpp @@ -25,6 +25,7 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #include +#include "../NeoUtil.h" #include "../NeoSettings.h" #include "RgbColorBase.h" #include "RgbColor.h" diff --git a/src/internal/colors/RgbwColor.cpp b/src/internal/colors/RgbwColor.cpp index 99fda1b..5da26da 100644 --- a/src/internal/colors/RgbwColor.cpp +++ b/src/internal/colors/RgbwColor.cpp @@ -25,6 +25,7 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #include +#include "../NeoUtil.h" #include "../NeoSettings.h" #include "RgbColorBase.h" #include "RgbColor.h" diff --git a/src/internal/colors/Rgbww80Color.cpp b/src/internal/colors/Rgbww80Color.cpp index bf02697..0fd7b98 100644 --- a/src/internal/colors/Rgbww80Color.cpp +++ b/src/internal/colors/Rgbww80Color.cpp @@ -26,6 +26,7 @@ License along with NeoPixel. If not, see #include +#include "../NeoUtil.h" #include "../NeoSettings.h" #include "RgbColorBase.h" #include "RgbColor.h" diff --git a/src/internal/colors/RgbwwColor.cpp b/src/internal/colors/RgbwwColor.cpp index 4903cf8..e99d278 100644 --- a/src/internal/colors/RgbwwColor.cpp +++ b/src/internal/colors/RgbwwColor.cpp @@ -25,6 +25,7 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #include +#include "../NeoUtil.h" #include "../NeoSettings.h" #include "RgbColorBase.h" #include "RgbColor.h" diff --git a/src/internal/colors/RgbwwwColor.cpp b/src/internal/colors/RgbwwwColor.cpp index 240895f..6403bfc 100644 --- a/src/internal/colors/RgbwwwColor.cpp +++ b/src/internal/colors/RgbwwwColor.cpp @@ -25,6 +25,7 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #include +#include "../NeoUtil.h" #include "../NeoSettings.h" #include "RgbColorBase.h" #include "RgbColor.h" diff --git a/src/internal/methods/NeoAvrMethod.h b/src/internal/methods/NeoAvrMethod.h index d8ab53a..3f71257 100644 --- a/src/internal/methods/NeoAvrMethod.h +++ b/src/internal/methods/NeoAvrMethod.h @@ -174,7 +174,8 @@ public: [[maybe_unused]] uint16_t pixelCount, [[maybe_unused]] size_t elementSize, [[maybe_unused]] size_t settingsSize) : - _pin(pin) + _pin(pin), + _pixelCount(pixelCount) { pinMode(pin, OUTPUT); _port = portOutputRegister(digitalPinToPort(pin)); @@ -211,7 +212,7 @@ public: { while (!IsReadyToUpdate()) { -#if !defined(ARDUINO_TEEONARDU_LEO) && !defined(ARDUINO_TEEONARDU_FLORA) && !defined(ARDUINO_AVR_DIGISPARK) +#if !defined(NEOPIXEBUS_NO_YIELD) yield(); // allows for system yield if needed #endif } @@ -222,26 +223,34 @@ public: noInterrupts(); // Need 100% focus on instruction timing // if there are settings at the front + // if (T_COLOR_FEATURE::applyFrontSettings(sendData, sendDataSize, featureSettings)) { T_SPEED::send_data(sendData, T_COLOR_FEATURE::SettingsSize, _port, _pinMask); } // send primary color data + // T_COLOR_OBJECT* pixel = pixels; - T_COLOR_OBJECT* pixelEnd = pixel + countPixels; + const T_COLOR_OBJECT* pixelEnd = pixel + countPixels; + uint16_t stripCount = _pixelCount; - while (pixel < pixelEnd) + while (--stripCount) { typename T_COLOR_FEATURE::ColorObject color = shader.Apply(*pixel); T_COLOR_FEATURE::applyPixelColor(sendData, T_COLOR_FEATURE::PixelSize, color); T_SPEED::send_data(sendData, T_COLOR_FEATURE::PixelSize, _port, _pinMask); - pixel++; + if (++pixel == pixelEnd) + { + // restart at first + pixel = pixels; + } } // if there are settings at the back + // if (T_COLOR_FEATURE::applyBackSettings(sendData, sendDataSize, featureSettings)) { T_SPEED::send_data(sendData, T_COLOR_FEATURE::SettingsSize, _port, _pinMask); @@ -259,6 +268,7 @@ public: protected: const uint8_t _pin; // output pin number + const uint16_t _pixelCount; // count of pixels in the strip volatile uint8_t* _port; // Output PORT register uint32_t _endTime; // Latch timing reference diff --git a/src/internal/methods/NeoEsp32RmtMethod.cpp b/src/internal/methods/NeoEsp32RmtMethod.cpp index cf2950c..b998285 100644 --- a/src/internal/methods/NeoEsp32RmtMethod.cpp +++ b/src/internal/methods/NeoEsp32RmtMethod.cpp @@ -30,6 +30,7 @@ License along with NeoPixel. If not, see #if defined(ARDUINO_ARCH_ESP32) && !defined(ARDUINO_ESP32C6_DEV) && !defined(ARDUINO_ESP32H2_DEV) #include +#include "../NeoUtil.h" #include "../NeoSettings.h" #include "../NeoBusChannel.h" #include "NeoEsp32RmtMethod.h" diff --git a/src/internal/methods/NeoEsp8266UartMethod.cpp b/src/internal/methods/NeoEsp8266UartMethod.cpp index ee74d47..33fbd8e 100644 --- a/src/internal/methods/NeoEsp8266UartMethod.cpp +++ b/src/internal/methods/NeoEsp8266UartMethod.cpp @@ -27,6 +27,7 @@ License along with NeoPixel. If not, see #ifdef ARDUINO_ARCH_ESP8266 #include +#include "../NeoUtil.h" #include "../NeoSettings.h" #include "NeoEsp8266UartMethod.h" #include diff --git a/src/internal/methods/NeoPixelAvr.c b/src/internal/methods/NeoPixelAvr.c index 4c28f18..02b7383 100644 --- a/src/internal/methods/NeoPixelAvr.c +++ b/src/internal/methods/NeoPixelAvr.c @@ -33,6 +33,10 @@ License along with NeoPixel. If not, see . -------------------------------------------------------------------------*/ +// Handy AVR ASM Reference links: +// https://onlinedocs.microchip.com/pr/GUID-317042D4-BCCE-4065-BB05-AC4312DBC2C4-en-US-2/index.html?GUID-E152F8C1-EEE2-4A9D-A728-568E1B02F740 +// + // must also check for arm due to Teensy incorrectly having ARDUINO_ARCH_AVR set #if (defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)) && !defined(__arm__) @@ -169,10 +173,12 @@ void send_data_8mhz_800_PortD(uint8_t* data, size_t sizeData, uint8_t pinMask) "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi "out %[port] , %[lo]" "\n\t" // 1 PORT = lo "brne headD" "\n" // 2 while(i) (Z flag set above) + // outputs : [byte] "+r" (b), [n1] "+r" (n1), [n2] "+r" (n2), [count] "+w" (i) + // inputs : [port] "I" (_SFR_IO_ADDR(PORTD)), [ptr] "e" (ptr), [hi] "r" (hi), @@ -266,8 +272,15 @@ void send_data_8mhz_800_PortB(uint8_t* data, size_t sizeData, uint8_t pinMask) "mov %[n1] , %[hi]" "\n\t" "out %[port] , %[lo]" "\n\t" "brne headB" "\n" - : [byte] "+r" (b), [n1] "+r" (n1), [n2] "+r" (n2), [count] "+w" (i) - : [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi), + // outputs + : [byte] "+r" (b), + [n1] "+r" (n1), + [n2] "+r" (n2), + [count] "+w" (i) + // inputs + : [port] "I" (_SFR_IO_ADDR(PORTB)), + [ptr] "e" (ptr), + [hi] "r" (hi), [lo] "r" (lo)); } @@ -318,14 +331,16 @@ void send_data_8mhz_400(uint8_t* data, size_t sizeData, volatile uint8_t* port, "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 16) "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) "brne head20" "\n" // 2 if(i != 0) -> (next byte) + // outputs : [port] "+e" (port), - [byte] "+r" (b), - [bit] "+r" (bit), + [byte] "+r" (b), // l = lower register + [bit] "+d" (bit), // d = upper register, due to ldi, must be upper register [next] "+r" (next), [count] "+w" (i) - : [hi] "r" (hi), - [lo] "r" (lo), - [ptr] "e" (ptr)); + // inputs + : [ptr] "e" (ptr), + [hi] "r" (hi), // a = simple upper register (16-23) + [lo] "r" (lo)); } #elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL) // 12Mhz CPU @@ -394,9 +409,11 @@ void send_data_12mhz_800_PortD(uint8_t* data, size_t sizeData, uint8_t pinMask) "out %[port], %[lo]" "\n\t" // 1 PORT = lo (T = 11) "ret" "\n\t" // 4 nop nop nop nop (T = 15) "doneD:" "\n" + // outputs : [byte] "+r" (b), [next] "+r" (next), [count] "+w" (i) + // inputs : [port] "I" (_SFR_IO_ADDR(PORTD)), [ptr] "e" (ptr), [hi] "r" (hi), @@ -461,8 +478,14 @@ void send_data_12mhz_800_PortB(uint8_t* data, size_t sizeData, uint8_t pinMask) "out %[port], %[lo]" "\n\t" "ret" "\n\t" "doneB:" "\n" - : [byte] "+r" (b), [next] "+r" (next), [count] "+w" (i) - : [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi), + // outputs + : [byte] "+r" (b), + [next] "+r" (next), + [count] "+w" (i) + // inputs + : [port] "I" (_SFR_IO_ADDR(PORTB)), + [ptr] "e" (ptr), + [hi] "r" (hi), [lo] "r" (lo)); } @@ -514,14 +537,16 @@ void send_data_12mhz_400(uint8_t* data, "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 26) "sbiw %[count], 1" "\n\t" // 2 i-- (T = 28) "brne head30" "\n" // 1-2 if(i != 0) -> (next byte) + // outputs : [port] "+e" (port), [byte] "+r" (b), - [bit] "+r" (bit), + [bit] "+d" (bit), // d = upper register, due to ldi, must be upper register [next] "+r" (next), [count] "+w" (i) - : [hi] "r" (hi), - [lo] "r" (lo), - [ptr] "e" (ptr)); + // inputs + : [ptr] "e" (ptr), + [hi] "r" (hi), // a = simple upper register (16-23) + [lo] "r" (lo)); } #elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000UL) // 16Mhz CPU @@ -571,13 +596,15 @@ void send_data_16mhz_800(uint8_t* data, size_t sizeData, volatile uint8_t* port, "nop" "\n\t" // 1 nop (T = 16) "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) "brne head20" "\n" // 2 if(i != 0) -> (next byte) + // outputs : [port] "+e" (port), - [byte] "+r" (b), - [bit] "+r" (bit), + [byte] "+r" (b), // l = lower register + [bit] "+d" (bit), // d = upper register, due to ldi, must be upper register [next] "+r" (next), [count] "+w" (i) + // inputs : [ptr] "e" (ptr), - [hi] "r" (hi), + [hi] "r" (hi), // a = simple upper register (16-23) [lo] "r" (lo)); } @@ -639,11 +666,13 @@ void send_data_16mhz_400(uint8_t* data, "rjmp .+0" "\n\t" // 2 nop nop (T = 36) "sbiw %[count], 1" "\n\t" // 2 i-- (T = 38) "brne head40" "\n" // 1-2 if(i != 0) -> (next byte) + // outputs : [port] "+e" (port), [byte] "+r" (b), - [bit] "+r" (bit), + [bit] "+d" (bit), // d = upper register, due to ldi, must be upper register [next] "+r" (next), [count] "+w" (i) + // inputs : [ptr] "e" (ptr), [hi] "r" (hi), [lo] "r" (lo)); @@ -701,11 +730,13 @@ void send_data_16mhz_600(uint8_t* data, "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 23) "sbiw %[count], 1" "\n\t" // 2 i-- (T = 25) "brne head60" "\n" // 1-2 if(i != 0) -> (next byte) + // outputs : [port] "+e" (port), [byte] "+r" (b), - [bit] "+r" (bit), + [bit] "+d" (bit), // d = upper register, due to ldi, must be upper register [next] "+r" (next), [count] "+w" (i) + // inputs : [ptr] "e" (ptr), [hi] "r" (hi), [lo] "r" (lo)); @@ -769,7 +800,7 @@ void send_data_32mhz(uint8_t* data, // outputs : [port] "+e" (port), [byte] "+r" (b), - [bit] "+r" (bit), + [bit] "+d" (bit), // d = upper register, due to ldi, must be upper register [next] "+r" (next), [cycle] "+r" (cycle), [count] "+w" (i) diff --git a/src/internal/methods/Tlc59711GenericMethod.h b/src/internal/methods/Tlc59711GenericMethod.h index de2477a..fea8848 100644 --- a/src/internal/methods/Tlc59711GenericMethod.h +++ b/src/internal/methods/Tlc59711GenericMethod.h @@ -111,7 +111,7 @@ public: { while (!IsReadyToUpdate()) { -#if !defined(ARDUINO_TEEONARDU_LEO) && !defined(ARDUINO_TEEONARDU_FLORA) && !defined(ARDUINO_AVR_DIGISPARK) +#if !defined(NEOPIXEBUS_NO_YIELD) yield(); // allows for system yield if needed #endif } diff --git a/src/internal/methods/Ws2801GenericMethod.h b/src/internal/methods/Ws2801GenericMethod.h index 33d8da0..acafcfe 100644 --- a/src/internal/methods/Ws2801GenericMethod.h +++ b/src/internal/methods/Ws2801GenericMethod.h @@ -86,7 +86,7 @@ public: { while (!IsReadyToUpdate()) { -#if !defined(ARDUINO_TEEONARDU_LEO) && !defined(ARDUINO_TEEONARDU_FLORA) && !defined(ARDUINO_AVR_DIGISPARK) +#if !defined(NEOPIXEBUS_NO_YIELD) yield(); // allows for system yield if needed #endif }