Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -1087,8 +1087,11 @@ custom_usermods = * ; Expands to all usermods in usermods folder

;; Core HUB75 flags - common to every HUB75 build
build_flags =
-D WLED_ENABLE_HUB75MATRIX -D NO_GFX
-D WLED_ENABLE_HUB75MATRIX
-D NO_GFX ; disable GFX library usage, we do not need it
-D NO_FAST_FUNCTIONS ; no fast line drawing functions (used by GFX, saves 1k of flash)
-D NO_CIE1931 ;; disable driver-internal gamma correction
; -D WLED_HUB75_EXTRA_BUFFER ; enable extra drawing buffer (use in case you see image tearing on large setups >8000 LEDs)
-D WLED_DEBUG_BUS
-D LED_TYPES=TYPE_HUB75MATRIX_HS
; -D WLED_DEBUG
Expand Down
4 changes: 1 addition & 3 deletions wled00/FX_fcn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,9 @@ bool Segment::allocateData(size_t len) {
if (len == 0) return false; // nothing to do
if (data && _dataLen >= len) { // already allocated enough (reduce fragmentation)
if (call == 0) {
if (_dataLen < FAIR_DATA_PER_SEG) { // segment data is small
//DEBUG_PRINTF_P(PSTR("-- Clearing data (%d): %p\n"), len, this);
memset(data, 0, len); // erase buffer if called during effect initialisation
return true; // no need to reallocate
}
}
else
return true;
Expand Down Expand Up @@ -196,7 +194,7 @@ void Segment::deallocateData() {
DEBUG_PRINTF_P(PSTR("---- Released data (%p): inconsistent UsedSegmentData (%d/%d), cowardly refusing to free nothing.\n"), this, _dataLen, Segment::getUsedSegmentData());
}
data = nullptr;
Segment::addUsedSegmentData(_dataLen <= Segment::getUsedSegmentData() ? -_dataLen : -Segment::getUsedSegmentData());
Segment::addUsedSegmentData(-_dataLen); // addUsedSegmentData guards agains negative and sets zero if underrun so this is safe
_dataLen = 0;
}

Expand Down
39 changes: 29 additions & 10 deletions wled00/bus_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1067,8 +1067,9 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc.
_valid = true;
display->clearScreen(); // initially clear the screen buffer
DEBUGBUS_PRINTLN("MatrixPanel_I2S_DMA clear ok");

#ifdef WLED_HUB75_EXTRA_BUFFER
if (_ledBuffer) d_free(_ledBuffer); // should not happen
#endif
if (_ledsDirty) d_free(_ledsDirty); // should not happen
DEBUGBUS_PRINTLN("MatrixPanel_I2S_DMA allocate memory");
_ledsDirty = (byte*) d_malloc(getBitArrayBytes(_len)); // create LEDs dirty bits
Expand All @@ -1083,9 +1084,10 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc.
return; // fail is we cannot get memory for the buffer
}
setBitArray(_ledsDirty, _len, false); // reset dirty bits

#ifdef WLED_HUB75_EXTRA_BUFFER
// create LEDs buffer (initialized to BLACK), prefer DRAM if enough heap is available (faster in case global _pixels buffer is in PSRAM as not both will fit the cache)
_ledBuffer = static_cast<CRGB*>(allocate_buffer(_len * sizeof(CRGB), BFRALLOC_PREFER_DRAM | BFRALLOC_CLEAR));
#endif
}

