Skip to content

Commit a0c55c6

Browse files
authored
Merge pull request #4484 from blazoncek/parallel-I2S
WWA strip support & parallel I2S for S2/S3 (bumping outputs from 5/4 to 12)
2 parents 386e2c6 + 77d7082 commit a0c55c6

File tree

15 files changed

+815
-675
lines changed

15 files changed

+815
-675
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ wled-update.sh
1515

1616
/build_output/
1717
/node_modules/
18+
/logs/
1819

1920
/wled00/extLibs
2021
/wled00/LittleFS

platformio.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ lib_compat_mode = strict
138138
lib_deps =
139139
fastled/FastLED @ 3.6.0
140140
IRremoteESP8266 @ 2.8.2
141-
makuna/NeoPixelBus @ 2.8.0
141+
makuna/NeoPixelBus @ 2.8.3
142142
#https://github.com/makuna/NeoPixelBus.git#CoreShaderBeta
143143
https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.4.0
144144
# for I2C interface

wled00/FX.h

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#pragma once
12
/*
23
WS2812FX.h - Library for WS2812 LED effects.
34
Harm Aldick - 2016
@@ -8,12 +9,15 @@
89
Adapted from code originally licensed under the MIT license
910
1011
Modified for WLED
12+
13+
Segment class/struct (c) 2022 Blaz Kristan (@blazoncek)
1114
*/
1215

1316
#ifndef WS2812FX_h
1417
#define WS2812FX_h
1518

1619
#include <vector>
20+
#include "wled.h"
1721

1822
#include "const.h"
1923
#include "bus_manager.h"
@@ -71,18 +75,15 @@ extern byte realtimeMode; // used in getMappedPixelIndex()
7175
/* each segment uses 82 bytes of SRAM memory, so if you're application fails because of
7276
insufficient memory, decreasing MAX_NUM_SEGMENTS may help */
7377
#ifdef ESP8266
74-
#define MAX_NUM_SEGMENTS 16
78+
#define MAX_NUM_SEGMENTS 16
7579
/* How much data bytes all segments combined may allocate */
7680
#define MAX_SEGMENT_DATA 5120
81+
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
82+
#define MAX_NUM_SEGMENTS 20
83+
#define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*512) // 10k by default (S2 is short on free RAM)
7784
#else
78-
#ifndef MAX_NUM_SEGMENTS
79-
#define MAX_NUM_SEGMENTS 32
80-
#endif
81-
#if defined(ARDUINO_ARCH_ESP32S2)
82-
#define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*768) // 24k by default (S2 is short on free RAM)
83-
#else
84-
#define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*1280) // 40k by default
85-
#endif
85+
#define MAX_NUM_SEGMENTS 32 // warning: going beyond 32 may consume too much RAM for stable operation
86+
#define MAX_SEGMENT_DATA (MAX_NUM_SEGMENTS*1280) // 40k by default
8687
#endif
8788

