diff --git a/keywords.txt b/keywords.txt index ced944a..c901108 100644 --- a/keywords.txt +++ b/keywords.txt @@ -69,6 +69,7 @@ NeoTm1829Method KEYWORD1 NeoTx1812Method KEYWORD1 NeoLc8812Method KEYWORD1 NeoApa106Method KEYWORD1 +NeoIntertekMethod KEYWORD1 Neo800KbpsInvertedMethod KEYWORD1 Neo400KbpsInvertedMethod KEYWORD1 NeoWs2813InvertedMethod KEYWORD1 @@ -83,6 +84,7 @@ NeoTm1829InvertedMethod KEYWORD1 NeoTx1812InvertedMethod KEYWORD1 NeoLc8812InvertedMethod KEYWORD1 NeoApa106InvertedMethod KEYWORD1 +NeoInvertedIntertekMethod KEYWORD1 NeoEsp8266DmaWs2812xMethod KEYWORD1 NeoEsp8266DmaWs2816Method KEYWORD1 NeoEsp8266DmaSk6812Method KEYWORD1 diff --git a/src/NeoPixelBrightnessBus.h b/src/NeoPixelBrightnessBus.h index b3a9bb2..2d82b56 100644 --- a/src/NeoPixelBrightnessBus.h +++ b/src/NeoPixelBrightnessBus.h @@ -28,7 +28,8 @@ License along with NeoPixel. If not, see #include "NeoPixelBus.h" -template class NeoPixelBrightnessBus : + +template class [[deprecated("Use NeoPixelBusLg instead.")]] NeoPixelBrightnessBus : public NeoPixelBus { private: diff --git a/src/internal/NeoEsp8266DmaMethod.h b/src/internal/NeoEsp8266DmaMethod.h index fff7003..4aa0302 100644 --- a/src/internal/NeoEsp8266DmaMethod.h +++ b/src/internal/NeoEsp8266DmaMethod.h @@ -125,7 +125,15 @@ public: const static uint32_t ResetTimeUs = 50; }; - +class NeoEsp8266DmaSpeedIntertek : public NeoEsp8266DmaSpeedBase +{ +public: + const static uint32_t I2sClockDivisor = 5; // 0-63 + const static uint32_t I2sBaseClockDivisor = 10; // 0-63 + const static uint32_t ByteSendTimeUs = 10; // us it takes to send a single pixel element + const static uint32_t ResetTimeUs = 12470; + const static uint32_t InterPixelTimeUs = 20; +}; class NeoEsp8266DmaInvertedSpeed800KbpsBase : public NeoEsp8266DmaInvertedSpeedBase { @@ -183,32 +191,103 @@ public: const static uint32_t ResetTimeUs = 50; }; +class NeoEsp8266DmaInvertedSpeedIntertek : public NeoEsp8266DmaInvertedSpeedBase +{ +public: + const static uint32_t I2sClockDivisor = 5; // 0-63 + const static uint32_t I2sBaseClockDivisor = 10; // 0-63 + const static uint32_t ByteSendTimeUs = 10; // us it takes to send a single pixel element at 800khz speed + const static uint32_t ResetTimeUs = 12470; + const static uint32_t InterPixelTimeUs = 20; +}; +template class NeoEsp8266DmaEncode : public T_SPEED +{ +public: + static size_t SpacingPixelSize(size_t sizePixel) + { + return sizePixel; + } -template class NeoEsp8266DmaMethodBase : NeoEsp8266I2sMethodCore + static void FillBuffers(uint8_t* i2sBuffer, + const uint8_t* data, + size_t sizeData, + [[maybe_unused]] size_t sizePixel) + { + uint16_t* pDma = (uint16_t*)i2sBuffer; + const uint8_t* pEnd = data + sizeData; + for (const uint8_t* pData = data; pData < pEnd; pData++) + { + *(pDma++) = T_SPEED::Convert(((*pData) & 0x0f)); + *(pDma++) = T_SPEED::Convert(((*pData) >> 4) & 0x0f); + } + } +}; + +template class NeoEsp8266DmaPixelSpacingEncode : public T_SPEED +{ +public: + static size_t SpacingPixelSize(size_t sizePixel) + { + return sizePixel + T_SPEED::InterPixelTimeUs / T_SPEED::ByteSendTimeUs; + } + + static void FillBuffers(uint8_t* i2sBuffer, + const uint8_t* data, + size_t sizeData, + size_t sizePixel) + { + uint16_t* pDma = (uint16_t*)i2sBuffer; + const uint8_t* pEnd = data + sizeData; + uint8_t element = 0; + for (const uint8_t* pData = data; pData < pEnd; pData++) + { + *(pDma++) = T_SPEED::Convert(((*pData) & 0x0f)); + *(pDma++) = T_SPEED::Convert(((*pData) >> 4) & 0x0f); + + element++; + if (element == sizePixel) + { + element = 0; + + for (uint8_t padding = 0; + padding < (T_SPEED::InterPixelTimeUs / T_SPEED::ByteSendTimeUs); + padding++) + { + *(pDma++) = T_SPEED::IdleLevel * 0xffff; + *(pDma++) = T_SPEED::IdleLevel * 0xffff; + } + } + } + } +}; + +template class NeoEsp8266DmaMethodBase : NeoEsp8266I2sMethodCore { public: typedef NeoNoSettings SettingsObject; NeoEsp8266DmaMethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _sizePixel(elementSize), _sizeData(pixelCount * elementSize + settingsSize) { - size_t dmaPixelSize = DmaBytesPerPixelBytes * elementSize; + size_t dmaPixelSize = DmaBytesPerPixelBytes * T_ENCODER::SpacingPixelSize(_sizePixel); size_t dmaSettingsSize = DmaBytesPerPixelBytes * settingsSize; size_t i2sBufferSize = pixelCount * dmaPixelSize + dmaSettingsSize; + // size is rounded up to nearest c_I2sByteBoundarySize + i2sBufferSize = NeoUtil::RoundUp(i2sBufferSize, c_I2sByteBoundarySize); - // normally 24 bytes creates the minimum 50us latch per spec, but - // with the new logic, this latch is used to space between mulitple states - // buffer size = (24 * (reset time / 50)) / 6 - size_t i2sZeroesSize = (24L * (T_SPEED::ResetTimeUs / 50L)) / 6L; - + // calculate a buffer size that takes reset amount of time + size_t i2sResetSize = T_ENCODER::ResetTimeUs * DmaBytesPerPixelBytes / T_ENCODER::ByteSendTimeUs; + // size is rounded up to nearest c_I2sByteBoundarySize + i2sResetSize = NeoUtil::RoundUp(i2sResetSize, c_I2sByteBoundarySize); size_t is2BufMaxBlockSize = (c_maxDmaBlockSize / dmaPixelSize) * dmaPixelSize; _data = static_cast(malloc(_sizeData)); // data cleared later in Begin() - AllocateI2s(i2sBufferSize, i2sZeroesSize, is2BufMaxBlockSize, T_SPEED::IdleLevel); + AllocateI2s(i2sBufferSize, i2sResetSize, is2BufMaxBlockSize, T_ENCODER::IdleLevel); } NeoEsp8266DmaMethodBase([[maybe_unused]] uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : @@ -228,7 +307,7 @@ public: // wait for any pending sends to complete // due to internal i2s caching/send delays, this can more that once the data size uint32_t time = micros(); - while ((micros() - time) < ((getPixelTime() + T_SPEED::ResetTimeUs) * waits)) + while ((micros() - time) < ((getPixelTime() + T_ENCODER::ResetTimeUs) * waits)) { yield(); } @@ -245,7 +324,7 @@ public: void Initialize() { - InitializeI2s(T_SPEED::I2sClockDivisor, T_SPEED::I2sBaseClockDivisor); + InitializeI2s(T_ENCODER::I2sClockDivisor, T_ENCODER::I2sBaseClockDivisor); } void IRAM_ATTR Update(bool) @@ -255,10 +334,9 @@ public: { yield(); } - FillBuffers(); + T_ENCODER::FillBuffers(_i2sBuffer, _data, _sizeData, _sizePixel); - // toggle state so the ISR reacts - _dmaState = NeoDmaState_Pending; + WriteI2s(); } bool AlwaysUpdate() @@ -285,23 +363,13 @@ private: // due to encoding required for i2s, we need 4 bytes to encode the pulses static const uint16_t DmaBytesPerPixelBytes = 4; + const size_t _sizePixel; // size of a pixel in _data const size_t _sizeData; // Size of '_data' buffer uint8_t* _data; // Holds LED color values - void FillBuffers() - { - uint16_t* pDma = (uint16_t*)_i2sBuffer; - uint8_t* pEnd = _data + _sizeData; - for (uint8_t* pData = _data; pData < pEnd; pData++) - { - *(pDma++) = T_SPEED::Convert(((*pData) & 0x0f)); - *(pDma++) = T_SPEED::Convert(((*pData) >> 4) & 0x0f); - } - } - uint32_t getPixelTime() const { - return (T_SPEED::ByteSendTimeUs * this->_sizeData); + return (T_ENCODER::ByteSendTimeUs * GetSendSize() / DmaBytesPerPixelBytes); }; }; @@ -309,25 +377,27 @@ private: // normal -typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaWs2812xMethod; -typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaSk6812Method; -typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaTm1814Method; -typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaTm1829Method; +typedef NeoEsp8266DmaMethodBase> NeoEsp8266DmaWs2812xMethod; +typedef NeoEsp8266DmaMethodBase> NeoEsp8266DmaSk6812Method; +typedef NeoEsp8266DmaMethodBase> NeoEsp8266DmaTm1814Method; +typedef NeoEsp8266DmaMethodBase> NeoEsp8266DmaTm1829Method; typedef NeoEsp8266DmaTm1814Method NeoEsp8266DmaTm1914Method; -typedef NeoEsp8266DmaMethodBase NeoEsp8266Dma800KbpsMethod; -typedef NeoEsp8266DmaMethodBase NeoEsp8266Dma400KbpsMethod; -typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaApa106Method; +typedef NeoEsp8266DmaMethodBase> NeoEsp8266Dma800KbpsMethod; +typedef NeoEsp8266DmaMethodBase> NeoEsp8266Dma400KbpsMethod; +typedef NeoEsp8266DmaMethodBase> NeoEsp8266DmaApa106Method; +typedef NeoEsp8266DmaMethodBase> NeoEsp8266DmaIntertekMethod; // inverted -typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaInvertedWs2812xMethod; -typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaInvertedSk6812Method; -typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaInvertedTm1814Method; -typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaInvertedTm1829Method; +typedef NeoEsp8266DmaMethodBase> NeoEsp8266DmaInvertedWs2812xMethod; +typedef NeoEsp8266DmaMethodBase> NeoEsp8266DmaInvertedSk6812Method; +typedef NeoEsp8266DmaMethodBase> NeoEsp8266DmaInvertedTm1814Method; +typedef NeoEsp8266DmaMethodBase> NeoEsp8266DmaInvertedTm1829Method; typedef NeoEsp8266DmaInvertedTm1814Method NeoEsp8266DmaInvertedTm1914Method; -typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaInverted800KbpsMethod; -typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaInverted400KbpsMethod; -typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaInvertedApa106Method; +typedef NeoEsp8266DmaMethodBase> NeoEsp8266DmaInverted800KbpsMethod; +typedef NeoEsp8266DmaMethodBase> NeoEsp8266DmaInverted400KbpsMethod; +typedef NeoEsp8266DmaMethodBase> NeoEsp8266DmaInvertedApa106Method; +typedef NeoEsp8266DmaMethodBase> NeoEsp8266DmaInvertedIntertekMethod; // Dma method is the default method for Esp8266 typedef NeoEsp8266DmaWs2812xMethod NeoWs2813Method; @@ -341,6 +411,7 @@ typedef NeoEsp8266DmaTm1829Method NeoTm1829Method; typedef NeoEsp8266DmaTm1914Method NeoTm1914Method; typedef NeoEsp8266DmaSk6812Method NeoLc8812Method; typedef NeoEsp8266DmaApa106Method NeoApa106Method; +typedef NeoEsp8266DmaIntertekMethod NeoIntertekMethod; typedef NeoEsp8266DmaWs2812xMethod Neo800KbpsMethod; typedef NeoEsp8266Dma400KbpsMethod Neo400KbpsMethod; @@ -357,6 +428,7 @@ typedef NeoEsp8266DmaInvertedTm1829Method NeoTm1829InvertedMethod; typedef NeoEsp8266DmaInvertedTm1914Method NeoTm1914InvertedMethod; typedef NeoEsp8266DmaInvertedSk6812Method NeoLc8812InvertedMethod; typedef NeoEsp8266DmaInvertedApa106Method NeoApa106InvertedMethod; +typedef NeoEsp8266DmaInvertedIntertekMethod NeoInvertedIntertekMethod; typedef NeoEsp8266DmaInvertedWs2812xMethod Neo800KbpsInvertedMethod; typedef NeoEsp8266DmaInverted400KbpsMethod Neo400KbpsInvertedMethod; diff --git a/src/internal/NeoEsp8266I2sDmx512Method.h b/src/internal/NeoEsp8266I2sDmx512Method.h index 2c46078..531a7de 100644 --- a/src/internal/NeoEsp8266I2sDmx512Method.h +++ b/src/internal/NeoEsp8266I2sDmx512Method.h @@ -142,20 +142,20 @@ public: i2sBufferSize = i2sBufferSize + T_SPEED::BreakMabSize; - // size is rounded up to nearest I2sByteBoundarySize - i2sBufferSize = NeoUtil::RoundUp(i2sBufferSize, I2sByteBoundarySize); + // size is rounded up to nearest c_I2sByteBoundarySize + i2sBufferSize = NeoUtil::RoundUp(i2sBufferSize, c_I2sByteBoundarySize); - // size of a looping silent space rounded up to nearest I2sByteBoundarySize - size_t i2sZeroesSize = NeoUtil::RoundUp(T_SPEED::MtbpSize, I2sByteBoundarySize); + // size of a looping silent space rounded up to nearest c_I2sByteBoundarySize + size_t i2sResetSize = NeoUtil::RoundUp(T_SPEED::MtbpSize, c_I2sByteBoundarySize); - // protocol limits use of full block size to I2sByteBoundarySize - size_t is2BufMaxBlockSize = (c_maxDmaBlockSize / I2sByteBoundarySize) * I2sByteBoundarySize; + // protocol limits use of full block size to c_I2sByteBoundarySize + size_t is2BufMaxBlockSize = (c_maxDmaBlockSize / c_I2sByteBoundarySize) * c_I2sByteBoundarySize; _data = static_cast(malloc(_sizeData)); // first "slot" cleared due to protocol requiring it to be zero memset(_data, 0x00, 1); - AllocateI2s(i2sBufferSize, i2sZeroesSize, is2BufMaxBlockSize, T_SPEED::MtbpLevel); + AllocateI2s(i2sBufferSize, i2sResetSize, is2BufMaxBlockSize, T_SPEED::MtbpLevel); } NeoEsp8266I2sDmx512MethodBase([[maybe_unused]] uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : @@ -204,8 +204,7 @@ public: } FillBuffers(); - // toggle state so the ISR reacts - _dmaState = NeoDmaState_Pending; + WriteI2s(); } bool AlwaysUpdate() @@ -231,8 +230,6 @@ public: private: // given 11 sending bits per pixel byte, static const uint16_t I2sBitsPerPixelBytes = 11; - // i2s sends 4 byte elements, - static const uint16_t I2sByteBoundarySize = 4; const size_t _sizeData; // Size of '_data' buffer uint8_t* _data; // Holds LED color values diff --git a/src/internal/NeoEsp8266I2sMethodCore.cpp b/src/internal/NeoEsp8266I2sMethodCore.cpp index 87a2633..308081b 100644 --- a/src/internal/NeoEsp8266I2sMethodCore.cpp +++ b/src/internal/NeoEsp8266I2sMethodCore.cpp @@ -25,6 +25,7 @@ License along with NeoPixel. If not, see -------------------------------------------------------------------------*/ #include +#include "NeoUtil.h" #include "NeoEsp8266I2sMethodCore.h" #ifdef ARDUINO_ARCH_ESP8266 diff --git a/src/internal/NeoEsp8266I2sMethodCore.h b/src/internal/NeoEsp8266I2sMethodCore.h index 2884f38..db67126 100644 --- a/src/internal/NeoEsp8266I2sMethodCore.h +++ b/src/internal/NeoEsp8266I2sMethodCore.h @@ -71,8 +71,7 @@ enum NeoDmaState { NeoDmaState_Idle, NeoDmaState_Pending, - NeoDmaState_Sending, - NeoDmaState_Zeroing, + NeoDmaState_Sending }; const uint16_t c_maxDmaBlockSize = 4095; @@ -81,6 +80,13 @@ const uint8_t c_I2sPin = 3; // due to I2S hardware, the pin used is restricted t class NeoEsp8266I2sMethodCore { +private: + static const uint8_t c_StateBlockCount = 2; + static const size_t c_StateDataSize = 4; // mulitples of c_I2sByteBoundarySize + + // i2s sends 4 byte elements, + static const uint16_t c_I2sByteBoundarySize = 4; + protected: static NeoEsp8266I2sMethodCore* s_this; // for the ISR @@ -92,11 +98,16 @@ protected: size_t _i2sBufferSize; // total size of _i2sBuffer uint8_t* _i2sBuffer; // holds the DMA buffer that is referenced by _i2sBufDesc - size_t _i2sZeroesSize; // total size of _i2sZeroes - uint8_t* _i2sZeroes; + size_t _i2sIdleDataTotalSize; // total size of represented zeroes, mulitple uses of _i2sIdleData + size_t _i2sIdleDataSize; // size of _i2sIdleData + uint8_t* _i2sIdleData; uint16_t _is2BufMaxBlockSize; // max size based on size of a pixel of a single block + size_t GetSendSize() const + { + return _i2sBufferSize + _i2sIdleDataTotalSize; + } // This routine is called as soon as the DMA routine has something to tell us. All we // handle here is the RX_EOF_INT status, which indicate the DMA has sent a buffer whose @@ -112,39 +123,15 @@ protected: if ((slc_intr_status & SLCIRXEOF) && s_this) { - switch (s_this->_dmaState) + if (s_this->_dmaState != NeoDmaState_Idle) { - case NeoDmaState_Idle: - break; + // first two items are the state blocks + slc_queue_item* itemLoop = s_this->_i2sBufDesc; + slc_queue_item* itemLoopBreaker = itemLoop + 1; + // set to loop on idle items + itemLoopBreaker->next_link_ptr = itemLoop; - case NeoDmaState_Pending: - { - slc_queue_item* finished_item = (slc_queue_item*)SLCRXEDA; - - // data block has pending data waiting to send, prepare it - // point last state block to top - (finished_item + 1)->next_link_ptr = s_this->_i2sBufDesc; - - s_this->_dmaState = NeoDmaState_Sending; - } - break; - - case NeoDmaState_Sending: - { - slc_queue_item* finished_item = (slc_queue_item*)SLCRXEDA; - - // the data block had actual data sent - // point last state block to first state block thus - // just looping and not sending the data blocks - (finished_item + 1)->next_link_ptr = finished_item; - - s_this->_dmaState = NeoDmaState_Zeroing; - } - break; - - case NeoDmaState_Zeroing: s_this->_dmaState = NeoDmaState_Idle; - break; } } @@ -154,21 +141,37 @@ protected: NeoEsp8266I2sMethodCore() { }; - void AllocateI2s(const size_t i2sBufferSize, - const size_t i2sZeroesSize, + void AllocateI2s(const size_t i2sBufferSize, // expected multiples of c_I2sByteBoundarySize + const size_t i2sZeroesSize, // expected multiples of c_I2sByteBoundarySize const size_t is2BufMaxBlockSize, const uint8_t idleLevel) { _i2sBufferSize = i2sBufferSize; - _i2sZeroesSize = i2sZeroesSize; + _i2sIdleDataTotalSize = i2sZeroesSize; + _i2sIdleDataSize = _i2sIdleDataTotalSize; + + size_t countIdleQueueItems = 1; + if (_i2sIdleDataSize > 256) + { + // reuse a single idle data buffer of 256 with multiple dma slc_queue_items + countIdleQueueItems = _i2sIdleDataSize / 256 + 1; + _i2sIdleDataSize = 256; + } + else + { + _i2sIdleDataSize = NeoUtil::RoundUp(_i2sIdleDataSize, c_I2sByteBoundarySize); + } _is2BufMaxBlockSize = is2BufMaxBlockSize; _i2sBuffer = static_cast(malloc(_i2sBufferSize)); // no need to initialize it, it gets overwritten on every send - _i2sZeroes = static_cast(malloc(_i2sZeroesSize)); - memset(_i2sZeroes, idleLevel * 0xff, _i2sZeroesSize); + _i2sIdleData = static_cast(malloc(_i2sIdleDataSize)); + memset(_i2sIdleData, idleLevel * 0xff, _i2sIdleDataSize); + + _i2sBufDescCount = (_i2sBufferSize / _is2BufMaxBlockSize) + 1 + + countIdleQueueItems + + c_StateBlockCount; // need more for state/latch blocks - _i2sBufDescCount = (_i2sBufferSize / _is2BufMaxBlockSize) + 1 + 2; // need two more for state/latch blocks _i2sBufDesc = (slc_queue_item*)malloc(_i2sBufDescCount * sizeof(slc_queue_item)); s_this = this; // store this for the ISR @@ -183,7 +186,7 @@ protected: free(_i2sBuffer); free(_i2sBufDesc); - free(_i2sZeroes); + free(_i2sIdleData); } bool IsIdle() const @@ -191,6 +194,19 @@ protected: return (_dmaState == NeoDmaState_Idle); } + + void DmaItemInit(slc_queue_item* item, uint8_t* data, size_t sizeData, slc_queue_item* itemNext) + { + item->owner = 1; + item->eof = 0; // no need to trigger interrupt generally + item->sub_sof = 0; + item->datalen = sizeData; + item->blocksize = sizeData; + item->buf_ptr = data; + item->unused = 0; + item->next_link_ptr = itemNext; + } + void InitializeI2s(const uint32_t i2sClockDivisor, const uint32_t i2sBaseClockDivisor) { StopI2s(); @@ -198,52 +214,61 @@ protected: pinMode(c_I2sPin, FUNCTION_1); // I2S0_DATA uint8_t* is2Buffer = _i2sBuffer; - uint32_t is2BufferSize = _i2sBufferSize; - uint16_t indexDesc; + uint8_t* is2BufferEnd = _i2sBuffer + _i2sBufferSize; + uint32_t is2BufferSize; + uint16_t indexDesc = 0; + + // prepare the two state/latch descriptors + uint16_t stateDataSize = min(c_StateDataSize, _i2sIdleDataSize); + while (indexDesc < c_StateBlockCount) + { + DmaItemInit(&_i2sBufDesc[indexDesc], _i2sIdleData, stateDataSize, &(_i2sBufDesc[indexDesc + 1])); + + indexDesc++; + } // prepare main data block decriptors that point into our one static dma buffer - for (indexDesc = 0; indexDesc < (_i2sBufDescCount - 2); indexDesc++) + is2BufferSize = _i2sBufferSize; + while (is2Buffer < is2BufferEnd) { uint32_t blockSize = (is2BufferSize > _is2BufMaxBlockSize) ? _is2BufMaxBlockSize : is2BufferSize; - _i2sBufDesc[indexDesc].owner = 1; - _i2sBufDesc[indexDesc].eof = 0; // no need to trigger interrupt generally - _i2sBufDesc[indexDesc].sub_sof = 0; - _i2sBufDesc[indexDesc].datalen = blockSize; - _i2sBufDesc[indexDesc].blocksize = blockSize; - _i2sBufDesc[indexDesc].buf_ptr = is2Buffer; - _i2sBufDesc[indexDesc].unused = 0; - _i2sBufDesc[indexDesc].next_link_ptr = reinterpret_cast(&(_i2sBufDesc[indexDesc + 1])); + DmaItemInit(&_i2sBufDesc[indexDesc], is2Buffer, blockSize, &(_i2sBufDesc[indexDesc + 1])); is2Buffer += blockSize; is2BufferSize -= blockSize; + indexDesc++; } - // prepare the two state/latch descriptors - for (; indexDesc < _i2sBufDescCount; indexDesc++) + // last data item triggers EOF ISR + _i2sBufDesc[indexDesc - 1].eof = 1; + + // prepare idle block decriptors that point into our one idle dma buffer + is2BufferSize = _i2sIdleDataTotalSize; + while (indexDesc < _i2sBufDescCount) { - _i2sBufDesc[indexDesc].owner = 1; - _i2sBufDesc[indexDesc].eof = 0; // no need to trigger interrupt generally - _i2sBufDesc[indexDesc].sub_sof = 0; - _i2sBufDesc[indexDesc].datalen = sizeof(_i2sZeroes); - _i2sBufDesc[indexDesc].blocksize = sizeof(_i2sZeroes); - _i2sBufDesc[indexDesc].buf_ptr = _i2sZeroes; - _i2sBufDesc[indexDesc].unused = 0; - _i2sBufDesc[indexDesc].next_link_ptr = reinterpret_cast(&(_i2sBufDesc[indexDesc + 1])); + uint32_t blockSize = (is2BufferSize > _i2sIdleDataSize) ? _i2sIdleDataSize : is2BufferSize; + + DmaItemInit(&_i2sBufDesc[indexDesc], _i2sIdleData, blockSize, &(_i2sBufDesc[indexDesc + 1])); + + is2Buffer += blockSize; + is2BufferSize -= blockSize; + indexDesc++; } - // the first state block will trigger the interrupt - _i2sBufDesc[indexDesc - 2].eof = 1; + // the last item will loop to the first item + _i2sBufDesc[indexDesc - 1].next_link_ptr = reinterpret_cast(&(_i2sBufDesc[0])); + // the last state block will loop to the first state block by defualt - _i2sBufDesc[indexDesc - 1].next_link_ptr = reinterpret_cast(&(_i2sBufDesc[indexDesc - 2])); + _i2sBufDesc[c_StateBlockCount - 1].next_link_ptr = reinterpret_cast(&(_i2sBufDesc[0])); // setup the rest of i2s DMA // ETS_SLC_INTR_DISABLE(); - // start off in sending state as that is what it will be all setup to be + // start off in idel state as that is what it will be all setup to be // for the interrupt - _dmaState = NeoDmaState_Sending; + _dmaState = NeoDmaState_Idle; SLCC0 |= SLCRXLR | SLCTXLR; SLCC0 &= ~(SLCRXLR | SLCTXLR); @@ -301,6 +326,18 @@ protected: I2SC |= I2STXS; // Start transmission } + void WriteI2s() + { + // first two items are the state blocks + slc_queue_item* itemLoopBreaker = &(_i2sBufDesc[1]); + slc_queue_item* itemData = itemLoopBreaker + 1; + + // set to NOT loop on idle items + itemLoopBreaker->next_link_ptr = itemData; + + _dmaState = NeoDmaState_Sending; + } + void StopI2s() { ETS_SLC_INTR_DISABLE(); diff --git a/src/internal/NeoEsp8266UartMethod.h b/src/internal/NeoEsp8266UartMethod.h index dd3018c..3dd30a1 100644 --- a/src/internal/NeoEsp8266UartMethod.h +++ b/src/internal/NeoEsp8266UartMethod.h @@ -163,6 +163,8 @@ protected: // synchronous uart method // // used by NeoEsp8266UartMethodBase +// T_UARTFEATURE - (UartFeature0 | UartFeature1) +// T_UARTCONTEXT - (NeoEsp8266UartContext | NeoEsp8266UartInterruptContext) // template class NeoEsp8266Uart : public NeoEsp8266UartBase { @@ -217,6 +219,8 @@ protected: // every call to NeoPixelBus.Show() and must not be cached. // // used by NeoEsp8266UartMethodBase +// T_UARTFEATURE - (UartFeature0 | UartFeature1) +// T_UARTCONTEXT - (NeoEsp8266UartContext | NeoEsp8266UartInterruptContext) // template class NeoEsp8266AsyncUart : public NeoEsp8266UartBase { @@ -348,6 +352,11 @@ public: // NeoEsp8266UartMethodBase is a light shell arround NeoEsp8266Uart or NeoEsp8266AsyncUart that // implements the methods needed to operate as a NeoPixelBus method. +// +// T_SPEED - (NeoEsp8266UartSpeed*) +// T_BASE - (NeoEsp8266Uart | NeoEsp8266AsyncUart) +// T_INVERT - (NeoEsp8266UartNotInverted | NeoEsp8266UartInverted) +// template class NeoEsp8266UartMethodBase: public T_BASE { diff --git a/src/internal/NeoEspBitBangMethod.cpp b/src/internal/NeoEspBitBangMethod.cpp index 27f1bac..93ae066 100644 --- a/src/internal/NeoEspBitBangMethod.cpp +++ b/src/internal/NeoEspBitBangMethod.cpp @@ -28,24 +28,67 @@ License along with NeoPixel. If not, see #include -// ESP32C3 I2S is not supported yet -#if !defined(CONFIG_IDF_TARGET_ESP32C3) - static inline uint32_t getCycleCount(void) { uint32_t ccount; + +#if defined(CONFIG_IDF_TARGET_ESP32C3) + __asm__ __volatile__("csrr %0,0x7e2":"=r" (ccount)); + //ccount = esp_cpu_get_ccount(); +#else __asm__ __volatile__("rsr %0,ccount":"=a" (ccount)); +#endif return ccount; } -void IRAM_ATTR NeoEspBitBangBase_send_pixels(uint8_t* pixels, uint8_t* end, uint8_t pin, uint32_t t0h, uint32_t t1h, uint32_t period) +void IRAM_ATTR neoEspBitBangWriteSpacingPixels(const uint8_t* pixels, + const uint8_t* end, + uint8_t pin, + uint32_t t0h, + uint32_t t1h, + uint32_t period, + size_t sizePixel, + uint32_t tSpacing, + bool invert) { - const uint32_t pinRegister = _BV(pin); + uint32_t setValue = _BV(pin); + uint32_t clearValue = _BV(pin); uint8_t mask = 0x80; uint8_t subpix = *pixels++; + uint8_t element = 0; uint32_t cyclesStart = 0; // trigger emediately uint32_t cyclesNext = 0; +#if defined(ARDUINO_ARCH_ESP32) +#if defined(CONFIG_IDF_TARGET_ESP32C3) + volatile uint32_t* setRegister = &GPIO.out_w1ts.val; + volatile uint32_t* clearRegister = &GPIO.out_w1tc.val; + setValue = _BV(pin); + clearValue = _BV(pin); +#else + volatile uint32_t* setRegister = &GPIO.out_w1ts; + volatile uint32_t* clearRegister = &GPIO.out_w1tc; +#endif // defined(CONFIG_IDF_TARGET_ESP32C3) +#else + uint32_t setRegister = PERIPHS_GPIO_BASEADDR + GPIO_OUT_W1TS_ADDRESS; + uint32_t clearRegister = PERIPHS_GPIO_BASEADDR + GPIO_OUT_W1TC_ADDRESS; + if (pin == 16) + { + setRegister = RTC_GPIO_OUT; + clearRegister = RTC_GPIO_OUT; + // reading AND writing RTC_GPIO_OUT is too slow inside the loop so + // we only do writing in the loop + clearValue = (READ_PERI_REG(RTC_GPIO_OUT) & (uint32)0xfffffffe); + setValue = clearValue | 1; + } +#endif // defined(ARDUINO_ARCH_ESP32) + + if (invert) + { + std::swap(setRegister, clearRegister); + std::swap(setValue, clearValue); + } + for (;;) { // do the checks here while we are waiting on time to pass @@ -61,9 +104,9 @@ void IRAM_ATTR NeoEspBitBangBase_send_pixels(uint8_t* pixels, uint8_t* end, uint // set pin state #if defined(ARDUINO_ARCH_ESP32) - GPIO.out_w1ts = pinRegister; + *setRegister = setValue; #else - GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinRegister); + WRITE_PERI_REG(setRegister, setValue); #endif // wait for the LOW @@ -71,9 +114,9 @@ void IRAM_ATTR NeoEspBitBangBase_send_pixels(uint8_t* pixels, uint8_t* end, uint // reset pin start #if defined(ARDUINO_ARCH_ESP32) - GPIO.out_w1tc = pinRegister; + *clearRegister = clearValue; #else - GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinRegister); + WRITE_PERI_REG(clearRegister, clearValue); #endif cyclesNext = cyclesStart; @@ -92,176 +135,22 @@ void IRAM_ATTR NeoEspBitBangBase_send_pixels(uint8_t* pixels, uint8_t* end, uint // reset mask to first bit and get the next byte mask = 0x80; subpix = *pixels++; - } - } -} -#if defined(ARDUINO_ARCH_ESP8266) -void IRAM_ATTR NeoEspBitBangBase_send_pixels_pin16(uint8_t *pixels, uint8_t *end, uint32_t t0h, uint32_t t1h, uint32_t period) -{ - uint8_t mask = 0x80; - uint8_t subpix = *pixels++; - uint32_t cyclesStart = 0; // trigger emediately - uint32_t cyclesNext = 0; - - // reading and writing RTC_GPIO_OUT is too slow inside the loop - uint32_t gpio_clear = (READ_PERI_REG(RTC_GPIO_OUT) & (uint32)0xfffffffe); - uint32_t gpio_set = gpio_clear | 1; - - for (;;) - { - // do the checks here while we are waiting on time to pass - uint32_t cyclesBit = t0h; - if (subpix & mask) - { - cyclesBit = t1h; - } - - // after we have done as much work as needed for this next bit - // now wait for the HIGH - while (((cyclesStart = getCycleCount()) - cyclesNext) < period); - - // set pin state - WRITE_PERI_REG(RTC_GPIO_OUT, gpio_set); - - // wait for the LOW - while ((getCycleCount() - cyclesStart) < cyclesBit); - - // reset pin start - WRITE_PERI_REG(RTC_GPIO_OUT, gpio_clear); - - cyclesNext = cyclesStart; - - // next bit - mask >>= 1; - if (mask == 0) - { - // no more bits to send in this byte - // check for another byte - if (pixels >= end) + // if pixel spacing is needed + if (tSpacing) { - // no more bytes to send so stop - break; + element++; + if (element == sizePixel) + { + element = 0; + + // wait for pixel spacing + while ((getCycleCount() - cyclesNext) < tSpacing); + } } - // reset mask to first bit and get the next byte - mask = 0x80; - subpix = *pixels++; - } - } -} -#endif // defined(ARDUINO_ARCH_ESP8266) - -void IRAM_ATTR NeoEspBitBangBase_send_pixels_inv(uint8_t* pixels, uint8_t* end, uint8_t pin, uint32_t t0h, uint32_t t1h, uint32_t period) -{ - 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 = t0h; - if (subpix & mask) - { - cyclesBit = t1h; - } - - // after we have done as much work as needed for this next bit - // now wait for the HIGH - while (((cyclesStart = getCycleCount()) - cyclesNext) < period); - - // set pin state -#if defined(ARDUINO_ARCH_ESP32) - GPIO.out_w1tc = pinRegister; -#else - GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinRegister); -#endif - - // wait for the LOW - while ((getCycleCount() - cyclesStart) < cyclesBit); - - // reset pin start -#if defined(ARDUINO_ARCH_ESP32) - GPIO.out_w1ts = pinRegister; -#else - GPIO_REG_WRITE(GPIO_OUT_W1TS_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++; } } } -#if defined(ARDUINO_ARCH_ESP8266) -void IRAM_ATTR NeoEspBitBangBase_send_pixels_inv_pin16(uint8_t *pixels, uint8_t *end, uint32_t t0h, uint32_t t1h, uint32_t period) -{ - uint8_t mask = 0x80; - uint8_t subpix = *pixels++; - uint32_t cyclesStart = 0; // trigger emediately - uint32_t cyclesNext = 0; - // reading and writing RTC_GPIO_OUT is too slow inside the loop - uint32_t gpio_clear = (READ_PERI_REG(RTC_GPIO_OUT) & (uint32)0xfffffffe); - uint32_t gpio_set = gpio_clear | 1; - - for (;;) - { - // do the checks here while we are waiting on time to pass - uint32_t cyclesBit = t0h; - if (subpix & mask) - { - cyclesBit = t1h; - } - - // after we have done as much work as needed for this next bit - // now wait for the HIGH - while (((cyclesStart = getCycleCount()) - cyclesNext) < period); - - // set pin state - WRITE_PERI_REG(RTC_GPIO_OUT, gpio_clear); - - // wait for the LOW - while ((getCycleCount() - cyclesStart) < cyclesBit); - - // reset pin start - WRITE_PERI_REG(RTC_GPIO_OUT, gpio_set); - - 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 // defined(ARDUINO_ARCH_ESP8266) -#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) #endif // defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) diff --git a/src/internal/NeoEspBitBangMethod.h b/src/internal/NeoEspBitBangMethod.h index 25ee665..1eab38d 100644 --- a/src/internal/NeoEspBitBangMethod.h +++ b/src/internal/NeoEspBitBangMethod.h @@ -28,221 +28,169 @@ License along with NeoPixel. If not, see #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) -// ESP32C3 I2S is not supported yet -#if !defined(CONFIG_IDF_TARGET_ESP32C3) - #if defined(ARDUINO_ARCH_ESP8266) #include #endif - +#if defined(CONFIG_IDF_TARGET_ESP32C3) +#define CYCLES_LOOPTEST (1) // adjustment due to loop exit test instruction cycles +#elif defined(CONFIG_IDF_TARGET_ESP32S3) +#define CYCLES_LOOPTEST (2) // adjustment due to loop exit test instruction cycles +#else #define CYCLES_LOOPTEST (4) // adjustment due to loop exit test instruction cycles +#endif -class NeoEspSpeedWs2811 +extern void neoEspBitBangWriteSpacingPixels(const uint8_t* pixels, + const uint8_t* end, + uint8_t pin, + uint32_t t0h, + uint32_t t1h, + uint32_t period, + size_t sizePixel, + uint32_t tSpacing, + bool invert); + + +class NeoEspNotInverted +{ +public: + const static uint8_t IdleLevel = LOW; +}; + +class NeoEspInverted +{ +public: + const static uint8_t IdleLevel = HIGH; +}; + +class NeoEspBitBangSpeedWs2811 { public: const static uint32_t T0H = (F_CPU / 3333333 - CYCLES_LOOPTEST); // 0.3us const static uint32_t T1H = (F_CPU / 1052632 - CYCLES_LOOPTEST); // 0.95us const static uint32_t Period = (F_CPU / 800000 - CYCLES_LOOPTEST); // 1.25us per bit + + static const uint32_t ResetTimeUs = 300; + const static uint32_t TInterPixel = 0; }; -class NeoEspSpeedTm1814 -{ -public: - const static uint32_t T0H = (F_CPU / 2916666 - CYCLES_LOOPTEST); // 0.35us - const static uint32_t T1H = (F_CPU / 1666666 - CYCLES_LOOPTEST); // 0.75us - const static uint32_t Period = (F_CPU / 800000 - CYCLES_LOOPTEST); // 1.25us per bit -}; - -class NeoEspSpeedTm1829 -{ -public: - const static uint32_t T0H = (F_CPU / 3333333 - CYCLES_LOOPTEST); // 0.3us - 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 NeoEspSpeed800Mhz +class NeoEspBitBangSpeedWs2812x { 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 + + static const uint32_t ResetTimeUs = 300; + const static uint32_t TInterPixel = 0; }; -class NeoEspSpeed400Mhz +class NeoEspBitBangSpeedSk6812 { 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); + 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 + + static const uint32_t ResetTimeUs = 80; + const static uint32_t TInterPixel = 0; }; -class NeoEspSpeedApa106 +// Tm1814 normal is inverted signal +class NeoEspBitBangSpeedTm1814 +{ +public: + const static uint32_t T0H = (F_CPU / 2916666 - CYCLES_LOOPTEST); // 0.35us + const static uint32_t T1H = (F_CPU / 1666666 - CYCLES_LOOPTEST); // 0.75us + const static uint32_t Period = (F_CPU / 800000 - CYCLES_LOOPTEST); // 1.25us per bit + + static const uint32_t ResetTimeUs = 200; + const static uint32_t TInterPixel = 0; +}; + +// Tm1829 normal is inverted signal +class NeoEspBitBangSpeedTm1829 +{ +public: + const static uint32_t T0H = (F_CPU / 3333333 - CYCLES_LOOPTEST); // 0.3us + 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 + + static const uint32_t ResetTimeUs = 200; + const static uint32_t TInterPixel = 0; +}; + +class NeoEspBitBangSpeed800Kbps +{ +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 + + static const uint32_t ResetTimeUs = 50; + const static uint32_t TInterPixel = 0; +}; + +class NeoEspBitBangSpeed400Kbps +{ +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); + + static const uint32_t ResetTimeUs = 50; + const static uint32_t TInterPixel = 0; +}; + +class NeoEspBitBangSpeedApa106 { public: const static uint32_t T0H = (F_CPU / 2857143 - CYCLES_LOOPTEST); // 0.35us const static uint32_t T1H = (F_CPU / 740741 - CYCLES_LOOPTEST); // 1.35 const static uint32_t Period = (F_CPU / 606061 - CYCLES_LOOPTEST); // 1.65us + + static const uint32_t ResetTimeUs = 50; + const static uint32_t TInterPixel = 0; }; -extern void NeoEspBitBangBase_send_pixels(uint8_t* pixels, uint8_t* end, uint8_t pin, uint32_t t0h, uint32_t t1h, uint32_t period); -extern void NeoEspBitBangBase_send_pixels_inv(uint8_t *pixels, uint8_t *end, uint8_t pin, uint32_t t0h, uint32_t t1h, uint32_t period); -#if defined(ARDUINO_ARCH_ESP8266) -extern void NeoEspBitBangBase_send_pixels_pin16(uint8_t *pixels, uint8_t *end, uint32_t t0h, uint32_t t1h, uint32_t period); -extern void NeoEspBitBangBase_send_pixels_inv_pin16(uint8_t *pixels, uint8_t *end, uint32_t t0h, uint32_t t1h, uint32_t period); -#endif - -class NeoEspPinset +class NeoEspBitBangSpeedIntertek { public: - const static uint8_t IdleLevel = LOW; + 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 - inline static void send_pixels_impl(uint8_t* pixels, uint8_t* end, uint8_t pin, uint32_t t0h, uint32_t t1h, uint32_t period) + const static uint32_t ResetTimeUs = 12470; + const static uint32_t TInterPixel = (F_CPU / 50000); // 20us +}; + + +template class NeoEspBitBangEncode : public T_SPEED, public T_INVERTED +{ +public: + static void WritePixels(uint8_t pin, + const uint8_t* data, + size_t sizeData, + size_t sizePixel) { -#if defined(ARDUINO_ARCH_ESP8266) - if (pin == 16) - NeoEspBitBangBase_send_pixels_pin16(pixels, end, t0h, t1h, period); - else - NeoEspBitBangBase_send_pixels(pixels, end, pin, t0h, t1h, period); -#else - NeoEspBitBangBase_send_pixels(pixels, end, pin, t0h, t1h, period); -#endif + neoEspBitBangWriteSpacingPixels(data, + data + sizeData, + pin, + T_SPEED::T0H, + T_SPEED::T1H, + T_SPEED::Period, + sizePixel, + T_SPEED::TInterPixel, + T_INVERTED::IdleLevel); } }; -class NeoEspPinsetInverted -{ -public: - const static uint8_t IdleLevel = HIGH; - - inline static void send_pixels_impl(uint8_t* pixels, uint8_t* end, uint8_t pin, uint32_t t0h, uint32_t t1h, uint32_t period) - { -#if defined(ARDUINO_ARCH_ESP8266) - if (pin == 16) - NeoEspBitBangBase_send_pixels_inv_pin16(pixels, end, t0h, t1h, period); - else - NeoEspBitBangBase_send_pixels_inv(pixels, end, pin, t0h, t1h, period); -#else - NeoEspBitBangBase_send_pixels_inv(pixels, end, pin, t0h, t1h, period); -#endif - } -}; - -template class NeoEspBitBangBase -{ -public: - static void send_pixels(uint8_t* pixels, uint8_t* end, uint8_t pin) - { - T_PINSET::send_pixels_impl(pixels, end, pin, T_SPEED::T0H, T_SPEED::T1H, T_SPEED::Period); - } -}; - -class NeoEspBitBangSpeedWs2811 : public NeoEspBitBangBase -{ -public: - static const uint32_t ResetTimeUs = 300; -}; - -class NeoEspBitBangSpeedWs2812x : public NeoEspBitBangBase -{ -public: - static const uint32_t ResetTimeUs = 300; -}; - -class NeoEspBitBangSpeedSk6812 : public NeoEspBitBangBase -{ -public: - static const uint32_t ResetTimeUs = 80; -}; - -// normal is inverted signal -class NeoEspBitBangSpeedTm1814 : public NeoEspBitBangBase -{ -public: - static const uint32_t ResetTimeUs = 200; -}; - -// normal is inverted signal -class NeoEspBitBangSpeedTm1829 : public NeoEspBitBangBase -{ -public: - static const uint32_t ResetTimeUs = 200; -}; - -class NeoEspBitBangSpeed800Kbps : public NeoEspBitBangBase -{ -public: - static const uint32_t ResetTimeUs = 50; -}; - -class NeoEspBitBangSpeed400Kbps : public NeoEspBitBangBase -{ -public: - static const uint32_t ResetTimeUs = 50; -}; - -class NeoEspBitBangSpeedApa106 : public NeoEspBitBangBase -{ -public: - static const uint32_t ResetTimeUs = 50; -}; - -class NeoEspBitBangInvertedSpeedWs2811 : public NeoEspBitBangBase -{ -public: - static const uint32_t ResetTimeUs = 300; -}; - -class NeoEspBitBangInvertedSpeedWs2812x : public NeoEspBitBangBase -{ -public: - static const uint32_t ResetTimeUs = 300; -}; - -class NeoEspBitBangInvertedSpeedSk6812 : public NeoEspBitBangBase -{ -public: - static const uint32_t ResetTimeUs = 80; -}; - -// normal is inverted signal, so inverted is normal -class NeoEspBitBangInvertedSpeedTm1814 : public NeoEspBitBangBase -{ -public: - static const uint32_t ResetTimeUs = 200; -}; - -// normal is inverted signal, so inverted is normal -class NeoEspBitBangInvertedSpeedTm1829 : public NeoEspBitBangBase -{ -public: - static const uint32_t ResetTimeUs = 200; -}; - -class NeoEspBitBangInvertedSpeed800Kbps : public NeoEspBitBangBase -{ -public: - static const uint32_t ResetTimeUs = 50; -}; - -class NeoEspBitBangInvertedSpeed400Kbps : public NeoEspBitBangBase -{ -public: - static const uint32_t ResetTimeUs = 50; -}; - -class NeoEspBitBangInvertedSpeedApa106 : public NeoEspBitBangBase -{ -public: - static const uint32_t ResetTimeUs = 50; -}; - -template class NeoEspBitBangMethodBase +template class NeoEspBitBangMethodBase { public: typedef NeoNoSettings SettingsObject; NeoEspBitBangMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _sizePixel(elementSize), _sizeData(pixelCount * elementSize + settingsSize), _pin(pin) { @@ -263,12 +211,12 @@ public: { uint32_t delta = micros() - _endTime; - return (delta >= T_SPEED::ResetTimeUs); + return (delta >= T_ENCODER::ResetTimeUs); } void Initialize() { - digitalWrite(_pin, T_PINSET::IdleLevel); + digitalWrite(_pin, T_ENCODER::IdleLevel); _endTime = micros(); } @@ -288,15 +236,18 @@ public: // Need 100% focus on instruction timing #if defined(ARDUINO_ARCH_ESP32) - delay(1); // required + // delay(1); // required ? portMUX_TYPE updateMux = portMUX_INITIALIZER_UNLOCKED; portENTER_CRITICAL(&updateMux); #else - noInterrupts(); + noInterrupts(); #endif - T_SPEED::send_pixels(_data, _data + _sizeData, _pin); + T_ENCODER::WritePixels(_pin, + _data, + _sizeData, + _sizePixel); #if defined(ARDUINO_ARCH_ESP32) portEXIT_CRITICAL(&updateMux); @@ -329,6 +280,7 @@ public: } private: + const size_t _sizePixel; // size of a pixel in _data const size_t _sizeData; // Size of '_data' buffer below const uint8_t _pin; // output pin number @@ -339,14 +291,15 @@ private: #if defined(ARDUINO_ARCH_ESP32) -typedef NeoEspBitBangMethodBase NeoEsp32BitBangWs2811Method; -typedef NeoEspBitBangMethodBase NeoEsp32BitBangWs2812xMethod; -typedef NeoEspBitBangMethodBase NeoEsp32BitBangSk6812Method; -typedef NeoEspBitBangMethodBase NeoEsp32BitBangTm1814Method; -typedef NeoEspBitBangMethodBase NeoEsp32BitBangTm1829Method; -typedef NeoEspBitBangMethodBase NeoEsp32BitBang800KbpsMethod; -typedef NeoEspBitBangMethodBase NeoEsp32BitBang400KbpsMethod; -typedef NeoEspBitBangMethodBase NeoEsp32BitBangApa106Method; +typedef NeoEspBitBangMethodBase> NeoEsp32BitBangWs2811Method; +typedef NeoEspBitBangMethodBase> NeoEsp32BitBangWs2812xMethod; +typedef NeoEspBitBangMethodBase> NeoEsp32BitBangSk6812Method; +typedef NeoEspBitBangMethodBase> NeoEsp32BitBangTm1814Method; +typedef NeoEspBitBangMethodBase> NeoEsp32BitBangTm1829Method; +typedef NeoEspBitBangMethodBase> NeoEsp32BitBang800KbpsMethod; +typedef NeoEspBitBangMethodBase> NeoEsp32BitBang400KbpsMethod; +typedef NeoEspBitBangMethodBase> NeoEsp32BitBangApa106Method; +typedef NeoEspBitBangMethodBase> NeoEsp32BitBangIntertekMethod; typedef NeoEsp32BitBangWs2812xMethod NeoEsp32BitBangWs2813Method; typedef NeoEsp32BitBang800KbpsMethod NeoEsp32BitBangWs2812Method; @@ -354,14 +307,15 @@ typedef NeoEsp32BitBangWs2812xMethod NeoEsp32BitBangWs2816Method; typedef NeoEsp32BitBangTm1814Method NeoEsp32BitBangTm1914Method; typedef NeoEsp32BitBangSk6812Method NeoEsp32BitBangLc8812Method; -typedef NeoEspBitBangMethodBase NeoEsp32BitBangWs2811InvertedMethod; -typedef NeoEspBitBangMethodBase NeoEsp32BitBangWs2812xInvertedMethod; -typedef NeoEspBitBangMethodBase NeoEsp32BitBangSk6812InvertedMethod; -typedef NeoEspBitBangMethodBase NeoEsp32BitBangTm1814InvertedMethod; -typedef NeoEspBitBangMethodBase NeoEsp32BitBangTm1829InvertedMethod; -typedef NeoEspBitBangMethodBase NeoEsp32BitBang800KbpsInvertedMethod; -typedef NeoEspBitBangMethodBase NeoEsp32BitBang400KbpsInvertedMethod; -typedef NeoEspBitBangMethodBase NeoEsp32BitBangApa106InvertedMethod; +typedef NeoEspBitBangMethodBase> NeoEsp32BitBangWs2811InvertedMethod; +typedef NeoEspBitBangMethodBase> NeoEsp32BitBangWs2812xInvertedMethod; +typedef NeoEspBitBangMethodBase> NeoEsp32BitBangSk6812InvertedMethod; +typedef NeoEspBitBangMethodBase> NeoEsp32BitBangTm1814InvertedMethod; +typedef NeoEspBitBangMethodBase> NeoEsp32BitBangTm1829InvertedMethod; +typedef NeoEspBitBangMethodBase> NeoEsp32BitBang800KbpsInvertedMethod; +typedef NeoEspBitBangMethodBase> NeoEsp32BitBang400KbpsInvertedMethod; +typedef NeoEspBitBangMethodBase> NeoEsp32BitBangApa106InvertedMethod; +typedef NeoEspBitBangMethodBase> NeoEsp32BitBangIntertekInvertedMethod; typedef NeoEsp32BitBangWs2812xInvertedMethod NeoEsp32BitBangWs2813InvertedMethod; typedef NeoEsp32BitBang800KbpsInvertedMethod NeoEsp32BitBangWs2812InvertedMethod; @@ -369,16 +323,17 @@ typedef NeoEsp32BitBangWs2812xInvertedMethod NeoEsp32BitBangWs2816InvertedMethod typedef NeoEsp32BitBangTm1814InvertedMethod NeoEsp32BitBangTm1914InvertedMethod; typedef NeoEsp32BitBangSk6812InvertedMethod NeoEsp32BitBangLc8812InvertedMethod; -#else +#else // defined(ARDUINO_ARCH_ESP8266) -typedef NeoEspBitBangMethodBase NeoEsp8266BitBangWs2811Method; -typedef NeoEspBitBangMethodBase NeoEsp8266BitBangWs2812xMethod; -typedef NeoEspBitBangMethodBase NeoEsp8266BitBangSk6812Method; -typedef NeoEspBitBangMethodBase NeoEsp8266BitBangTm1814Method; -typedef NeoEspBitBangMethodBase NeoEsp8266BitBangTm1829Method; -typedef NeoEspBitBangMethodBase NeoEsp8266BitBang800KbpsMethod; -typedef NeoEspBitBangMethodBase NeoEsp8266BitBang400KbpsMethod; -typedef NeoEspBitBangMethodBase NeoEsp8266BitBangApa106Method; +typedef NeoEspBitBangMethodBase> NeoEsp8266BitBangWs2811Method; +typedef NeoEspBitBangMethodBase> NeoEsp8266BitBangWs2812xMethod; +typedef NeoEspBitBangMethodBase> NeoEsp8266BitBangSk6812Method; +typedef NeoEspBitBangMethodBase> NeoEsp8266BitBangTm1814Method; +typedef NeoEspBitBangMethodBase> NeoEsp8266BitBangTm1829Method; +typedef NeoEspBitBangMethodBase> NeoEsp8266BitBang800KbpsMethod; +typedef NeoEspBitBangMethodBase> NeoEsp8266BitBang400KbpsMethod; +typedef NeoEspBitBangMethodBase> NeoEsp8266BitBangApa106Method; +typedef NeoEspBitBangMethodBase> NeoEsp8266BitBangIntertekMethod; typedef NeoEsp8266BitBangWs2812xMethod NeoEsp8266BitBangWs2813Method; typedef NeoEsp8266BitBang800KbpsMethod NeoEsp8266BitBangWs2812Method; @@ -386,14 +341,15 @@ typedef NeoEsp8266BitBangWs2812xMethod NeoEsp8266BitBangWs2816Method; typedef NeoEsp8266BitBangTm1814Method NeoEsp8266BitBangTm1914Method; typedef NeoEsp8266BitBangSk6812Method NeoEsp8266BitBangLc8812Method; -typedef NeoEspBitBangMethodBase NeoEsp8266BitBangWs2811InvertedMethod; -typedef NeoEspBitBangMethodBase NeoEsp8266BitBangWs2812xInvertedMethod; -typedef NeoEspBitBangMethodBase NeoEsp8266BitBangSk6812InvertedMethod; -typedef NeoEspBitBangMethodBase NeoEsp8266BitBangTm1814InvertedMethod; -typedef NeoEspBitBangMethodBase NeoEsp8266BitBangTm1829InvertedMethod; -typedef NeoEspBitBangMethodBase NeoEsp8266BitBang800KbpsInvertedMethod; -typedef NeoEspBitBangMethodBase NeoEsp8266BitBang400KbpsInvertedMethod; -typedef NeoEspBitBangMethodBase NeoEsp8266BitBangApa106InvertedMethod; +typedef NeoEspBitBangMethodBase> NeoEsp8266BitBangWs2811InvertedMethod; +typedef NeoEspBitBangMethodBase> NeoEsp8266BitBangWs2812xInvertedMethod; +typedef NeoEspBitBangMethodBase> NeoEsp8266BitBangSk6812InvertedMethod; +typedef NeoEspBitBangMethodBase> NeoEsp8266BitBangTm1814InvertedMethod; +typedef NeoEspBitBangMethodBase> NeoEsp8266BitBangTm1829InvertedMethod; +typedef NeoEspBitBangMethodBase> NeoEsp8266BitBang800KbpsInvertedMethod; +typedef NeoEspBitBangMethodBase> NeoEsp8266BitBang400KbpsInvertedMethod; +typedef NeoEspBitBangMethodBase> NeoEsp8266BitBangApa106InvertedMethod; +typedef NeoEspBitBangMethodBase> NeoEsp8266BitBangIntertekInvertedMethod; typedef NeoEsp8266BitBangWs2812xInvertedMethod NeoEsp8266BitBangWs2813InvertedMethod; typedef NeoEsp8266BitBang800KbpsInvertedMethod NeoEsp8266BitBangWs2812InvertedMethod; @@ -401,9 +357,8 @@ typedef NeoEsp8266BitBangWs2812xInvertedMethod NeoEsp8266BitBangWs2816InvertedMe typedef NeoEsp8266BitBangTm1814InvertedMethod NeoEsp8266BitBangTm1914InvertedMethod; typedef NeoEsp8266BitBangSk6812InvertedMethod NeoEsp8266BitBangLc8812InvertedMethod; -#endif +#endif // defined(ARDUINO_ARCH_ESP32) // ESP bitbang doesn't have defaults and should avoided except for testing -#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) #endif // defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)