Fix ESP8266 DMA off-by-one
Shim in https://github.com/Makuna/NeoPixelBus/pull/894 until approved by upstream. Fixes #4906 and #5136.
This commit is contained in:
122
lib/NeoESP8266DMAFix/include/NeoEsp8266DmaMethodFix.h
Normal file
122
lib/NeoESP8266DMAFix/include/NeoEsp8266DmaMethodFix.h
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
NeoPixel library helper functions for Esp8266.
|
||||||
|
|
||||||
|
FIXED VERSION FROM https://github.com/Makuna/NeoPixelBus/pull/894
|
||||||
|
This library will overlay/shadow the base version from NeoPixelBus
|
||||||
|
|
||||||
|
Written by Michael C. Miller.
|
||||||
|
Thanks to g3gg0.de for porting the initial DMA support which lead to this.
|
||||||
|
Thanks to github/cnlohr for the original work on DMA support, which opend
|
||||||
|
all our minds to a better way (located at https://github.com/cnlohr/esp8266ws2812i2s).
|
||||||
|
|
||||||
|
I invest time and resources providing this open source code,
|
||||||
|
please support me by donating (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
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
|
#include "internal/methods/NeoEsp8266DmaMethod.h"
|
||||||
|
|
||||||
|
template<typename T_PATTERN> class NeoEsp8266Dma3StepEncodeFixed : public T_PATTERN
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const static size_t DmaBitsPerPixelBit = 3; // 3 step cadence, matches encoding
|
||||||
|
|
||||||
|
static size_t SpacingPixelSize(size_t sizePixel)
|
||||||
|
{
|
||||||
|
return sizePixel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FillBuffers(uint8_t* i2sBuffer,
|
||||||
|
const uint8_t* data,
|
||||||
|
size_t sizeData,
|
||||||
|
[[maybe_unused]] size_t sizePixel)
|
||||||
|
{
|
||||||
|
const uint8_t SrcBitMask = 0x80;
|
||||||
|
const size_t BitsInSample = sizeof(uint32_t) * 8;
|
||||||
|
|
||||||
|
uint32_t* pDma = reinterpret_cast<uint32_t*>(i2sBuffer);
|
||||||
|
uint32_t dmaValue = 0;
|
||||||
|
uint8_t destBitsLeft = BitsInSample;
|
||||||
|
|
||||||
|
const uint8_t* pSrc = data;
|
||||||
|
const uint8_t* pEnd = pSrc + sizeData;
|
||||||
|
|
||||||
|
while (pSrc < pEnd)
|
||||||
|
{
|
||||||
|
uint8_t value = *(pSrc++);
|
||||||
|
|
||||||
|
for (uint8_t bitSrc = 0; bitSrc < 8; bitSrc++)
|
||||||
|
{
|
||||||
|
const uint16_t Bit = ((value & SrcBitMask) ? T_PATTERN::OneBit3Step : T_PATTERN::ZeroBit3Step);
|
||||||
|
|
||||||
|
if (destBitsLeft > 3)
|
||||||
|
{
|
||||||
|
destBitsLeft -= 3;
|
||||||
|
dmaValue |= Bit << destBitsLeft;
|
||||||
|
|
||||||
|
#if defined(NEO_DEBUG_DUMP_I2S_BUFFER)
|
||||||
|
NeoUtil::PrintBin<uint32_t>(dmaValue);
|
||||||
|
Serial.print(" < ");
|
||||||
|
Serial.println(destBitsLeft);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (destBitsLeft <= 3)
|
||||||
|
{
|
||||||
|
uint8_t bitSplit = (3 - destBitsLeft);
|
||||||
|
dmaValue |= Bit >> bitSplit;
|
||||||
|
|
||||||
|
#if defined(NEO_DEBUG_DUMP_I2S_BUFFER)
|
||||||
|
NeoUtil::PrintBin<uint32_t>(dmaValue);
|
||||||
|
Serial.print(" > ");
|
||||||
|
Serial.println(bitSplit);
|
||||||
|
#endif
|
||||||
|
// next dma value, store and reset
|
||||||
|
*(pDma++) = dmaValue;
|
||||||
|
dmaValue = 0;
|
||||||
|
|
||||||
|
destBitsLeft = BitsInSample - bitSplit;
|
||||||
|
if (bitSplit)
|
||||||
|
{
|
||||||
|
dmaValue |= Bit << destBitsLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(NEO_DEBUG_DUMP_I2S_BUFFER)
|
||||||
|
NeoUtil::PrintBin<uint32_t>(dmaValue);
|
||||||
|
Serial.print(" v ");
|
||||||
|
Serial.println(bitSplit);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next
|
||||||
|
value <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// store the remaining bits
|
||||||
|
if (destBitsLeft != BitsInSample) *pDma++ = dmaValue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Abuse explict specialization to overlay the methods
|
||||||
|
template<> class NeoEsp8266Dma3StepEncode<NeoEsp8266DmaNormalPattern> : public NeoEsp8266Dma3StepEncodeFixed<NeoEsp8266DmaNormalPattern> {};
|
||||||
|
template<> class NeoEsp8266Dma3StepEncode<NeoEsp8266DmaInvertedPattern> : public NeoEsp8266Dma3StepEncodeFixed<NeoEsp8266DmaInvertedPattern> {};
|
||||||
|
|
||||||
|
#endif
|
||||||
12
lib/NeoESP8266DMAFix/library.json
Normal file
12
lib/NeoESP8266DMAFix/library.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "NeoESP8266DMAFix",
|
||||||
|
"build": { "libArchive": false },
|
||||||
|
"platforms": ["espressif8266"],
|
||||||
|
"dependencies": [
|
||||||
|
{
|
||||||
|
"owner": "makuna",
|
||||||
|
"name": "NeoPixelBus",
|
||||||
|
"version": "2.8.3"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -220,6 +220,7 @@ lib_deps =
|
|||||||
ESPAsyncUDP
|
ESPAsyncUDP
|
||||||
ESP8266PWM
|
ESP8266PWM
|
||||||
${env.lib_deps}
|
${env.lib_deps}
|
||||||
|
NeoESP8266DMAFix
|
||||||
|
|
||||||
;; compatibilty flags - same as 0.14.0 which seems to work better on some 8266 boards. Not using PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48
|
;; compatibilty flags - same as 0.14.0 which seems to work better on some 8266 boards. Not using PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48
|
||||||
build_flags_compat =
|
build_flags_compat =
|
||||||
|
|||||||
@@ -4,6 +4,9 @@
|
|||||||
|
|
||||||
//#define NPB_CONF_4STEP_CADENCE
|
//#define NPB_CONF_4STEP_CADENCE
|
||||||
#include "NeoPixelBus.h"
|
#include "NeoPixelBus.h"
|
||||||
|
#ifdef ARDUINO_ARCH_ESP8266
|
||||||
|
#include <NeoEsp8266DmaMethodFix.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
//Hardware SPI Pins
|
//Hardware SPI Pins
|
||||||
#define P_8266_HS_MOSI 13
|
#define P_8266_HS_MOSI 13
|
||||||
|
|||||||
Reference in New Issue
Block a user