Skip to content

Commit 4995f05

Browse files
committed
Fix ESP8266 DMA off-by-one
Shim in Makuna/NeoPixelBus#894 until approved by upstream. Fixes wled#4906 and wled#5136.
1 parent a9a2b83 commit 4995f05

File tree

4 files changed

+138
-0
lines changed

4 files changed

+138
-0
lines changed
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*-------------------------------------------------------------------------
2+
NeoPixel library helper functions for Esp8266.
3+
4+
FIXED VERSION FROM https://github.com/Makuna/NeoPixelBus/pull/894
5+
This library will overlay/shadow the base version from NeoPixelBus
6+
7+
Written by Michael C. Miller.
8+
Thanks to g3gg0.de for porting the initial DMA support which lead to this.
9+
Thanks to github/cnlohr for the original work on DMA support, which opend
10+
all our minds to a better way (located at https://github.com/cnlohr/esp8266ws2812i2s).
11+
12+
I invest time and resources providing this open source code,
13+
please support me by donating (see https://github.com/Makuna/NeoPixelBus)
14+
15+
-------------------------------------------------------------------------
16+
This file is part of the Makuna/NeoPixelBus library.
17+
18+
NeoPixelBus is free software: you can redistribute it and/or modify
19+
it under the terms of the GNU Lesser General Public License as
20+
published by the Free Software Foundation, either version 3 of
21+
the License, or (at your option) any later version.
22+
23+
NeoPixelBus is distributed in the hope that it will be useful,
24+
but WITHOUT ANY WARRANTY; without even the implied warranty of
25+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26+
GNU Lesser General Public License for more details.
27+
28+
You should have received a copy of the GNU Lesser General Public
29+
License along with NeoPixel. If not, see
30+
<http://www.gnu.org/licenses/>.
31+
-------------------------------------------------------------------------*/
32+
33+
#pragma once
34+
35+
#ifdef ARDUINO_ARCH_ESP8266
36+
#include "internal/methods/NeoEsp8266DmaMethod.h"
37+
38+
template<typename T_PATTERN> class NeoEsp8266Dma3StepEncodeFixed : public T_PATTERN
39+
{
40+
public:
41+
const static size_t DmaBitsPerPixelBit = 3; // 3 step cadence, matches encoding
42+
43+
static size_t SpacingPixelSize(size_t sizePixel)
44+
{
45+
return sizePixel;
46+
}
47+
48+
static void FillBuffers(uint8_t* i2sBuffer,
49+
const uint8_t* data,
50+
size_t sizeData,
51+
[[maybe_unused]] size_t sizePixel)
52+
{
53+
const uint8_t SrcBitMask = 0x80;
54+
const size_t BitsInSample = sizeof(uint32_t) * 8;
55+
56+
uint32_t* pDma = reinterpret_cast<uint32_t*>(i2sBuffer);
57+
uint32_t dmaValue = 0;
58+
uint8_t destBitsLeft = BitsInSample;
59+
60+
const uint8_t* pSrc = data;
61+
const uint8_t* pEnd = pSrc + sizeData;
62+
63+
while (pSrc < pEnd)
64+
{
65+
uint8_t value = *(pSrc++);
66+
67+
for (uint8_t bitSrc = 0; bitSrc < 8; bitSrc++)
68+
{
69+
const uint16_t Bit = ((value & SrcBitMask) ? T_PATTERN::OneBit3Step : T_PATTERN::ZeroBit3Step);
70+
71+
if (destBitsLeft > 3)
72+
{
73+
destBitsLeft -= 3;
74+
dmaValue |= Bit << destBitsLeft;
75+
76+
#if defined(NEO_DEBUG_DUMP_I2S_BUFFER)
77+
NeoUtil::PrintBin<uint32_t>(dmaValue);
78+
Serial.print(" < ");
79+
Serial.println(destBitsLeft);
80+
#endif
81+
}
82+
else if (destBitsLeft <= 3)
83+
{
84+
uint8_t bitSplit = (3 - destBitsLeft);
85+
dmaValue |= Bit >> bitSplit;
86+
87+
#if defined(NEO_DEBUG_DUMP_I2S_BUFFER)
88+
NeoUtil::PrintBin<uint32_t>(dmaValue);
89+
Serial.print(" > ");
90+
Serial.println(bitSplit);
91+
#endif
92+
// next dma value, store and reset
93+
*(pDma++) = dmaValue;
94+
dmaValue = 0;
95+
96+
destBitsLeft = BitsInSample - bitSplit;
97+
if (bitSplit)
98+
{
99+
dmaValue |= Bit << destBitsLeft;
100+
}
101+
102+
#if defined(NEO_DEBUG_DUMP_I2S_BUFFER)
103+
NeoUtil::PrintBin<uint32_t>(dmaValue);
104+
Serial.print(" v ");
105+
Serial.println(bitSplit);
106+
#endif
107+
}
108+
109+
// Next
110+
value <<= 1;
111+
}
112+
}
113+
// store the remaining bits
114+
if (destBitsLeft != BitsInSample) *pDma++ = dmaValue;
115+
}
116+
};
117+
118+
// Abuse explict specialization to overlay the methods
119+
template<> class NeoEsp8266Dma3StepEncode<NeoEsp8266DmaNormalPattern> : public NeoEsp8266Dma3StepEncodeFixed<NeoEsp8266DmaNormalPattern> {};
120+
template<> class NeoEsp8266Dma3StepEncode<NeoEsp8266DmaInvertedPattern> : public NeoEsp8266Dma3StepEncodeFixed<NeoEsp8266DmaInvertedPattern> {};
121+
122+
#endif

lib/NeoESP8266DMAFix/library.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "NeoESP8266DMAFix",
3+
"build": { "libArchive": false },
4+
"platforms": ["espressif8266"],
5+
"dependencies": [
6+
{
7+
"owner": "makuna",
8+
"name": "NeoPixelBus",
9+
"version": "2.8.3"
10+
}
11+
]
12+
}

platformio.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ lib_deps =
205205
ESPAsyncUDP
206206
ESP8266PWM
207207
${env.lib_deps}
208+
NeoESP8266DMAFix
208209

209210
;; compatibilty flags - same as 0.14.0 which seems to work better on some 8266 boards. Not using PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48
210211
build_flags_compat =

wled00/bus_wrapper.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
//#define NPB_CONF_4STEP_CADENCE
66
#include "NeoPixelBusLg.h"
7+
#ifdef ARDUINO_ARCH_ESP8266
8+
#include <NeoEsp8266DmaMethodFix.h>
9+
#endif
710

811
//Hardware SPI Pins
912
#define P_8266_HS_MOSI 13

0 commit comments

Comments
 (0)