diff --git a/ReadMe.md b/ReadMe.md index de61efd..00e2ca6 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -4,7 +4,7 @@ Arduino NeoPixel library -A library to control one wire protocol RGB and RGBW leds like APA106, SK6812, WS2811, WS2812 and WS2813 that are commonly refered to as NeoPixels and two wire protocol RGB like APA102 commonly refered to as DotStars. +A library to control one wire protocol RGB and RGBW leds like APA106, SK6812, WS2811, WS2812 and WS2813 that are commonly refered to as NeoPixels and two wire protocol RGB like Lpd8806 and APA102 commonly refered to as DotStars. Supports most Arduino platforms. This is the most functional library for the Esp8266 as it provides solutions for all Esp8266 module types even when WiFi is used. diff --git a/keywords.txt b/keywords.txt index 4734aca..e8a55d4 100644 --- a/keywords.txt +++ b/keywords.txt @@ -20,6 +20,7 @@ NeoBrgFeature KEYWORD1 NeoRbgFeature KEYWORD1 DotStarBgrFeature KEYWORD1 DotStarLbgrFeature KEYWORD1 +Lpd8806GrbFeature KEYWORD1 Neo800KbpsMethod KEYWORD1 Neo400KbpsMethod KEYWORD1 NeoWs2813Method KEYWORD1 @@ -123,6 +124,14 @@ NeoEsp32BitBang800KbpsMethod KEYWORD1 NeoEsp32BitBang400KbpsMethod KEYWORD1 DotStarMethod KEYWORD1 DotStarSpiMethod KEYWORD1 +DotStarSpi20MhzMethod KEYWORD1 +DotStarSpi10MhzMethod KEYWORD1 +DotStarSpi2MhzMethod KEYWORD1 +Lpd8806Method KEYWORD1 +Lpd8806SpiMethod KEYWORD1 +Lpd8806Spi20MhzMethod KEYWORD1 +Lpd8806Spi10MhzMethod KEYWORD1 +Lpd8806Spi2MhzMethod KEYWORD1 NeoPixelAnimator KEYWORD1 AnimUpdateCallback KEYWORD1 AnimationParam KEYWORD1 diff --git a/library.json b/library.json index 88f550c..7ee7ca2 100644 --- a/library.json +++ b/library.json @@ -1,14 +1,14 @@ { - "name": "NeoPixelBus", - "keywords": "NeoPixel, WS2811, WS2812, WS2813, SK6812, DotStar, APA102, APA106, RGB, RGBW", - "description": "A library that makes controlling NeoPixels (APA106, WS2811, WS2812, WS2813 & SK6812) and DotStars (APA102) easy. Supports most Arduino platforms. Support for RGBW pixels. Includes seperate RgbColor, RgbwColor, HslColor, and HsbColor objects. Includes an animator class that helps create asyncronous animations. For Esp8266 it has three methods of sending NeoPixel data, DMA, UART, and Bit Bang. For Esp32 it has two base methods of sending NeoPixel data, i2s and RMT. For all platforms, there are two methods of sending DotStar data, hardware SPI and software SPI.", - "homepage": "https://github.com/Makuna/NeoPixelBus/wiki", - "repository": { - "type": "git", - "url": "https://github.com/Makuna/NeoPixelBus" - }, - "version": "2.5.1", - "frameworks": "arduino", - "platforms": "*" + "name": "NeoPixelBus", + "keywords": "NeoPixel, WS2811, WS2812, WS2813, SK6812, DotStar, APA102, APA106, LPD8806, RGB, RGBW", + "description": "A library that makes controlling NeoPixels (APA106, WS2811, WS2812, WS2813 & SK6812) and DotStars (APA102, LPD8806) easy. Supports most Arduino platforms. Support for RGBW pixels. Includes seperate RgbColor, RgbwColor, HslColor, and HsbColor objects. Includes an animator class that helps create asyncronous animations. For Esp8266 it has three methods of sending NeoPixel data, DMA, UART, and Bit Bang. For Esp32 it has two base methods of sending NeoPixel data, i2s and RMT. For all platforms, there are two methods of sending DotStar data, hardware SPI and software SPI.", + "homepage": "https://github.com/Makuna/NeoPixelBus/wiki", + "repository": { + "type": "git", + "url": "https://github.com/Makuna/NeoPixelBus" + }, + "version": "2.5.1", + "frameworks": "arduino", + "platforms": "*" } diff --git a/library.properties b/library.properties index 1e89b08..5526bb7 100644 --- a/library.properties +++ b/library.properties @@ -2,7 +2,7 @@ name=NeoPixelBus by Makuna version=2.5.1 author=Michael C. Miller (makuna@live.com) maintainer=Michael C. Miller (makuna@live.com) -sentence=A library that makes controlling NeoPixels (APA106, WS2811, WS2812, WS2813 & SK6812) and DotStars (APA102) easy. +sentence=A library that makes controlling NeoPixels (APA106, WS2811, WS2812, WS2813 & SK6812) and DotStars (APA102, LPD8806) easy. paragraph=Supports most Arduino platforms, including Esp8266 and Esp32. Support for RGBW pixels. Includes seperate RgbColor, RgbwColor, HslColor, and HsbColor objects. Includes an animator class that helps create asyncronous animations. Supports Matrix layout of pixels. Includes Gamma corretion object. For Esp8266 it has three methods of sending NeoPixel data, DMA, UART, and Bit Bang. For Esp32 it has two base methods of sending NeoPixel data, i2s and RMT. For all platforms, there are two methods of sending DotStar data, hardware SPI and software SPI. category=Display url=https://github.com/Makuna/NeoPixelBus/wiki diff --git a/src/NeoPixelBus.h b/src/NeoPixelBus.h index 3c08f83..15ac120 100644 --- a/src/NeoPixelBus.h +++ b/src/NeoPixelBus.h @@ -46,6 +46,7 @@ License along with NeoPixel. If not, see #include "internal/NeoColorFeatures.h" #include "internal/DotStarColorFeatures.h" +#include "internal/Lpd8806ColorFeatures.h" #include "internal/Layouts.h" #include "internal/NeoTopology.h" @@ -63,37 +64,34 @@ License along with NeoPixel. If not, see #include "internal/NeoEase.h" #include "internal/NeoGamma.h" +#include "internal/DotStarGenericMethod.h" +#include "internal/Lpd8806GenericMethod.h" + #if defined(ARDUINO_ARCH_ESP8266) #include "internal/NeoEsp8266DmaMethod.h" #include "internal/NeoEsp8266UartMethod.h" #include "internal/NeoEspBitBangMethod.h" -#include "internal/DotStarGenericMethod.h" #elif defined(ARDUINO_ARCH_ESP32) #include "internal/NeoEsp32I2sMethod.h" #include "internal/NeoEsp32RmtMethod.h" #include "internal/NeoEspBitBangMethod.h" -#include "internal/DotStarGenericMethod.h" #elif defined(__arm__) // must be before ARDUINO_ARCH_AVR due to Teensy incorrectly having it set #include "internal/NeoArmMethod.h" -#include "internal/DotStarGenericMethod.h" #elif defined(ARDUINO_ARCH_AVR) #include "internal/NeoAvrMethod.h" -#include "internal/DotStarAvrMethod.h" #else #error "Platform Currently Not Supported, please add an Issue at Github/Makuna/NeoPixelBus" #endif -#if !defined(__AVR_ATtiny85__) -#include "internal/DotStarSpiMethod.h" -#endif + template class NeoPixelBus diff --git a/src/internal/DotStarAvrMethod.h b/src/internal/DotStarAvrMethod.h deleted file mode 100644 index a627d0a..0000000 --- a/src/internal/DotStarAvrMethod.h +++ /dev/null @@ -1,153 +0,0 @@ -/*------------------------------------------------------------------------- -NeoPixel library helper functions for DotStars on AVR (APA102). - -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 -. --------------------------------------------------------------------------*/ - -#pragma once - -// must also check for arm due to Teensy incorrectly having ARDUINO_ARCH_AVR set -#if defined(ARDUINO_ARCH_AVR) && !defined(__arm__) - -class DotStarAvrMethod -{ -public: - DotStarAvrMethod(uint8_t pinClock, uint8_t pinData, uint16_t pixelCount, size_t elementSize) : - _pinClock(pinClock), - _pinData(pinData), - _sizePixels(pixelCount * elementSize) - { - pinMode(pinClock, OUTPUT); - pinMode(pinData, OUTPUT); - - _pixels = (uint8_t*)malloc(_sizePixels); - memset(_pixels, 0, _sizePixels); - - _portClock = portOutputRegister(digitalPinToPort(_pinClock)); - _pinMaskClock = digitalPinToBitMask(_pinClock); - _portData = portOutputRegister(digitalPinToPort(_pinData)); - _pinMaskData = digitalPinToBitMask(_pinData); - } - - ~DotStarAvrMethod() - { - pinMode(_pinClock, INPUT); - pinMode(_pinData, INPUT); - - free(_pixels); - } - - bool IsReadyToUpdate() const - { - return true; // dot stars don't have a required delay - } - - void Initialize() - { - digitalWrite(_pinClock, LOW); - digitalWrite(_pinData, LOW); - } - - void Update(bool) - { - // start frame - for (int startFrameByte = 0; startFrameByte < 4; startFrameByte++) - { - _transmitByte(0x00); - } - - // data - uint8_t* data = _pixels; - const uint8_t* endData = _pixels + _sizePixels; - while (data < endData) - { - _transmitByte(*data++); - } - - // end frame - // one bit for every two pixels with no less than 1 byte - const uint16_t countEndFrameBytes = ((_sizePixels / 4) + 15) / 16; - for (uint16_t endFrameByte = 0; endFrameByte < countEndFrameBytes; endFrameByte++) - { - _transmitByte(0xff); - } - - // set clock and data back to low between updates - digitalWrite(_pinData, LOW); - } - - uint8_t* getPixels() const - { - return _pixels; - }; - - size_t getPixelsSize() const - { - return _sizePixels; - }; - -private: - const uint8_t _pinClock; // output pin number for clock line - const uint8_t _pinData; // output pin number for data line - const size_t _sizePixels; // Size of '_pixels' buffer below - - uint8_t* _pixels; // Holds LED color values - - volatile uint8_t* _portData; // Output PORT register - uint8_t _pinMaskData; // Output PORT bitmask - volatile uint8_t* _portClock; // Output PORT register - uint8_t _pinMaskClock; // Output PORT bitmask - - void _transmitByte(uint8_t data) - { - for (int bit = 7; bit >= 0; bit--) - { - // set data bit on pin - // digitalWrite(_pinData, (data & 0x80) == 0x80 ? HIGH : LOW); - if (data & 0x80) - { - *_portData |= _pinMaskData; - } - else - { - *_portData &= ~_pinMaskData; - } - - - // set clock high as data is ready - // digitalWrite(_pinClock, HIGH); - *_portClock |= _pinMaskClock; - - // done between clock toggle to give a little time - data <<= 1; - - // set clock low as data pin is changed - // digitalWrite(_pinClock, LOW); - *_portClock &= ~_pinMaskClock; - } - } -}; - -typedef DotStarAvrMethod DotStarMethod; - -#endif diff --git a/src/internal/DotStarGenericMethod.h b/src/internal/DotStarGenericMethod.h index 8b3fe33..c660e3c 100644 --- a/src/internal/DotStarGenericMethod.h +++ b/src/internal/DotStarGenericMethod.h @@ -26,26 +26,33 @@ License along with NeoPixel. If not, see #pragma once -class DotStarGenericMethod +// must also check for arm due to Teensy incorrectly having ARDUINO_ARCH_AVR set +#if defined(ARDUINO_ARCH_AVR) && !defined(__arm__) +#include "TwoWireBitBangImpleAvr.h" +#else +#include "TwoWireBitBangImple.h" +#endif + + +template class DotStarMethodBase { public: - DotStarGenericMethod(uint8_t pinClock, uint8_t pinData, uint16_t pixelCount, size_t elementSize) : - _pinClock(pinClock), - _pinData(pinData), - _sizePixels(pixelCount * elementSize) + DotStarMethodBase(uint8_t pinClock, uint8_t pinData, uint16_t pixelCount, size_t elementSize) : + _sizePixels(pixelCount * elementSize), + _sizeEndFrame((pixelCount + 15) / 16), // 16 = div 2 (bit for every two pixels) div 8 (bits to bytes) + _wire(pinClock, pinData) { - pinMode(pinClock, OUTPUT); - pinMode(pinData, OUTPUT); - _pixels = (uint8_t*)malloc(_sizePixels); memset(_pixels, 0, _sizePixels); } - ~DotStarGenericMethod() - { - pinMode(_pinClock, INPUT); - pinMode(_pinData, INPUT); + DotStarMethodBase(uint16_t pixelCount, size_t elementSize) : + DotStarMethodBase(SCK, MOSI, pixelCount, elementSize) + { + } + ~DotStarMethodBase() + { free(_pixels); } @@ -54,38 +61,38 @@ public: return true; // dot stars don't have a required delay } +#if defined(ARDUINO_ARCH_ESP32) + void Initialize(int8_t sck, int8_t miso, int8_t mosi, int8_t ss) + { + _wire.begin(sck, miso, mosi, ss); + } +#endif + void Initialize() { - digitalWrite(_pinClock, LOW); - digitalWrite(_pinData, LOW); + _wire.begin(); } void Update(bool) { + const uint8_t startFrame[4] = { 0x00 }; + + _wire.beginTransaction(); + // start frame - for (int startFrameByte = 0; startFrameByte < 4; startFrameByte++) - { - _transmitByte(0x00); - } + _wire.transmitBytes(startFrame, sizeof(startFrame)); // data - uint8_t* data = _pixels; - const uint8_t* endData = _pixels + _sizePixels; - while (data < endData) - { - _transmitByte(*data++); - } + _wire.transmitBytes(_pixels, _sizePixels); // end frame - // one bit for every two pixels with no less than 1 byte - const uint16_t countEndFrameBytes = ((_sizePixels / 4) + 15) / 16; - for (uint16_t endFrameByte = 0; endFrameByte < countEndFrameBytes; endFrameByte++) - { - _transmitByte(0xff); - } + // one bit for every two pixels with no less than 1 byte + for (size_t endFrameByte = 0; endFrameByte < _sizeEndFrame; endFrameByte++) + { + _wire.transmitByte(0xff); + } - // set clock and data back to low between updates - digitalWrite(_pinData, LOW); + _wire.endTransaction(); } uint8_t* getPixels() const @@ -99,30 +106,22 @@ public: }; private: - const uint8_t _pinClock; // output pin number for clock line - const uint8_t _pinData; // output pin number for data line - const size_t _sizePixels; // Size of '_pixels' buffer below + const size_t _sizePixels; // Size of '_pixels' buffer below + const size_t _sizeEndFrame; + T_TWOWIRE _wire; uint8_t* _pixels; // Holds LED color values - - void _transmitByte(uint8_t data) - { - for (int bit = 7; bit >= 0; bit--) - { - // set data bit on pin - digitalWrite(_pinData, (data & 0x80) == 0x80 ? HIGH : LOW); - - // set clock high as data is ready - digitalWrite(_pinClock, HIGH); - - data <<= 1; - - // set clock low as data pin is changed - digitalWrite(_pinClock, LOW); - } - } }; -typedef DotStarGenericMethod DotStarMethod; +typedef DotStarMethodBase DotStarMethod; + +#if !defined(__AVR_ATtiny85__) +#include "TwoWireSpiImple.h" +typedef DotStarMethodBase> DotStarSpi20MhzMethod; +typedef DotStarMethodBase> DotStarSpi10MhzMethod; +typedef DotStarMethodBase> DotStarSpi2MhzMethod; +typedef DotStarSpi10MhzMethod DotStarSpiMethod; +#endif + diff --git a/src/internal/DotStarSpiMethod.h b/src/internal/DotStarSpiMethod.h deleted file mode 100644 index 7c51816..0000000 --- a/src/internal/DotStarSpiMethod.h +++ /dev/null @@ -1,133 +0,0 @@ -/*------------------------------------------------------------------------- -NeoPixel library helper functions for DotStars using SPI hardware (APA102). - -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 -. --------------------------------------------------------------------------*/ - -#pragma once - -#include - -class DotStarSpiMethod -{ -public: - DotStarSpiMethod(uint16_t pixelCount, size_t elementSize) : - _sizeData(pixelCount * elementSize), - _sizeSendBuffer(calcBufferSize(pixelCount * elementSize)) - { - _sendBuffer = (uint8_t*)malloc(_sizeSendBuffer); - memset(_sendBuffer, 0, _sizeSendBuffer); - setEndFrameBytes(); - } - - ~DotStarSpiMethod() - { - SPI.end(); - free(_sendBuffer); - } - - bool IsReadyToUpdate() const - { - return true; // dot stars don't have a required delay - } - -#if defined(ARDUINO_ARCH_ESP32) - void Initialize(int8_t sck, int8_t miso, int8_t mosi, int8_t ss) - { - SPI.begin(sck, miso, mosi, ss); - } -#endif - - void Initialize() - { - SPI.begin(); - } - - void Update(bool) - { - SPI.beginTransaction(SPISettings(20000000L, MSBFIRST, SPI_MODE0)); -#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) - // ESPs have a method to write without inplace overwriting the send buffer - // since we don't care what gets received, use it for performance - SPI.writeBytes(_sendBuffer, _sizeSendBuffer); - -#else - // default ARDUINO transfer inplace overwrites the send buffer - // which is bad, so we have to send one byte at a time - uint8_t* out = _sendBuffer; - uint8_t* end = out + _sizeSendBuffer; - while (out < end) - { - SPI.transfer(*out++); - } -#endif - SPI.endTransaction(); - } - - uint8_t* getPixels() const - { - return _sendBuffer + _countStartFrame; - }; - - size_t getPixelsSize() const - { - return _sizeData; - }; - -private: - const size_t _countStartFrame = 4; - const size_t _sizeData; // size of actuall pixel data within _sendBuffer - const size_t _sizeSendBuffer; // Size of '_sendBuffer' buffer below - - uint8_t* _sendBuffer; // Holds SPI send Buffer, including LED color values - - size_t calcBufferSize(size_t sizePixels) const - { - const size_t countEndFrameBytes = calcEndFrameSize(sizePixels); - - // start frame + data + end frame - const size_t bufferSize = _countStartFrame + sizePixels + countEndFrameBytes; - return bufferSize; - } - - size_t calcEndFrameSize(size_t sizePixels) const - { - // end frame - // one bit for every two pixels with no less than 1 byte - return ((sizePixels / 4) + 15) / 16; - } - - void setEndFrameBytes() - { - uint8_t* pEndFrame = _sendBuffer + _countStartFrame + _sizeData; - uint8_t* pEndFrameStop = pEndFrame + calcEndFrameSize(_sizeData); - while (pEndFrame != pEndFrameStop) - { - *pEndFrame++ = 0xff; - } - } -}; - - - - diff --git a/src/internal/Lpd8806ColorFeatures.h b/src/internal/Lpd8806ColorFeatures.h new file mode 100644 index 0000000..2dade10 --- /dev/null +++ b/src/internal/Lpd8806ColorFeatures.h @@ -0,0 +1,167 @@ +/*------------------------------------------------------------------------- +Lpd8806ColorFeatures provides feature classes to describe color order and +color depth for NeoPixelBus template class when used with DotStar like chips + +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 +. +-------------------------------------------------------------------------*/ +#pragma once + +class Lpd88063Elements +{ +public: + static const size_t PixelSize = 3; + + static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel) + { + return pPixels + indexPixel * PixelSize; + } + static const uint8_t* getPixelAddress(const uint8_t* pPixels, uint16_t indexPixel) + { + return pPixels + indexPixel * PixelSize; + } + + static void replicatePixel(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + while (pPixelDest < pEnd) + { + *pPixelDest++ = pPixelSrc[0]; + *pPixelDest++ = pPixelSrc[1]; + *pPixelDest++ = pPixelSrc[2]; + } + } + + static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + while (pPixelDest < pEnd) + { + *pPixelDest++ = *pPixelSrc++; + *pPixelDest++ = *pPixelSrc++; + *pPixelDest++ = *pPixelSrc++; + } + } + + static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + const uint8_t* pSrc = (const uint8_t*)pPixelSrc; + while (pPixelDest < pEnd) + { + *pPixelDest++ = pgm_read_byte(pSrc++); + *pPixelDest++ = pgm_read_byte(pSrc++); + *pPixelDest++ = pgm_read_byte(pSrc++); + } + } + + static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pDestBack = pPixelDest + (count * PixelSize); + const uint8_t* pSrcBack = pPixelSrc + (count * PixelSize); + while (pDestBack > pPixelDest) + { + *--pDestBack = *--pSrcBack; + *--pDestBack = *--pSrcBack; + *--pDestBack = *--pSrcBack; + } + } + + typedef RgbColor ColorObject; +}; + +class Lpd8806BrgFeature : public Lpd88063Elements +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = (color.B >> 1) | 0x80; + *p++ = (color.R >> 1) | 0x80; + *p = (color.G >> 1) | 0x80; + } + + static ColorObject retrievePixelColor(uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + color.B = (*p++) << 1; + color.R = (*p++) << 1; + color.G = (*p) << 1; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + color.B = (pgm_read_byte(p++)) << 1; + color.R = (pgm_read_byte(p++)) << 1; + color.G = (pgm_read_byte(p)) << 1; + + return color; + } + +}; + +class Lpd8806GrbFeature : public Lpd88063Elements +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = (color.G >> 1) | 0x80; + *p++ = (color.R >> 1) | 0x80; + *p = (color.B >> 1) | 0x80; + } + + static ColorObject retrievePixelColor(uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + color.G = (*p++) << 1; + color.R = (*p++) << 1; + color.B = (*p) << 1; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + color.G = (pgm_read_byte(p++)) << 1; + color.R = (pgm_read_byte(p++)) << 1; + color.B = (pgm_read_byte(p)) << 1; + + return color; + } + +}; + diff --git a/src/internal/Lpd8806GenericMethod.h b/src/internal/Lpd8806GenericMethod.h new file mode 100644 index 0000000..ddfe0d0 --- /dev/null +++ b/src/internal/Lpd8806GenericMethod.h @@ -0,0 +1,127 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for LPD8806 using general Pins + +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 +. +-------------------------------------------------------------------------*/ + +#pragma once + +// must also check for arm due to Teensy incorrectly having ARDUINO_ARCH_AVR set +#if defined(ARDUINO_ARCH_AVR) && !defined(__arm__) +#include "TwoWireBitBangImpleAvr.h" +#else +#include "TwoWireBitBangImple.h" +#endif + + +template class Lpd8806MethodBase +{ +public: + Lpd8806MethodBase(uint8_t pinClock, uint8_t pinData, uint16_t pixelCount, size_t elementSize) : + _sizePixels(pixelCount * elementSize), + _sizeFrame((pixelCount + 31) / 32), + _wire(pinClock, pinData) + { + _pixels = (uint8_t*)malloc(_sizePixels); + memset(_pixels, 0, _sizePixels); + } + + Lpd8806MethodBase(uint16_t pixelCount, size_t elementSize) : + Lpd8806MethodBase(SCK, MOSI, pixelCount, elementSize) + { + } + + ~Lpd8806MethodBase() + { + free(_pixels); + } + + bool IsReadyToUpdate() const + { + return true; // dot stars don't have a required delay + } + +#if defined(ARDUINO_ARCH_ESP32) + void Initialize(int8_t sck, int8_t miso, int8_t mosi, int8_t ss) + { + _wire.begin(sck, miso, mosi, ss); + } +#endif + + void Initialize() + { + _wire.begin(); + } + + void Update(bool) + { + _wire.beginTransaction(); + + // start frame + for (size_t frameByte = 0; frameByte < _sizeFrame; frameByte++) + { + _wire.transmitByte(0x00); + } + + // data + _wire.transmitBytes(_pixels, _sizePixels); + + // end frame + for (size_t frameByte = 0; frameByte < _sizeFrame; frameByte++) + { + _wire.transmitByte(0xff); + } + + _wire.endTransaction(); + } + + uint8_t* getPixels() const + { + return _pixels; + }; + + size_t getPixelsSize() const + { + return _sizePixels; + }; + +private: + const size_t _sizePixels; // Size of '_pixels' buffer below + const size_t _sizeFrame; + + T_TWOWIRE _wire; + uint8_t* _pixels; // Holds LED color values +}; + +typedef Lpd8806MethodBase Lpd8806Method; + +#if !defined(__AVR_ATtiny85__) +#include "TwoWireSpiImple.h" +typedef Lpd8806MethodBase> Lpd8806Spi20MhzMethod; +typedef Lpd8806MethodBase> Lpd8806Spi10MhzMethod; +typedef Lpd8806MethodBase> Lpd8806Spi2MhzMethod; +typedef Lpd8806Spi10MhzMethod Lpd8806SpiMethod; +#endif + + + diff --git a/src/internal/TwoWireBitBangImple.h b/src/internal/TwoWireBitBangImple.h new file mode 100644 index 0000000..44aed15 --- /dev/null +++ b/src/internal/TwoWireBitBangImple.h @@ -0,0 +1,92 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for DotStars using general Pins (APA102/LPD8806). + +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 +. +-------------------------------------------------------------------------*/ + +#pragma once + + +class TwoWireBitBangImple +{ +public: + TwoWireBitBangImple(uint8_t pinClock, uint8_t pinData) : + _pinClock(pinClock), + _pinData(pinData) + { + pinMode(pinClock, OUTPUT); + pinMode(pinData, OUTPUT); + } + + ~TwoWireBitBangImple() + { + pinMode(_pinClock, INPUT); + pinMode(_pinData, INPUT); + } + + void begin() + { + digitalWrite(_pinClock, LOW); + digitalWrite(_pinData, LOW); + } + + void beginTransaction() + { + + } + + void endTransaction() + { + digitalWrite(_pinData, LOW); + } + + void transmitByte(uint8_t data) + { + for (int bit = 7; bit >= 0; bit--) + { + // set data bit on pin + digitalWrite(_pinData, (data & 0x80) == 0x80 ? HIGH : LOW); + + // set clock high as data is ready + digitalWrite(_pinClock, HIGH); + + data <<= 1; + + // set clock low as data pin is changed + digitalWrite(_pinClock, LOW); + } + } + + void transmitBytes(const uint8_t* data, size_t dataSize) + { + const uint8_t* endData = data + dataSize; + while (data < endData) + { + transmitByte(*data++); + } + } + +private: + const uint8_t _pinClock; // output pin number for clock line + const uint8_t _pinData; // output pin number for data line +}; \ No newline at end of file diff --git a/src/internal/TwoWireBitBangImpleAvr.h b/src/internal/TwoWireBitBangImpleAvr.h new file mode 100644 index 0000000..3e32437 --- /dev/null +++ b/src/internal/TwoWireBitBangImpleAvr.h @@ -0,0 +1,112 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for DotStars using general Pins (APA102/LPD8806). + +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 +. +-------------------------------------------------------------------------*/ + +#pragma once + + +class TwoWireBitBangImple +{ +public: + TwoWireBitBangImple(uint8_t pinClock, uint8_t pinData) : + _pinClock(pinClock), + _pinData(pinData) + { + pinMode(pinClock, OUTPUT); + pinMode(pinData, OUTPUT); + + _portClock = portOutputRegister(digitalPinToPort(_pinClock)); + _pinMaskClock = digitalPinToBitMask(_pinClock); + _portData = portOutputRegister(digitalPinToPort(_pinData)); + _pinMaskData = digitalPinToBitMask(_pinData); + } + + ~TwoWireBitBangImple() + { + pinMode(_pinClock, INPUT); + pinMode(_pinData, INPUT); + } + + void begin() + { + digitalWrite(_pinClock, LOW); + digitalWrite(_pinData, LOW); + } + + void beginTransaction() + { + + } + + void endTransaction() + { + digitalWrite(_pinData, LOW); + } + + void transmitByte(uint8_t data) + { + for (int bit = 7; bit >= 0; bit--) + { + // set data bit on pin + // digitalWrite(_pinData, (data & 0x80) == 0x80 ? HIGH : LOW); + if (data & 0x80) + { + *_portData |= _pinMaskData; + } + else + { + *_portData &= ~_pinMaskData; + } + + // set clock high as data is ready + // digitalWrite(_pinClock, HIGH); + *_portClock |= _pinMaskClock; + + data <<= 1; + + // set clock low as data pin is changed + // digitalWrite(_pinClock, LOW); + *_portClock &= ~_pinMaskClock; + } + } + + void transmitBytes(const uint8_t* data, size_t dataSize) + { + const uint8_t* endData = data + dataSize; + while (data < endData) + { + transmitByte(*data++); + } + } + +private: + const uint8_t _pinClock; // output pin number for clock line + const uint8_t _pinData; // output pin number for data line + + volatile uint8_t* _portData; // Output PORT register + uint8_t _pinMaskData; // Output PORT bitmask + volatile uint8_t* _portClock; // Output PORT register + uint8_t _pinMaskClock; // Output PORT bitmask +}; \ No newline at end of file diff --git a/src/internal/TwoWireSpiImple.h b/src/internal/TwoWireSpiImple.h new file mode 100644 index 0000000..bc4e37f --- /dev/null +++ b/src/internal/TwoWireSpiImple.h @@ -0,0 +1,109 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for DotStars using general Pins (APA102/LPD8806). + +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 +. +-------------------------------------------------------------------------*/ + +#pragma once + +#include + +class SpiSpeed20Mhz +{ +public: + static const uint32_t Clock = 20000000L; +}; + +class SpiSpeed10Mhz +{ +public: + static const uint32_t Clock = 10000000L; +}; + +class SpiSpeed2Mhz +{ +public: + static const uint32_t Clock = 2000000L; +}; + +template class TwoWireSpiImple +{ +public: + TwoWireSpiImple(uint8_t, uint8_t) // clock and data pins ignored for hardware SPI + { + } + + ~TwoWireSpiImple() + { + SPI.end(); + } + +#if defined(ARDUINO_ARCH_ESP32) + // for cases where hardware SPI can have pins changed + void begin(int8_t sck, int8_t miso, int8_t mosi, int8_t ss) + { + SPI.begin(sck, miso, mosi, ss); + } +#endif + + void begin() + { + SPI.begin(); + } + + void beginTransaction() + { + SPI.beginTransaction(SPISettings(T_SPISPEED::Clock, MSBFIRST, SPI_MODE0)); + } + + void endTransaction() + { + SPI.endTransaction(); + } + + void transmitByte(uint8_t data) + { + SPI.transfer(data); + } + + void transmitBytes(const uint8_t* data, size_t dataSize) + { +#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) + // ESPs have a method to write without inplace overwriting the send buffer + // since we don't care what gets received, use it for performance + // FIX: but for what ever reason on Esp32, its not const + SPI.writeBytes(const_cast(data), dataSize); + +#else + // default ARDUINO transfer inplace overwrites the send buffer + // which is bad in this case, so we have to send one byte at a time + const uint8_t* endData = data + dataSize; + while (data < endData) + { + SPI.transfer(*data++); + } +#endif + } + +private: +}; \ No newline at end of file