PANEL_CHAIN_TYPE chainType = CHAIN_NONE; // default for quarter-scan panels that do not use chaining
Expand Down Expand Up @@ -1132,27 +1134,34 @@ BusHub75Matrix::BusHub75Matrix(const BusConfig &bc) : Bus(bc.type, bc.start, bc.

DEBUGBUS_PRINT(F("MatrixPanel_I2S_DMA "));
DEBUGBUS_PRINTF_P(PSTR("%sstarted, width=%u, %u pixels.\n"), _valid? "":"not ", _panelWidth, _len);

if (_ledBuffer != nullptr) DEBUGBUS_PRINTLN(F("MatrixPanel_I2S_DMA LEDS buffer enabled."));
if (_ledsDirty != nullptr) DEBUGBUS_PRINTLN(F("MatrixPanel_I2S_DMA LEDS dirty bit optimization enabled."));
if ((_ledBuffer != nullptr) || (_ledsDirty != nullptr)) {
DEBUGBUS_PRINT(F("MatrixPanel_I2S_DMA LEDS buffer uses "));
DEBUGBUS_PRINT((_ledBuffer? _len*sizeof(CRGB) :0) + (_ledsDirty? getBitArrayBytes(_len) :0));
DEBUGBUS_PRINTLN(F(" bytes."));
#ifdef WLED_HUB75_EXTRA_BUFFER
if (_ledBuffer != nullptr) {
DEBUGBUS_PRINTLN(F("MatrixPanel_I2S_DMA extra buffer enabled."));
DEBUGBUS_PRINT(F("Extra buffer uses "));
DEBUGBUS_PRINT(_len*sizeof(CRGB));
}
#endif
if (_ledsDirty != nullptr) {
DEBUGBUS_PRINTLN(F("MatrixPanel_I2S_DMA LEDS dirty bit optimization enabled."));
DEBUGBUS_PRINT(F("Dirty buffer uses "));
DEBUGBUS_PRINT((getBitArrayBytes(_len)));
}
}

void IRAM_ATTR BusHub75Matrix::setPixelColor(unsigned pix, uint32_t c) {
if (!_valid) return; // note: no need to check pix >= _len as that is checked in containsPixel()
// if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT

#ifdef WLED_HUB75_EXTRA_BUFFER
if (_ledBuffer) {
CRGB fastled_col = CRGB(c);
if (_ledBuffer[pix] != fastled_col) {
_ledBuffer[pix] = fastled_col;
setBitInArray(_ledsDirty, pix, true); // flag pixel as "dirty"
}
}
#else
if (false) {} // placeholder
#endif
else {
if ((c == IS_BLACK) && (getBitFromArray(_ledsDirty, pix) == false)) return; // ignore black if pixel is already black
setBitInArray(_ledsDirty, pix, c != IS_BLACK); // dirty = true means "color is not BLACK"
Expand All @@ -1175,10 +1184,14 @@ void IRAM_ATTR BusHub75Matrix::setPixelColor(unsigned pix, uint32_t c) {

uint32_t BusHub75Matrix::getPixelColor(unsigned pix) const {
if (!_valid) return IS_BLACK; // note: no need to check pix >= _len as that is checked in containsPixel()
#ifdef WLED_HUB75_EXTRA_BUFFER
if (_ledBuffer)
return uint32_t(_ledBuffer[pix]); // fastled-slim already returns RGB, no need to mask out the upper byte
else
return getBitFromArray(_ledsDirty, pix) ? IS_DARKGREY: IS_BLACK; // just a hack - we only know if the pixel is black or not
#else
return getBitFromArray(_ledsDirty, pix) ? IS_DARKGREY: IS_BLACK; // just a hack - we only know if the pixel is black or not
#endif
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

void BusHub75Matrix::setBrightness(uint8_t b) {
Expand All @@ -1188,6 +1201,7 @@ void BusHub75Matrix::setBrightness(uint8_t b) {
}

void BusHub75Matrix::show(void) {
#ifdef WLED_HUB75_EXTRA_BUFFER
if (!_valid) return;
if (_ledBuffer) {
// write out buffered LEDs
Expand All @@ -1207,6 +1221,9 @@ void BusHub75Matrix::show(void) {
}
setBitArray(_ledsDirty, _len, false); // buffer shown - reset all dirty bits
}
#endif
// show() is a no-op if WLED_HUB75_EXTRA_BUFFER is not defined: pixels were already written directly in setPixelColor(),
// the DMA driver handles continuous refresh asynchronously
}

void BusHub75Matrix::cleanup() {
Expand All @@ -1224,7 +1241,9 @@ void BusHub75Matrix::cleanup() {
#else // runtime reconfiguration is not working on -S3, request reboot from user instead
errorFlag = ERR_REBOOT_NEEDED;
#endif
#ifdef WLED_HUB75_EXTRA_BUFFER
if (_ledBuffer != nullptr) d_free(_ledBuffer); _ledBuffer = nullptr;
#endif
if (_ledsDirty != nullptr) d_free(_ledsDirty); _ledsDirty = nullptr;
}

Expand Down
2 changes: 1 addition & 1 deletion wled00/const.h
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ static_assert(WLED_MAX_BUSSES <= 32, "WLED_MAX_BUSSES exceeds hard limit");
#elif defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C61)
#define MAX_LEDS 4096
#else
#define MAX_LEDS 16384 // classic esp32, S3 and P4 can take more
#define MAX_LEDS 16384 // note: P4/S3 can take more, 24576 is already unstable on S3 using HUB75 (DMA buffers)
#endif
#endif

Expand Down
4 changes: 2 additions & 2 deletions wled00/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -927,8 +927,8 @@ void *allocate_buffer(size_t size, uint32_t type) {
buffer = d_malloc(size);
#else
if (type & BFRALLOC_PREFER_DRAM) {
if (getContiguousFreeHeap() < 3*(MIN_HEAP_SIZE/2) + size && size > PSRAM_THRESHOLD)
buffer = p_malloc(size); // prefer PSRAM for large allocations & when DRAM is low
if ((getContiguousFreeHeap() < 3*(MIN_HEAP_SIZE/2) + size && size > PSRAM_THRESHOLD) || size > 2*PSRAM_THRESHOLD)
buffer = p_malloc(size); // prefer PSRAM for large allocations & when DRAM is low or when buffer is huge
else
buffer = d_malloc(size); // allocate in DRAM if enough free heap is available, PSRAM as fallback
}
Expand Down
Loading