8889
/* How much data bytes each segment should max allocate to leave enough space for other segments,
@@ -571,6 +572,8 @@ typedef struct Segment {
571572
inline uint16_t groupLength() const { return grouping + spacing; }
572573
inline uint8_t getLightCapabilities() const { return _capabilities; }
573574
inline void deactivate() { setGeometry(0,0); }
575+
inline Segment &clearName() { if (name) free(name); name = nullptr; return *this; }
576+
inline Segment &setName(const String &name) { return setName(name.c_str()); }
574577

575578
inline static unsigned getUsedSegmentData() { return Segment::_usedSegmentData; }
576579
inline static void addUsedSegmentData(int len) { Segment::_usedSegmentData += len; }
@@ -593,6 +596,7 @@ typedef struct Segment {
593596
Segment &setOption(uint8_t n, bool val);
594597
Segment &setMode(uint8_t fx, bool loadDefaults = false);
595598
Segment &setPalette(uint8_t pal);
599+
Segment &setName(const char* name);
596600
uint8_t differs(const Segment& b) const;
597601
void refreshLightCapabilities();
598602

wled00/FX_fcn.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,20 @@ Segment &Segment::setPalette(uint8_t pal) {
649649
return *this;
650650
}
651651

652+
Segment &Segment::setName(const char *newName) {
653+
if (newName) {
654+
const int newLen = min(strlen(newName), (size_t)WLED_MAX_SEGNAME_LEN);
655+
if (newLen) {
656+
if (name) name = static_cast<char*>(realloc(name, newLen+1));
657+
else name = static_cast<char*>(malloc(newLen+1));
658+
if (name) strlcpy(name, newName, newLen+1);
659+
name[newLen] = 0;
660+
return *this;
661+
}
662+
}
663+
return clearName();
664+
}
665+
652666
// 2D matrix
653667
unsigned Segment::virtualWidth() const {
654668
unsigned groupLen = groupLength();
@@ -1311,6 +1325,34 @@ void WS2812FX::finalizeInit() {
13111325

13121326
_hasWhiteChannel = _isOffRefreshRequired = false;
13131327

1328+
unsigned digitalCount = 0;
1329+
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
1330+
// determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT)
1331+
unsigned maxLedsOnBus = 0;
1332+
for (const auto &bus : busConfigs) {
1333+
if (Bus::isDigital(bus.type) && !Bus::is2Pin(bus.type)) {
1334+
digitalCount++;
1335+
if (bus.count > maxLedsOnBus) maxLedsOnBus = bus.count;
1336+
}
1337+
}
1338+
DEBUG_PRINTF_P(PSTR("Maximum LEDs on a bus: %u\nDigital buses: %u\n"), maxLedsOnBus, digitalCount);
1339+
// we may remove 300 LEDs per bus limit when NeoPixelBus is updated beyond 2.9.0
1340+
if (maxLedsOnBus <= 300 && useParallelI2S) BusManager::useParallelOutput(); // must call before creating buses
1341+
else useParallelI2S = false; // enforce single I2S
1342+
#endif
1343+
1344+
// create buses/outputs
1345+
unsigned mem = 0;
1346+
digitalCount = 0;
1347+
for (const auto &bus : busConfigs) {
1348+
mem += bus.memUsage(Bus::isDigital(bus.type) && !Bus::is2Pin(bus.type) ? digitalCount++ : 0); // includes global buffer
1349+
if (mem <= MAX_LED_MEMORY) {
1350+
if (BusManager::add(bus) == -1) break;
1351+
} else DEBUG_PRINTF_P(PSTR("Out of LED memory! Bus %d (%d) #%u not created."), (int)bus.type, (int)bus.count, digitalCount);
1352+
}
1353+
busConfigs.clear();
1354+
busConfigs.shrink_to_fit();
1355+
13141356
//if busses failed to load, add default (fresh install, FS issue, ...)
13151357
if (BusManager::getNumBusses() == 0) {
13161358
DEBUG_PRINTLN(F("No busses, init default"));
@@ -1326,6 +1368,7 @@ void WS2812FX::finalizeInit() {
13261368

13271369
unsigned prevLen = 0;
13281370
unsigned pinsIndex = 0;
1371+
digitalCount = 0;
13291372
for (unsigned i = 0; i < WLED_MAX_BUSSES+WLED_MIN_VIRTUAL_BUSSES; i++) {
13301373
uint8_t defPin[OUTPUT_MAX_PINS];
13311374
// if we have less types than requested outputs and they do not align, use last known type to set current type
@@ -1390,9 +1433,11 @@ void WS2812FX::finalizeInit() {
13901433
if (Bus::isPWM(dataType) || Bus::isOnOff(dataType)) count = 1;
13911434
prevLen += count;
13921435
BusConfig defCfg = BusConfig(dataType, defPin, start, count, DEFAULT_LED_COLOR_ORDER, false, 0, RGBW_MODE_MANUAL_ONLY, 0, useGlobalLedBuffer);
1436+
mem += defCfg.memUsage(Bus::isDigital(dataType) && !Bus::is2Pin(dataType) ? digitalCount++ : 0);
13931437
if (BusManager::add(defCfg) == -1) break;
13941438
}
13951439
}
1440+
DEBUG_PRINTF_P(PSTR("LED buffer size: %uB/%uB\n"), mem, BusManager::memUsage());
13961441

13971442
_length = 0;
13981443
for (int i=0; i<BusManager::getNumBusses(); i++) {
@@ -1409,6 +1454,7 @@ void WS2812FX::finalizeInit() {
14091454
// This must be done after all buses have been created, as some kinds (parallel I2S) interact
14101455
bus->begin();
14111456
}
1457+
DEBUG_PRINTF_P(PSTR("Heap after buses: %d\n"), ESP.getFreeHeap());
14121458

14131459
Segment::maxWidth = _length;
14141460
Segment::maxHeight = 1;

0 commit comments

Comments
 (0)