From 9b10436ea560fc43cd45e1b0a73943524f81838b Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Fri, 5 Jun 2026 20:25:30 -0400 Subject: [PATCH 01/31] Changes to provide proper config settings to rmt engine --- src/output/OutputRmtV5.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/output/OutputRmtV5.cpp b/src/output/OutputRmtV5.cpp index 7bc2c4f18..d17b3fbc4 100644 --- a/src/output/OutputRmtV5.cpp +++ b/src/output/OutputRmtV5.cpp @@ -187,6 +187,8 @@ void c_OutputRmt::Begin (OutputRmtConfig_t config, c_OutputCommon * _pParent ) ESP_ERROR_CHECK(rmt_new_simple_encoder(&encoder_cfg, &rmt_encoder_handle)); DEBUG_V(); + tx_config.flags.eot_level = OutputRmtConfig.idle_level == rmt_idle_level_t::RMT_IDLE_LEVEL_HIGH; + // reset the internal and external pointers to the start of the mem block ISR_ResetRmtBlockPointers (); // DEBUG_V(); @@ -251,6 +253,7 @@ void c_OutputRmt::GetStatus (ArduinoJson::JsonObject& jsonStatus) debugStatus["ISRpaused"] = ISRpaused; debugStatus["SendBlockIsrCounter"] = SendBlockIsrCounter; debugStatus["UnknownISRcounter"] = UnknownISRcounter; + debugStatus["WriteToBuffer"] = WriteToBuffer; #ifdef IncludeBufferData { @@ -486,7 +489,6 @@ bool c_OutputRmt::StartNewFrame () } // Stop the transmitter - rmt_disable(rmt_channel_handle); ISR_ResetRmtBlockPointers (); #ifdef USE_RMT_DEBUG_COUNTERS @@ -515,8 +517,13 @@ bool c_OutputRmt::StartNewFrame () // digitalWrite(42, LOW); // DEBUG_V("start the transmitter"); - rmt_enable(rmt_channel_handle); - rmt_transmit(rmt_channel_handle, rmt_encoder_handle, OutputRmtConfig.BufferStart, OutputRmtConfig.NumBytesInFrame, &tx_config); + // rmt_enable(rmt_channel_handle); + OutputRmtConfig.NumBytesInFrame = 9000; + // DEBUG_V(String("rmt_channel_handle: ") + String(uint32_t(rmt_channel_handle))); + // DEBUG_V(String("rmt_encoder_handle: ") + String(uint32_t(rmt_encoder_handle))); + // DEBUG_V(String(" BufferStart: ") + String(uint32_t(OutputRmtConfig.BufferStart))); + // DEBUG_V(String(" NumBytesInFrame: ") + String(uint32_t(OutputRmtConfig.NumBytesInFrame))); + ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_transmit(rmt_channel_handle, rmt_encoder_handle, OutputRmtConfig.BufferStart, OutputRmtConfig.NumBytesInFrame, &tx_config)); // rmt_set_gpio (OutputRmtConfig.RmtChannelId, rmt_mode_t::RMT_MODE_TX, OutputRmtConfig.DataPin, false); // digitalWrite(42, HIGH); From afc97906eea66b92d2d3a04314e1b33dd59de9e2 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Fri, 5 Jun 2026 20:28:20 -0400 Subject: [PATCH 02/31] Turned off debug counters --- include/output/OutputRmt.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/output/OutputRmt.hpp b/include/output/OutputRmt.hpp index 1c96cd585..668bddbec 100644 --- a/include/output/OutputRmt.hpp +++ b/include/output/OutputRmt.hpp @@ -171,7 +171,7 @@ inline void IRAM_ATTR ClearRmtInterrupts() rmt_item32_t *symbols, bool *done); c_OutputCommon * pParent = nullptr; -#define USE_RMT_DEBUG_COUNTERS +// #define USE_RMT_DEBUG_COUNTERS #ifdef USE_RMT_DEBUG_COUNTERS // #define IncludeBufferData // debug counters From 2fabbaa735dd69edaff09950b8838ebaac6c759b Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Fri, 5 Jun 2026 20:28:54 -0400 Subject: [PATCH 03/31] Added missing config value --- src/output/OutputGECERmt.cpp | 1 + src/output/OutputGS8208Rmt.cpp | 1 + src/output/OutputSerialRmt.cpp | 1 + src/output/OutputTLS3001Rmt.cpp | 1 + src/output/OutputTM1814Rmt.cpp | 1 + src/output/OutputUCS8903Rmt.cpp | 1 + src/output/OutputWS2811Rmt.cpp | 1 + 7 files changed, 7 insertions(+) diff --git a/src/output/OutputGECERmt.cpp b/src/output/OutputGECERmt.cpp index 555b0a00d..922a3a56e 100644 --- a/src/output/OutputGECERmt.cpp +++ b/src/output/OutputGECERmt.cpp @@ -87,6 +87,7 @@ bool c_OutputGECERmt::SetConfig (ArduinoJson::JsonObject& jsonConfig) OutputRmtConfig.arg = this; OutputRmtConfig.ISR_GetNextIntensityBit = ISR_GetNextBitToSendBase; OutputRmtConfig.StartNewDataFrame = StartNewDataFrameBase; + OutputRmtConfig.BufferStart = GetBufferAddress(); Rmt.Begin(OutputRmtConfig, this); diff --git a/src/output/OutputGS8208Rmt.cpp b/src/output/OutputGS8208Rmt.cpp index a872e4b59..a971c60c4 100644 --- a/src/output/OutputGS8208Rmt.cpp +++ b/src/output/OutputGS8208Rmt.cpp @@ -96,6 +96,7 @@ bool c_OutputGS8208Rmt::SetConfig (ArduinoJson::JsonObject& jsonConfig) OutputRmtConfig.arg = this; OutputRmtConfig.ISR_GetNextIntensityBit = ISR_GetNextBitToSendBase; OutputRmtConfig.StartNewDataFrame = StartNewDataFrameBase; + OutputRmtConfig.BufferStart = GetBufferAddress(); Rmt.Begin(OutputRmtConfig, this); diff --git a/src/output/OutputSerialRmt.cpp b/src/output/OutputSerialRmt.cpp index 307bfc35f..a7019b085 100644 --- a/src/output/OutputSerialRmt.cpp +++ b/src/output/OutputSerialRmt.cpp @@ -81,6 +81,7 @@ bool c_OutputSerialRmt::SetConfig (ArduinoJson::JsonObject& jsonConfig) OutputRmtConfig.arg = this; OutputRmtConfig.ISR_GetNextIntensityBit = ISR_GetNextBitToSendBase; OutputRmtConfig.StartNewDataFrame = StartNewDataFrameBase; + OutputRmtConfig.BufferStart = GetBufferAddress(); Rmt.Begin(OutputRmtConfig, this); SetUpRmtBitTimes(); diff --git a/src/output/OutputTLS3001Rmt.cpp b/src/output/OutputTLS3001Rmt.cpp index eff70ccd8..ac1d60e12 100644 --- a/src/output/OutputTLS3001Rmt.cpp +++ b/src/output/OutputTLS3001Rmt.cpp @@ -97,6 +97,7 @@ bool c_OutputTLS3001Rmt::SetConfig (ArduinoJson::JsonObject& jsonConfig) OutputRmtConfig.arg = this; OutputRmtConfig.ISR_GetNextIntensityBit = ISR_GetNextBitToSendBase; OutputRmtConfig.StartNewDataFrame = StartNewDataFrameBase; + OutputRmtConfig.BufferStart = GetBufferAddress(); // DEBUG_V(); SetBitTimes(); diff --git a/src/output/OutputTM1814Rmt.cpp b/src/output/OutputTM1814Rmt.cpp index 4adc5a9c9..4fc6feed5 100644 --- a/src/output/OutputTM1814Rmt.cpp +++ b/src/output/OutputTM1814Rmt.cpp @@ -96,6 +96,7 @@ bool c_OutputTM1814Rmt::SetConfig (ArduinoJson::JsonObject& jsonConfig) OutputRmtConfig.arg = this; OutputRmtConfig.ISR_GetNextIntensityBit = ISR_GetNextBitToSendBase; OutputRmtConfig.StartNewDataFrame = StartNewDataFrameBase; + OutputRmtConfig.BufferStart = GetBufferAddress(); Rmt.Begin(OutputRmtConfig, this); diff --git a/src/output/OutputUCS8903Rmt.cpp b/src/output/OutputUCS8903Rmt.cpp index b43a594c4..441f2b5e4 100644 --- a/src/output/OutputUCS8903Rmt.cpp +++ b/src/output/OutputUCS8903Rmt.cpp @@ -96,6 +96,7 @@ bool c_OutputUCS8903Rmt::SetConfig (ArduinoJson::JsonObject& jsonConfig) OutputRmtConfig.arg = this; OutputRmtConfig.ISR_GetNextIntensityBit = ISR_GetNextBitToSendBase; OutputRmtConfig.StartNewDataFrame = StartNewDataFrameBase; + OutputRmtConfig.BufferStart = GetBufferAddress(); Rmt.Begin(OutputRmtConfig, this); diff --git a/src/output/OutputWS2811Rmt.cpp b/src/output/OutputWS2811Rmt.cpp index 775412e78..61d0641aa 100644 --- a/src/output/OutputWS2811Rmt.cpp +++ b/src/output/OutputWS2811Rmt.cpp @@ -95,6 +95,7 @@ bool c_OutputWS2811Rmt::SetConfig (ArduinoJson::JsonObject& jsonConfig) OutputRmtConfig.arg = this; OutputRmtConfig.ISR_GetNextIntensityBit = ISR_GetNextBitToSendBase; OutputRmtConfig.StartNewDataFrame = StartNewDataFrameBase; + OutputRmtConfig.BufferStart = GetBufferAddress(); // DEBUG_V(); Rmt.Begin(OutputRmtConfig, this); From ae5172dc29fea117927c0e4256ee9f4757ff82bc Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Fri, 5 Jun 2026 23:11:03 -0400 Subject: [PATCH 04/31] Removed function definitions that are not used in idf v5.x --- include/output/OutputRmt.hpp | 8 ++------ src/output/OutputRmtV5.cpp | 4 ---- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/include/output/OutputRmt.hpp b/include/output/OutputRmt.hpp index 668bddbec..b7303a504 100644 --- a/include/output/OutputRmt.hpp +++ b/include/output/OutputRmt.hpp @@ -129,36 +129,32 @@ class c_OutputRmt void GetDriverName (String &value) { value = CN_RMT; } void SetBitDuration (double BitLenNs, rmt_item32_t & OutputBit, uint32_t & OutputNumBits); +#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) __attribute__((always_inline)) inline void IRAM_ATTR DisableRmtInterrupts() { - #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) rmt_ll_enable_tx_thres_interrupt(&RMT, OutputRmtConfig.RmtChannelId, false); rmt_ll_enable_tx_end_interrupt(&RMT, OutputRmtConfig.RmtChannelId, false); rmt_ll_enable_tx_err_interrupt(&RMT, OutputRmtConfig.RmtChannelId, false); ClearRmtInterrupts(); - #endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) } __attribute__((always_inline)) inline void IRAM_ATTR EnableRmtInterrupts() { - #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) rmt_ll_enable_tx_thres_interrupt(&RMT, OutputRmtConfig.RmtChannelId, true); rmt_ll_enable_tx_end_interrupt(&RMT, OutputRmtConfig.RmtChannelId, true); rmt_ll_enable_tx_err_interrupt(&RMT, OutputRmtConfig.RmtChannelId, true); - #endif // ndef rmt_ll_clear_tx_thres_interrupt } __attribute__((always_inline)) inline void IRAM_ATTR ClearRmtInterrupts() { - #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) rmt_ll_clear_tx_thres_interrupt(&RMT, OutputRmtConfig.RmtChannelId); rmt_ll_clear_tx_end_interrupt(&RMT, OutputRmtConfig.RmtChannelId); rmt_ll_clear_tx_err_interrupt(&RMT, OutputRmtConfig.RmtChannelId); - #endif // ndef rmt_ll_clear_tx_thres_interrupt } +#endif // ndef rmt_ll_clear_tx_thres_interrupt #define RMT_ClockRate 80000000.0 #define RMT_Clock_Divisor 2.0 diff --git a/src/output/OutputRmtV5.cpp b/src/output/OutputRmtV5.cpp index d17b3fbc4..16a7bfc08 100644 --- a/src/output/OutputRmtV5.cpp +++ b/src/output/OutputRmtV5.cpp @@ -110,8 +110,6 @@ c_OutputRmt::~c_OutputRmt () RequestReboot(Reason, 100000); ISR_ResetRmtBlockPointers (); // Stop transmitter - DisableRmtInterrupts(); - ClearRmtInterrupts(); yield(); rmt_isr_ThisPtrs[OutputRmtConfig.RmtChannelId] = (c_OutputRmt*)nullptr; } @@ -461,8 +459,6 @@ void c_OutputRmt::PauseOutput(bool PauseOutput) else if (PauseOutput) { ///DEBUG_V("stop the output"); - DisableRmtInterrupts(); - ClearRmtInterrupts(); } OutputIsPaused = PauseOutput; From 71b5e9f4776e52c88d1ce59c169579d7ac46d810 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Sat, 6 Jun 2026 12:16:47 -0400 Subject: [PATCH 05/31] Removed magic number --- src/output/OutputGECERmt.cpp | 1 + src/output/OutputGS8208Rmt.cpp | 1 + src/output/OutputRmtV5.cpp | 2 +- src/output/OutputSerialRmt.cpp | 1 + src/output/OutputTLS3001Rmt.cpp | 1 + src/output/OutputTM1814Rmt.cpp | 1 + src/output/OutputUCS1903Rmt.cpp | 2 ++ src/output/OutputUCS8903Rmt.cpp | 1 + src/output/OutputWS2811Rmt.cpp | 1 + 9 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/output/OutputGECERmt.cpp b/src/output/OutputGECERmt.cpp index 922a3a56e..1362afa9e 100644 --- a/src/output/OutputGECERmt.cpp +++ b/src/output/OutputGECERmt.cpp @@ -88,6 +88,7 @@ bool c_OutputGECERmt::SetConfig (ArduinoJson::JsonObject& jsonConfig) OutputRmtConfig.ISR_GetNextIntensityBit = ISR_GetNextBitToSendBase; OutputRmtConfig.StartNewDataFrame = StartNewDataFrameBase; OutputRmtConfig.BufferStart = GetBufferAddress(); + OutputRmtConfig.NumBytesInFrame = OM_MAX_NUM_CHANNELS; Rmt.Begin(OutputRmtConfig, this); diff --git a/src/output/OutputGS8208Rmt.cpp b/src/output/OutputGS8208Rmt.cpp index a971c60c4..67e48fb2b 100644 --- a/src/output/OutputGS8208Rmt.cpp +++ b/src/output/OutputGS8208Rmt.cpp @@ -97,6 +97,7 @@ bool c_OutputGS8208Rmt::SetConfig (ArduinoJson::JsonObject& jsonConfig) OutputRmtConfig.ISR_GetNextIntensityBit = ISR_GetNextBitToSendBase; OutputRmtConfig.StartNewDataFrame = StartNewDataFrameBase; OutputRmtConfig.BufferStart = GetBufferAddress(); + OutputRmtConfig.NumBytesInFrame = OM_MAX_NUM_CHANNELS; Rmt.Begin(OutputRmtConfig, this); diff --git a/src/output/OutputRmtV5.cpp b/src/output/OutputRmtV5.cpp index 16a7bfc08..a2c10adbf 100644 --- a/src/output/OutputRmtV5.cpp +++ b/src/output/OutputRmtV5.cpp @@ -514,7 +514,7 @@ bool c_OutputRmt::StartNewFrame () // DEBUG_V("start the transmitter"); // rmt_enable(rmt_channel_handle); - OutputRmtConfig.NumBytesInFrame = 9000; + // DEBUG_V(String("rmt_channel_handle: ") + String(uint32_t(rmt_channel_handle))); // DEBUG_V(String("rmt_encoder_handle: ") + String(uint32_t(rmt_encoder_handle))); // DEBUG_V(String(" BufferStart: ") + String(uint32_t(OutputRmtConfig.BufferStart))); diff --git a/src/output/OutputSerialRmt.cpp b/src/output/OutputSerialRmt.cpp index a7019b085..754661b56 100644 --- a/src/output/OutputSerialRmt.cpp +++ b/src/output/OutputSerialRmt.cpp @@ -82,6 +82,7 @@ bool c_OutputSerialRmt::SetConfig (ArduinoJson::JsonObject& jsonConfig) OutputRmtConfig.ISR_GetNextIntensityBit = ISR_GetNextBitToSendBase; OutputRmtConfig.StartNewDataFrame = StartNewDataFrameBase; OutputRmtConfig.BufferStart = GetBufferAddress(); + OutputRmtConfig.NumBytesInFrame = OM_MAX_NUM_CHANNELS; Rmt.Begin(OutputRmtConfig, this); SetUpRmtBitTimes(); diff --git a/src/output/OutputTLS3001Rmt.cpp b/src/output/OutputTLS3001Rmt.cpp index ac1d60e12..7036c0449 100644 --- a/src/output/OutputTLS3001Rmt.cpp +++ b/src/output/OutputTLS3001Rmt.cpp @@ -98,6 +98,7 @@ bool c_OutputTLS3001Rmt::SetConfig (ArduinoJson::JsonObject& jsonConfig) OutputRmtConfig.ISR_GetNextIntensityBit = ISR_GetNextBitToSendBase; OutputRmtConfig.StartNewDataFrame = StartNewDataFrameBase; OutputRmtConfig.BufferStart = GetBufferAddress(); + OutputRmtConfig.NumBytesInFrame = OM_MAX_NUM_CHANNELS; // DEBUG_V(); SetBitTimes(); diff --git a/src/output/OutputTM1814Rmt.cpp b/src/output/OutputTM1814Rmt.cpp index 4fc6feed5..f1ea0f2fc 100644 --- a/src/output/OutputTM1814Rmt.cpp +++ b/src/output/OutputTM1814Rmt.cpp @@ -97,6 +97,7 @@ bool c_OutputTM1814Rmt::SetConfig (ArduinoJson::JsonObject& jsonConfig) OutputRmtConfig.ISR_GetNextIntensityBit = ISR_GetNextBitToSendBase; OutputRmtConfig.StartNewDataFrame = StartNewDataFrameBase; OutputRmtConfig.BufferStart = GetBufferAddress(); + OutputRmtConfig.NumBytesInFrame = OM_MAX_NUM_CHANNELS; Rmt.Begin(OutputRmtConfig, this); diff --git a/src/output/OutputUCS1903Rmt.cpp b/src/output/OutputUCS1903Rmt.cpp index 39bfb5b61..79d91cf9f 100644 --- a/src/output/OutputUCS1903Rmt.cpp +++ b/src/output/OutputUCS1903Rmt.cpp @@ -95,6 +95,8 @@ bool c_OutputUCS1903Rmt::SetConfig (ArduinoJson::JsonObject& jsonConfig) OutputRmtConfig.arg = this; OutputRmtConfig.ISR_GetNextIntensityBit = ISR_GetNextBitToSendBase; OutputRmtConfig.StartNewDataFrame = StartNewDataFrameBase; + OutputRmtConfig.BufferStart = GetBufferAddress(); + OutputRmtConfig.NumBytesInFrame = OM_MAX_NUM_CHANNELS; Rmt.Begin(OutputRmtConfig, this); diff --git a/src/output/OutputUCS8903Rmt.cpp b/src/output/OutputUCS8903Rmt.cpp index 441f2b5e4..4b8900abf 100644 --- a/src/output/OutputUCS8903Rmt.cpp +++ b/src/output/OutputUCS8903Rmt.cpp @@ -97,6 +97,7 @@ bool c_OutputUCS8903Rmt::SetConfig (ArduinoJson::JsonObject& jsonConfig) OutputRmtConfig.ISR_GetNextIntensityBit = ISR_GetNextBitToSendBase; OutputRmtConfig.StartNewDataFrame = StartNewDataFrameBase; OutputRmtConfig.BufferStart = GetBufferAddress(); + OutputRmtConfig.NumBytesInFrame = OM_MAX_NUM_CHANNELS; Rmt.Begin(OutputRmtConfig, this); diff --git a/src/output/OutputWS2811Rmt.cpp b/src/output/OutputWS2811Rmt.cpp index 61d0641aa..7718123fd 100644 --- a/src/output/OutputWS2811Rmt.cpp +++ b/src/output/OutputWS2811Rmt.cpp @@ -96,6 +96,7 @@ bool c_OutputWS2811Rmt::SetConfig (ArduinoJson::JsonObject& jsonConfig) OutputRmtConfig.ISR_GetNextIntensityBit = ISR_GetNextBitToSendBase; OutputRmtConfig.StartNewDataFrame = StartNewDataFrameBase; OutputRmtConfig.BufferStart = GetBufferAddress(); + OutputRmtConfig.NumBytesInFrame = OM_MAX_NUM_CHANNELS; // DEBUG_V(); Rmt.Begin(OutputRmtConfig, this); From 3edc71bf81306b19db33e3cd62642416d044b100 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Sat, 6 Jun 2026 20:02:22 -0400 Subject: [PATCH 06/31] Removed unneeded forward declaration. No longer force a reset when rmy based channels are shut down. --- src/output/OutputRmtV5.cpp | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/output/OutputRmtV5.cpp b/src/output/OutputRmtV5.cpp index a2c10adbf..b879be097 100644 --- a/src/output/OutputRmtV5.cpp +++ b/src/output/OutputRmtV5.cpp @@ -23,20 +23,17 @@ #include "output/OutputRmt.hpp" #include -// forward declaration for the isr handler -static void IRAM_ATTR rmt_intr_handler (void* param); -static c_OutputRmt * rmt_isr_ThisPtrs[MAX_NUM_RMT_CHANNELS]; - #ifdef USE_RMT_DEBUG_COUNTERS -static uint32_t RawIsrCounter = 0; +static uint32_t RawIsrCounter = 0; #endif // def USE_RMT_DEBUG_COUNTERS -static TaskHandle_t SendFrameTaskHandle = NULL; -static BaseType_t xHigherPriorityTaskWoken = pdTRUE; -static uint32_t FrameCompletes = 0; -static uint32_t FrameTimeouts = 0; -static uint32_t SavedInterruptEnables = 0; -static uint32_t SavedInterruptStatus = 0; +static TaskHandle_t SendFrameTaskHandle = NULL; +static BaseType_t xHigherPriorityTaskWoken = pdTRUE; +static uint32_t FrameCompletes = 0; +static uint32_t FrameTimeouts = 0; +static uint32_t SavedInterruptEnables = 0; +static uint32_t SavedInterruptStatus = 0; +static c_OutputRmt * rmt_isr_ThisPtrs[MAX_NUM_RMT_CHANNELS]; //---------------------------------------------------------------------------- void RMT_Task (void *arg) @@ -95,7 +92,6 @@ c_OutputRmt::c_OutputRmt() memset((void *)&SendBuffer[0], 0x00, sizeof(SendBuffer)); - // DEBUG_END; } // c_OutputRmt @@ -106,12 +102,10 @@ c_OutputRmt::~c_OutputRmt () if (HasBeenInitialized) { - String Reason = (F("Shutting down an RMT channel requires a reboot")); - RequestReboot(Reason, 100000); - ISR_ResetRmtBlockPointers (); // Stop transmitter - yield(); + rmt_disable(rmt_channel_handle); rmt_isr_ThisPtrs[OutputRmtConfig.RmtChannelId] = (c_OutputRmt*)nullptr; + yield(); } // DEBUG_END; From 682b9f3a836c49c746d8769f58261f0c3e2e50c3 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Sat, 13 Jun 2026 11:34:12 -0400 Subject: [PATCH 07/31] Removed unused variables --- src/output/OutputRmtV5.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/output/OutputRmtV5.cpp b/src/output/OutputRmtV5.cpp index b879be097..a1f6e16c3 100644 --- a/src/output/OutputRmtV5.cpp +++ b/src/output/OutputRmtV5.cpp @@ -31,8 +31,6 @@ static TaskHandle_t SendFrameTaskHandle = NULL; static BaseType_t xHigherPriorityTaskWoken = pdTRUE; static uint32_t FrameCompletes = 0; static uint32_t FrameTimeouts = 0; -static uint32_t SavedInterruptEnables = 0; -static uint32_t SavedInterruptStatus = 0; static c_OutputRmt * rmt_isr_ThisPtrs[MAX_NUM_RMT_CHANNELS]; //---------------------------------------------------------------------------- From 905f87f126f2694e8182a2ca88932319220cdf0e Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Mon, 15 Jun 2026 15:07:04 -0400 Subject: [PATCH 08/31] Added debug info. --- src/output/OutputPixel.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/output/OutputPixel.cpp b/src/output/OutputPixel.cpp index afa4a400b..3bac9a1b4 100644 --- a/src/output/OutputPixel.cpp +++ b/src/output/OutputPixel.cpp @@ -204,6 +204,7 @@ bool c_OutputPixel::SetConfig (ArduinoJson::JsonObject& jsonConfig) bool response = validate (); + // AdjustedBrightness = map (brightness, 0, 100, 0, 256); AdjustedBrightness = map (brightness, 0, 100, 0, 204); GECEBrightness = GECE_SET_BRIGHTNESS(map(brightness, 0, 100, 0, 204)); // DEBUG_V (String ("brightness: ") + String (brightness)); @@ -233,6 +234,7 @@ void c_OutputPixel::updateGammaTable () { // DEBUG_START; double tempBrightness = double (brightness) / 100.0; + // DEBUG_V (String (" brightness: ") + String (brightness)); // DEBUG_V (String ("tempBrightness: ") + String (tempBrightness)); for (unsigned int i = 0; i < sizeof (gamma_table); ++i) @@ -791,21 +793,25 @@ void c_OutputPixel::WriteChannelData(uint32_t StartChannelId, uint32_t ChannelCo { // DEBUG_START; - if((StartChannelId + ChannelCount) > OutputBufferSize) + // if((StartChannelId + ChannelCount) > OutputBufferSize) { // DEBUG_V("ERROR: Writting beyond the end of the output buffer"); // DEBUG_V(String("StartChannelId: 0x") + String(StartChannelId, HEX)); // DEBUG_V(String(" ChannelCount: 0x") + String(ChannelCount)); } - // DEBUG_V(String(" StartChannelId: 0x") + String(StartChannelId, HEX)); - // DEBUG_V(String(" ChannelCount: 0x") + String(ChannelCount, HEX)); + // DEBUG_V(String(" StartChannelId: 0x") + String(StartChannelId, HEX)); + // DEBUG_V(String(" ChannelCount: 0x") + String(ChannelCount, HEX)); + // DEBUG_V(String(" AdjustedBrightness: ") + String(AdjustedBrightness)); uint32_t EndChannelId = StartChannelId + ChannelCount; uint32_t SourceDataIndex = 0; for (uint32_t currentChannelId = StartChannelId; currentChannelId < EndChannelId; ++currentChannelId, ++SourceDataIndex) { + // DEBUG_V(String(" pSourceData[SourceDataIndex]: ") + String(pSourceData[SourceDataIndex])); uint32_t CurrentIntensityData = gamma_table[pSourceData[SourceDataIndex]]; + // DEBUG_V(String(" CurrentIntensityData: ") + String(CurrentIntensityData)); CurrentIntensityData = uint8_t((uint32_t(CurrentIntensityData) * AdjustedBrightness) >> 8); + // DEBUG_V(String(" CurrentIntensityData: ") + String(CurrentIntensityData)); uint32_t CalculatedChannelId = CalculateIntensityOffset(currentChannelId); uint8_t *pBuffer = &pOutputBuffer[CalculatedChannelId]; for(uint32_t CurrentGroupIndex = 0; CurrentGroupIndex < PixelGroupSize; ++CurrentGroupIndex) From 06ee98bccaf38004e2ab6a4e3ec593946956030d Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Fri, 19 Jun 2026 22:19:14 -0400 Subject: [PATCH 09/31] Fixed issue that could cause data buffer corruption on S3 RMT output channel buffers. --- include/output/OutputRmt.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/output/OutputRmt.hpp b/include/output/OutputRmt.hpp index b7303a504..9e989630f 100644 --- a/include/output/OutputRmt.hpp +++ b/include/output/OutputRmt.hpp @@ -96,7 +96,7 @@ class c_OutputRmt uint32_t NumRmtSlotOverruns = 0; const uint32_t MaxNumRmtSlotsPerInterrupt = (_NUM_RMT_SLOTS/2); - #define NumSendBufferSlots _NUM_RMT_SLOTS + #define NumSendBufferSlots 128 // Must be a power of 2 rmt_item32_t SendBuffer[NumSendBufferSlots]; uint32_t RmtBufferWriteIndex = 0; uint32_t SendBufferWriteIndex = 0; From 93bd33a5b1fbf9871abd28501a56f505493ef8c1 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Sat, 20 Jun 2026 10:11:22 -0400 Subject: [PATCH 10/31] Restore buffer size to prevent output class size jump. --- include/output/OutputRmt.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/output/OutputRmt.hpp b/include/output/OutputRmt.hpp index 9e989630f..aa2126157 100644 --- a/include/output/OutputRmt.hpp +++ b/include/output/OutputRmt.hpp @@ -96,7 +96,7 @@ class c_OutputRmt uint32_t NumRmtSlotOverruns = 0; const uint32_t MaxNumRmtSlotsPerInterrupt = (_NUM_RMT_SLOTS/2); - #define NumSendBufferSlots 128 // Must be a power of 2 + #define NumSendBufferSlots 64 // Must be a power of 2 rmt_item32_t SendBuffer[NumSendBufferSlots]; uint32_t RmtBufferWriteIndex = 0; uint32_t SendBufferWriteIndex = 0; From 6ce5918e1fa5715d05dea67f4f63d08f81f43a37 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Sat, 20 Jun 2026 22:02:15 -0400 Subject: [PATCH 11/31] Automated determining the class buffer size to preallocate. --- include/output/OutputMgr.hpp | 28 +------ src/output/OutputMgr.cpp | 141 ++++++++++++++++++++++++++++++----- 2 files changed, 127 insertions(+), 42 deletions(-) diff --git a/include/output/OutputMgr.hpp b/include/output/OutputMgr.hpp index 43a738a80..d06ca20bb 100644 --- a/include/output/OutputMgr.hpp +++ b/include/output/OutputMgr.hpp @@ -58,7 +58,6 @@ class c_OutputMgr void SetConfig (const char * NewConfig); ///< Save the current configuration data to nvram void SetConfig (ArduinoJson::JsonDocument & NewConfig); ///< Save the current configuration data to nvram void GetStatus (JsonObject & jsonStatus); -// void GetPortCounts (uint16_t& PixelCount, uint16_t& SerialCount) {PixelCount = uint16_t(OutputPortId_End); SerialCount = uint16_t(NUM_UARTS); } uint8_t* GetBufferAddress () { return pOutputBuffer; } ///< Get the address of the buffer into which the E1.31 handler will stuff data uint32_t GetBufferUsedSize () { return UsedBufferSize; } ///< Get the size (in intensities) of the buffer into which the E1.31 handler will stuff data uint32_t GetBufferSize () { return uint32_t(OM_MAX_NUM_CHANNELS); } ///< Get the size (in intensities) of the buffer into which the E1.31 handler will stuff data @@ -149,31 +148,10 @@ class c_OutputMgr }; uint32_t NumberOfOutputProtocols = uint32_t(0); - // must be 16 byte aligned. Determined by upshifting the max size of all drivers - // #define OutputDriverMemorySize 1200 - #define OutputDriverMemorySize 1400 - uint32_t GetDriverSize() {return OutputDriverMemorySize;} private: - struct alignas(16) DriverInfo_t - { - byte OutputDriver[OutputDriverMemorySize]; - uint32_t OutputBufferStartingOffset = 0; - uint32_t OutputBufferDataSize = 0; - uint32_t OutputBufferEndOffset = 0; - - uint32_t OutputChannelStartingOffset = 0; - uint32_t OutputChannelSize = 0; - uint32_t OutputChannelEndOffset = 0; - - OM_OutputPortDefinition_t PortDefinition; - uint8_t DriverId = -1; - bool OutputDriverInUse = false; - }; // pointer(s) to the current active output drivers - DriverInfo_t *pOutputChannelDrivers = nullptr; - uint8_t NumOutputPorts = 0; - uint32_t SizeOfTable = 0; + uint8_t NumOutputPorts; // configuration parameter names for the channel manager within the config file #define NO_CONFIG_NEEDED time_t(-1) @@ -186,11 +164,11 @@ class c_OutputMgr bool ProcessJsonConfig (JsonDocument & jsonConfig); void CreateJsonConfig (JsonObject & jsonConfig); void UpdateDisplayBufferReferences (void); - void InstantiateNewOutputChannel(DriverInfo_t &ChannelIndex, e_OutputProtocolType NewChannelType, bool StartDriver = true); + void InstantiateNewOutputChannel(uint32_t PortIndex, e_OutputProtocolType NewChannelType, bool StartDriver = true); void CreateNewConfig(); void SetSerialUart(); bool FindJsonChannelConfig (JsonDocument& jsonConfig, OM_PortId_t PortId, JsonObject& ChanConfig); - bool SetPortDefnitionDefaults(DriverInfo_t & CurrentOutput, e_OutputProtocolType TargetProtocolType); + bool SetPortDefnitionDefaults(uint32_t PortIndex, e_OutputProtocolType TargetProtocolType); String ConfigFileName; diff --git a/src/output/OutputMgr.cpp b/src/output/OutputMgr.cpp index 093422296..e9e5d3348 100644 --- a/src/output/OutputMgr.cpp +++ b/src/output/OutputMgr.cpp @@ -62,7 +62,6 @@ #define AllocatePort(ClassType, Output, OutputType) \ { \ - static_assert(sizeof(Output.OutputDriver) >= sizeof(ClassType)); \ new(&Output.OutputDriver) ClassType(Output.PortDefinition, OutputType); \ Output.OutputDriverInUse = true; \ } @@ -146,6 +145,105 @@ static const SupportedOutputProtocol_t SupportedOutputProtocolList[] = #endif // def SUPPORT_OutputProtocol_FireGod }; +union alignas(32) OutputProtocolClasses_t +{ + c_OutputDisabled OutputDisabled; + + #ifdef SUPPORT_OutputProtocol_WS2811 + c_OutputWS2811Uart OutputWS2811Uart; + c_OutputWS2811Rmt OutputWS2811Rmt; + #endif // def SUPPORT_OutputProtocol_WS2811 + + #ifdef SUPPORT_OutputProtocol_GECE + c_OutputGECEUart OutputGECEUart; + c_OutputGECERmt OutputGECERmt; + #endif // def SUPPORT_OutputProtocol_GECE + + #ifdef SUPPORT_OutputProtocol_DMX + c_OutputDMXUart OutputDMXUart; + c_OutputDMXRmt OutputDMXRmt; + #endif // def SUPPORT_OutputProtocol_DMX + + #ifdef SUPPORT_OutputProtocol_Renard + c_OutputRenardUart OutputRenardUart; + c_OutputRenardRmt OutputRenardRmt; + #endif // def SUPPORT_OutputProtocol_Renard + + #ifdef SUPPORT_OutputProtocol_Serial + c_OutputSerialUart OutputSerialUart; + c_OutputSerialRmt OutputSerialRmt; + #endif // def SUPPORT_OutputProtocol_Serial + + #ifdef SUPPORT_OutputProtocol_Relay + c_OutputRelay OutputRelay; + #endif // def SUPPORT_OutputProtocol_Relay + + #ifdef SUPPORT_OutputProtocol_Servo_PCA9685 + c_OutputServoPCA9685 OutputServoPCA9685; + #endif // def SUPPORT_OutputProtocol_Servo_PCA9685 + + #ifdef SUPPORT_OutputProtocol_UCS1903 + c_OutputUCS1903Uart OutputUCS1903Uart; + c_OutputUCS1903Rmt OutputUCS1903Rmt; + #endif // def SUPPORT_OutputProtocol_UCS1903 + + #ifdef SUPPORT_OutputProtocol_TM1814 + c_OutputTM1814Uart OutputTM1814Uart; + c_OutputTM1814Rmt OutputTM1814Rmt; + #endif // def SUPPORT_OutputProtocol_TM1814 + + #ifdef SUPPORT_OutputProtocol_WS2801 + c_OutputWS2801Spi OutputWS2801Spi; + #endif // def SUPPORT_OutputProtocol_WS2801 + + #ifdef SUPPORT_OutputProtocol_APA102 + c_OutputAPA102Spi OutputAPA102Spi; + #endif // def SUPPORT_OutputProtocol_APA102 + + #ifdef SUPPORT_OutputProtocol_GS8208 + c_OutputGS8208Uart OutputGS8208Uart; + c_OutputGS8208Rmt OutputGS8208Rmt; + #endif // def SUPPORT_OutputProtocol_GS8208 + + #ifdef SUPPORT_OutputProtocol_UCS8903 + c_OutputUCS8903Uart OutputUCS8903Uart; + c_OutputUCS8903Rmt OutputUCS8903Rmt; + #endif // def SUPPORT_OutputProtocol_UCS8903 + + #ifdef SUPPORT_OutputProtocol_TLS3001 + // c_OutputTLS3001Uart OutputTLS3001Uart; + c_OutputTLS3001Rmt OutputTLS3001Rmt; + #endif // def SUPPORT_OutputProtocol_TLS3001 + + #ifdef SUPPORT_OutputProtocol_GRINCH + c_OutputGRINCHSpi OutputGRINCHSpi; + #endif // def SUPPORT_OutputProtocol_GRINCH + + #ifdef SUPPORT_OutputProtocol_FireGod + c_OutputFireGodSpi OutputFireGodSpi; + #endif // def SUPPORT_OutputProtocol_FireGod + + // Add new types here +}; + +struct alignas(32) DriverInfo_t +{ + OutputProtocolClasses_t OutputDriver; + uint32_t OutputBufferStartingOffset; + uint32_t OutputBufferDataSize; + uint32_t OutputBufferEndOffset; + + uint32_t OutputChannelStartingOffset; + uint32_t OutputChannelSize; + uint32_t OutputChannelEndOffset; + + OM_OutputPortDefinition_t PortDefinition; + uint8_t DriverId; + bool OutputDriverInUse; +}; + +static DriverInfo_t * pOutputChannelDrivers = nullptr;; + //----------------------------------------------------------------------------- // Methods //----------------------------------------------------------------------------- @@ -170,14 +268,14 @@ c_OutputMgr::c_OutputMgr () NumOutputPorts = CurrentOutputPortDefinition.PortId; } } + // convert the zero based port ID into a port count NumOutputPorts++; // allocate a port driver control space - pOutputChannelDrivers = nullptr; // DriverInfo_t is an aligned structure size_t alignment = alignof(DriverInfo_t); - SizeOfTable = sizeof(DriverInfo_t) * NumOutputPorts; + uint32_t SizeOfTable = sizeof(DriverInfo_t) * NumOutputPorts; // Ensure total_size is a multiple of alignment (which it should be if sizeof(AlignedObject) is used) byte * raw_mem = (((byte*)malloc(SizeOfTable + (2*alignment))) + alignment); pOutputChannelDrivers = static_cast((void*)raw_mem); @@ -187,6 +285,15 @@ c_OutputMgr::c_OutputMgr () for (uint8_t index = 0; index < NumOutputPorts; ++index) { DriverInfo_t & CurrentOutput = pOutputChannelDrivers[index]; + + // CurrentOutput.OutputDriver; + // CurrentOutput.OutputBufferStartingOffset = 0; + // CurrentOutput.OutputBufferDataSize = 0; + // CurrentOutput.OutputBufferEndOffset = 0; + // CurrentOutput.OutputChannelStartingOffset = 0; + // CurrentOutput.OutputChannelSize = 0; + // CurrentOutput.OutputChannelEndOffset = 0; + CurrentOutput.DriverId = index; CurrentOutput.OutputDriverInUse = false; } @@ -204,6 +311,7 @@ c_OutputMgr::~c_OutputMgr() { DriverInfo_t & CurrentOutput = pOutputChannelDrivers[index]; // the drivers will put the hardware in a safe state + CurrentOutput.OutputDriverInUse = false; ((c_OutputCommon&)(CurrentOutput.OutputDriver)).~c_OutputCommon(); } // DEBUG_END; @@ -250,9 +358,7 @@ void c_OutputMgr::Begin () // make sure the pointers are set up properly for (uint8_t index = 0; index < NumOutputPorts; ++index) { - DriverInfo_t & CurrentOutput = pOutputChannelDrivers[index]; - // DEBUG_V(String("DriverId: ") + String(CurrentOutput.DriverId)); - InstantiateNewOutputChannel(CurrentOutput, e_OutputProtocolType::OutputProtocol_Disabled); + InstantiateNewOutputChannel(index, e_OutputProtocolType::OutputProtocol_Disabled); // DEBUG_V(String("init index: ") + String(index) + " Done"); } @@ -417,7 +523,7 @@ void c_OutputMgr::CreateNewConfig () (CurrentOutputProtocol.RequiredPortType == OM_PortType_t::OM_ANY)) { // DEBUG_V("Port supports this protocol"); - InstantiateNewOutputChannel(CurrentOutput, CurrentOutputProtocol.ProtocolId, false); + InstantiateNewOutputChannel(CurrentOutput.DriverId, CurrentOutputProtocol.ProtocolId, false); } else { @@ -448,8 +554,7 @@ void c_OutputMgr::CreateNewConfig () // DEBUG_V ("leave the outputs disabled"); for (uint8_t index = 0; index < NumOutputPorts; ++index) { - DriverInfo_t & CurrentOutput = pOutputChannelDrivers[index]; - InstantiateNewOutputChannel(CurrentOutput, e_OutputProtocolType::OutputProtocol_Disabled); + InstantiateNewOutputChannel(index, e_OutputProtocolType::OutputProtocol_Disabled); }// end for each interface // PrettyPrint(JsonConfig, "Complete OutputMgr"); @@ -549,13 +654,14 @@ void c_OutputMgr::ClearStatistics () returns nothing */ -void c_OutputMgr::InstantiateNewOutputChannel(DriverInfo_t & CurrentOutput, e_OutputProtocolType NewOutputChannelType, bool StartDriver) +void c_OutputMgr::InstantiateNewOutputChannel(uint32_t PortIndex, e_OutputProtocolType NewOutputChannelType, bool StartDriver) { // DEBUG_START; // BuildingNewConfig = false; // IsBooting = false; do // once { + DriverInfo_t & CurrentOutput = pOutputChannelDrivers[PortIndex]; // DEBUG_V(String("CurrentOutput: 0x") + String(uint32_t(&CurrentOutput), HEX)); // DEBUG_V(String("OutputDriverInUse: ") + String(CurrentOutput.OutputDriverInUse)); // is there an existing driver? @@ -579,7 +685,7 @@ void c_OutputMgr::InstantiateNewOutputChannel(DriverInfo_t & CurrentOutput, e_Ou } ((c_OutputCommon&)(CurrentOutput.OutputDriver)).~c_OutputCommon(); - memset(CurrentOutput.OutputDriver, 0x0, sizeof(CurrentOutput.OutputDriver)); + memset((void*) & (CurrentOutput.OutputDriver), 0x0, sizeof(CurrentOutput.OutputDriver)); CurrentOutput.OutputDriverInUse = false; // DEBUG_V (); } // end there is an existing driver @@ -599,7 +705,7 @@ void c_OutputMgr::InstantiateNewOutputChannel(DriverInfo_t & CurrentOutput, e_Ou // DEBUG_V (String("PortType: ") + String(CurrentOutput.PortType)); // DEBUG_V (String(" PortId: ") + String(CurrentOutput.PortId)); - if(!SetPortDefnitionDefaults(CurrentOutput, NewOutputChannelType)) + if(!SetPortDefnitionDefaults(CurrentOutput.DriverId, NewOutputChannelType)) { logcon(String(CN_stars) + F(" No valid port definition for port ") + String(CurrentOutput.DriverId + 1) + F(" of protocol type ") + String(NewOutputChannelType)) AllocatePort(c_OutputDisabled, CurrentOutput, OutputProtocol_Disabled); @@ -1011,13 +1117,14 @@ void c_OutputMgr::InstantiateNewOutputChannel(DriverInfo_t & CurrentOutput, e_Ou } // InstantiateNewOutputChannel //----------------------------------------------------------------------------- -bool c_OutputMgr::SetPortDefnitionDefaults(DriverInfo_t & CurrentOutput, e_OutputProtocolType TargetProtocolType) +bool c_OutputMgr::SetPortDefnitionDefaults(uint32_t PortIndex, e_OutputProtocolType TargetProtocolType) { // DEBUG_START; bool Response = false; do // once { + DriverInfo_t & CurrentOutput = pOutputChannelDrivers[PortIndex]; // DEBUG_V(String(" DriverId: ") + String(CurrentOutput.DriverId)); // DEBUG_V(String("TargetProtocolType: ") + String(TargetProtocolType)); @@ -1272,7 +1379,7 @@ bool c_OutputMgr::ProcessJsonConfig (JsonDocument& jsonConfig) // DEBUG_V (String(" OutputPortType: ") + String(OutputPortType)); // if not, flag an error and move on to the next channel logcon(String(MN_19) + OutputPortType + MN_20 + CurrentOutput.DriverId + MN_03); - InstantiateNewOutputChannel(CurrentOutput, e_OutputProtocolType::OutputProtocol_Disabled); + InstantiateNewOutputChannel(CurrentOutput.DriverId, e_OutputProtocolType::OutputProtocol_Disabled); continue; } // DEBUG_V (); @@ -1283,7 +1390,7 @@ bool c_OutputMgr::ProcessJsonConfig (JsonDocument& jsonConfig) { // if not, flag an error and stop processing logcon(String(MN_16) + CurrentOutput.DriverId + MN_18); - InstantiateNewOutputChannel(CurrentOutput, e_OutputProtocolType::OutputProtocol_Disabled); + InstantiateNewOutputChannel(CurrentOutput.DriverId, e_OutputProtocolType::OutputProtocol_Disabled); continue; } // DEBUG_V (); @@ -1291,7 +1398,7 @@ bool c_OutputMgr::ProcessJsonConfig (JsonDocument& jsonConfig) // DEBUG_V (); // make sure the proper output type is running - InstantiateNewOutputChannel(CurrentOutput, e_OutputProtocolType(OutputPortType)); + InstantiateNewOutputChannel(CurrentOutput.DriverId, e_OutputProtocolType(OutputPortType)); // DEBUG_V (); // PrettyPrint(OutputChannelDriverConfig, "ProcessJson Channel Driver Config"); @@ -1559,7 +1666,7 @@ void c_OutputMgr::RelayUpdate (uint8_t RelayId, String & NewValue, String & Resp DriverInfo_t & CurrentOutput = pOutputChannelDrivers[RelayId]; if(e_OutputProtocolType::OutputProtocol_Relay == ((c_OutputCommon&)(CurrentOutput.OutputDriver)).GetOutputType()) { - ((c_OutputRelay*)(CurrentOutput.OutputDriver))->RelayUpdate(NewValue, Response); + CurrentOutput.OutputDriver.OutputRelay.RelayUpdate(NewValue, Response); break; } #endif // def SUPPORT_OutputProtocol_Relay From e2bf033f95788dcc448f431bad016b0a82a8a4fd Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Sun, 21 Jun 2026 17:51:49 -0400 Subject: [PATCH 12/31] Updated the Serial class size calculation and the Grinch Class. --- src/output/OutputMgr.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/output/OutputMgr.cpp b/src/output/OutputMgr.cpp index e9e5d3348..e00e46f28 100644 --- a/src/output/OutputMgr.cpp +++ b/src/output/OutputMgr.cpp @@ -160,13 +160,13 @@ union alignas(32) OutputProtocolClasses_t #endif // def SUPPORT_OutputProtocol_GECE #ifdef SUPPORT_OutputProtocol_DMX - c_OutputDMXUart OutputDMXUart; - c_OutputDMXRmt OutputDMXRmt; + c_OutputSerialUart OutputDMXUart; + c_OutputSerialRmt OutputDMXRmt; #endif // def SUPPORT_OutputProtocol_DMX #ifdef SUPPORT_OutputProtocol_Renard - c_OutputRenardUart OutputRenardUart; - c_OutputRenardRmt OutputRenardRmt; + c_OutputSerialUart OutputRenardUart; + c_OutputSerialRmt OutputRenardRmt; #endif // def SUPPORT_OutputProtocol_Renard #ifdef SUPPORT_OutputProtocol_Serial @@ -216,11 +216,12 @@ union alignas(32) OutputProtocolClasses_t #endif // def SUPPORT_OutputProtocol_TLS3001 #ifdef SUPPORT_OutputProtocol_GRINCH - c_OutputGRINCHSpi OutputGRINCHSpi; + c_OutputGrinchSpi OutputGrinchSpi; #endif // def SUPPORT_OutputProtocol_GRINCH #ifdef SUPPORT_OutputProtocol_FireGod - c_OutputFireGodSpi OutputFireGodSpi; + c_OutputSerialUart OutputFireGodUart; + c_OutputSerialRmt OutputFireGodRmt; #endif // def SUPPORT_OutputProtocol_FireGod // Add new types here From 950bf37fd920f24a8f80fb5a199ee3d8169f3976 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Tue, 23 Jun 2026 19:25:29 -0400 Subject: [PATCH 13/31] Updated a comment. --- include/platforms/GPIO_Defs_ESP32_Octa2go.hpp | 2 +- .../platforms/GPIO_Defs_ESP32_Octa2go_ETH.hpp | 100 ++++++++++++++++++ .../GPIO_Defs_ESP32_Tetra2go_ETH.hpp | 92 ++++++++++++++++ 3 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 include/platforms/GPIO_Defs_ESP32_Octa2go_ETH.hpp create mode 100644 include/platforms/GPIO_Defs_ESP32_Tetra2go_ETH.hpp diff --git a/include/platforms/GPIO_Defs_ESP32_Octa2go.hpp b/include/platforms/GPIO_Defs_ESP32_Octa2go.hpp index e9e43f99b..5d1f1dfac 100644 --- a/include/platforms/GPIO_Defs_ESP32_Octa2go.hpp +++ b/include/platforms/GPIO_Defs_ESP32_Octa2go.hpp @@ -42,7 +42,7 @@ const OM_OutputPortDefinition_t OM_OutputPortDefinitions[] = {OM_PortId_t(9), OM_PortType_t::OM_I2C, {gpio_num_t::GPIO_NUM_21, gpio_num_t::GPIO_NUM_22}}, }; -// File Manager +// File Manager - Defnitions must be present even if SD is not supported #define SUPPORT_SD #define SD_CARD_MISO_PIN gpio_num_t::GPIO_NUM_19 #define SD_CARD_MOSI_PIN gpio_num_t::GPIO_NUM_23 diff --git a/include/platforms/GPIO_Defs_ESP32_Octa2go_ETH.hpp b/include/platforms/GPIO_Defs_ESP32_Octa2go_ETH.hpp new file mode 100644 index 000000000..ee508d58d --- /dev/null +++ b/include/platforms/GPIO_Defs_ESP32_Octa2go_ETH.hpp @@ -0,0 +1,100 @@ +#pragma once +/* +* GPIO_Defs_ESP32_Octa2go_ETH.hpp - Output Management class +* +* Project: ESPixelStick - An ESP8266 / ESP32 and E1.31 based pixel driver +* Copyright (c) 2024-2026 Shelby Merrick +* http://www.forkineye.com +* +* This program is provided free for you to use in any way that you wish, +* subject to the laws and regulations where you are using it. Due diligence +* is strongly suggested before using this code. Please give credit where due. +* +* The Author makes no warranty of any kind, express or implied, with regard +* to this program or the documentation contained in this document. The +* Author shall not be liable in any event for incidental or consequential +* damages in connection with, or arising out of, the furnishing, performance +* or use of these programs. +* +*/ + +// Output Manager +// MAX 8 Serial port on ESP32 +const OM_OutputPortDefinition_t OM_OutputPortDefinitions[] = +{ + {OM_PortId_t(0), OM_PortType_t::OM_SERIAL, {gpio_num_t::GPIO_NUM_2}}, + {OM_PortId_t(0), OM_PortType_t::OM_RELAY, {gpio_num_t::GPIO_NUM_2}}, + {OM_PortId_t(1), OM_PortType_t::OM_SERIAL, {gpio_num_t::GPIO_NUM_13}}, + {OM_PortId_t(1), OM_PortType_t::OM_RELAY, {gpio_num_t::GPIO_NUM_13}}, + {OM_PortId_t(2), OM_PortType_t::OM_SERIAL, {gpio_num_t::GPIO_NUM_12}}, + {OM_PortId_t(2), OM_PortType_t::OM_RELAY, {gpio_num_t::GPIO_NUM_12}}, + {OM_PortId_t(3), OM_PortType_t::OM_SERIAL, {gpio_num_t::GPIO_NUM_14}}, + {OM_PortId_t(3), OM_PortType_t::OM_RELAY, {gpio_num_t::GPIO_NUM_14}}, + {OM_PortId_t(4), OM_PortType_t::OM_SERIAL, {gpio_num_t::GPIO_NUM_4}}, + {OM_PortId_t(4), OM_PortType_t::OM_RELAY, {gpio_num_t::GPIO_NUM_4}}, + {OM_PortId_t(5), OM_PortType_t::OM_SERIAL, {gpio_num_t::GPIO_NUM_16}}, + {OM_PortId_t(5), OM_PortType_t::OM_RELAY, {gpio_num_t::GPIO_NUM_16}}, + {OM_PortId_t(6), OM_PortType_t::OM_SERIAL, {gpio_num_t::GPIO_NUM_32}}, + {OM_PortId_t(6), OM_PortType_t::OM_RELAY, {gpio_num_t::GPIO_NUM_32}}, + {OM_PortId_t(7), OM_PortType_t::OM_SERIAL, {gpio_num_t::GPIO_NUM_33}}, + {OM_PortId_t(7), OM_PortType_t::OM_RELAY, {gpio_num_t::GPIO_NUM_33}}, + {OM_PortId_t(8), OM_PortType_t::OM_SPI, {gpio_num_t::GPIO_NUM_15, gpio_num_t::GPIO_NUM_25, gpio_num_t::GPIO_NUM_0}}, + {OM_PortId_t(9), OM_PortType_t::OM_I2C, {gpio_num_t::GPIO_NUM_21, gpio_num_t::GPIO_NUM_22}}, +}; + +// File Manager - Defnitions must be present even if SD is not supported +// #define SUPPORT_SD +#define SD_CARD_MISO_PIN gpio_num_t::GPIO_NUM_19 +#define SD_CARD_MOSI_PIN gpio_num_t::GPIO_NUM_23 +#define SD_CARD_CLK_PIN gpio_num_t::GPIO_NUM_18 +#define SD_CARD_CS_PIN gpio_num_t::GPIO_NUM_5 + +#include +#define SUPPORT_ETHERNET + +/* + * ETH_CLOCK_GPIO0_IN - default: external clock from crystal oscillator + * ETH_CLOCK_GPIO0_OUT - 50MHz clock from internal APLL output on GPIO0 - possibly an inverter is needed for LAN8720 + * ETH_CLOCK_GPIO16_OUT - 50MHz clock from internal APLL output on GPIO16 - possibly an inverter is needed for LAN8720 + * ETH_CLOCK_GPIO17_OUT - 50MHz clock from internal APLL inverted output on GPIO17 - tested with LAN8720 +*/ +#define DEFAULT_ETH_CLK_MODE eth_clock_mode_t::ETH_CLOCK_GPIO17_OUT + +// Pin# of the enable signal for the external crystal oscillator (-1 to disable for internal APLL source) +#define DEFAULT_ETH_POWER_PIN gpio_num_t(-1) +#define DEFAULT_ETH_POWER_PIN_ACTIVE HIGH + +// Type of the Ethernet PHY (LAN8720 or TLK110) +#define DEFAULT_ETH_TYPE eth_phy_type_t::ETH_PHY_LAN8720 + +// I2C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110) +// #define ETH_ADDR_PHY_LAN8720 0 +#define ETH_ADDR_PHY_LAN8720 1 +//#define ETH_ADDR_PHY_TLK110 31 +#define DEFAULT_ETH_ADDR ETH_ADDR_PHY_LAN8720 +#define DEFAULT_ETH_TXEN gpio_num_t::GPIO_NUM_21 +#define DEFAULT_ETH_TXD0 gpio_num_t::GPIO_NUM_19 +#define DEFAULT_ETH_TXD1 gpio_num_t::GPIO_NUM_22 +#define DEFAULT_ETH_CRSDV gpio_num_t::GPIO_NUM_27 +#define DEFAULT_ETH_RXD0 gpio_num_t::GPIO_NUM_25 +#define DEFAULT_ETH_RXD1 gpio_num_t::GPIO_NUM_26 +#define DEFAULT_ETH_MDC_PIN gpio_num_t::GPIO_NUM_23 +#define DEFAULT_ETH_MDIO_PIN gpio_num_t::GPIO_NUM_18 + +// Output Types +#define SUPPORT_OutputProtocol_TLS3001 // OM_SERIAL +#define SUPPORT_OutputProtocol_APA102 // OM_SPI +#define SUPPORT_OutputProtocol_DMX // OM_SERIAL +#define SUPPORT_OutputProtocol_GECE // OM_SERIAL +#define SUPPORT_OutputProtocol_GS8208 // OM_SERIAL +#define SUPPORT_OutputProtocol_Renard // OM_SERIAL +#define SUPPORT_OutputProtocol_Serial // OM_SERIAL +#define SUPPORT_OutputProtocol_TM1814 // OM_SERIAL +#define SUPPORT_OutputProtocol_UCS1903 // OM_SERIAL +#define SUPPORT_OutputProtocol_UCS8903 // OM_SERIAL +#define SUPPORT_OutputProtocol_WS2801 // OM_SPI +#define SUPPORT_OutputProtocol_WS2811 // OM_SERIAL +#define SUPPORT_OutputProtocol_Relay // OM_RELAY +#define SUPPORT_OutputProtocol_Servo_PCA9685 // OM_I2C +#define SUPPORT_OutputProtocol_FireGod // OM_SERIAL +#define SUPPORT_OutputProtocol_GRINCH // OM_SPI diff --git a/include/platforms/GPIO_Defs_ESP32_Tetra2go_ETH.hpp b/include/platforms/GPIO_Defs_ESP32_Tetra2go_ETH.hpp new file mode 100644 index 000000000..87efc1a90 --- /dev/null +++ b/include/platforms/GPIO_Defs_ESP32_Tetra2go_ETH.hpp @@ -0,0 +1,92 @@ +#pragma once +/* +* GPIO_Defs_ESP32_Tetra2go.hpp - Output Management class +* +* Project: ESPixelStick - An ESP8266 / ESP32 and E1.31 based pixel driver +* Copyright (c) 2024-2026 Shelby Merrick +* http://www.forkineye.com +* +* This program is provided free for you to use in any way that you wish, +* subject to the laws and regulations where you are using it. Due diligence +* is strongly suggested before using this code. Please give credit where due. +* +* The Author makes no warranty of any kind, express or implied, with regard +* to this program or the documentation contained in this document. The +* Author shall not be liable in any event for incidental or consequential +* damages in connection with, or arising out of, the furnishing, performance +* or use of these programs. +* +*/ + +// Output Manager +// MAX 8 Serial port on ESP32 +const OM_OutputPortDefinition_t OM_OutputPortDefinitions[] = +{ + {OM_PortId_t(0), OM_PortType_t::OM_SERIAL, {gpio_num_t::GPIO_NUM_2}}, + {OM_PortId_t(0), OM_PortType_t::OM_RELAY, {gpio_num_t::GPIO_NUM_2}}, + {OM_PortId_t(1), OM_PortType_t::OM_SERIAL, {gpio_num_t::GPIO_NUM_13}}, + {OM_PortId_t(1), OM_PortType_t::OM_RELAY, {gpio_num_t::GPIO_NUM_13}}, + {OM_PortId_t(2), OM_PortType_t::OM_SERIAL, {gpio_num_t::GPIO_NUM_12}}, + {OM_PortId_t(2), OM_PortType_t::OM_RELAY, {gpio_num_t::GPIO_NUM_12}}, + {OM_PortId_t(3), OM_PortType_t::OM_SERIAL, {gpio_num_t::GPIO_NUM_14}}, + {OM_PortId_t(3), OM_PortType_t::OM_RELAY, {gpio_num_t::GPIO_NUM_14}}, + {OM_PortId_t(4), OM_PortType_t::OM_SPI, {gpio_num_t::GPIO_NUM_15, gpio_num_t::GPIO_NUM_25, gpio_num_t::GPIO_NUM_0}}, + {OM_PortId_t(5), OM_PortType_t::OM_I2C, {gpio_num_t::GPIO_NUM_21, gpio_num_t::GPIO_NUM_22}}, +}; + +// File Manager - Defnitions must be present even if SD is not supported +// #define SUPPORT_SD +#define SD_CARD_MISO_PIN gpio_num_t::GPIO_NUM_19 +#define SD_CARD_MOSI_PIN gpio_num_t::GPIO_NUM_23 +#define SD_CARD_CLK_PIN gpio_num_t::GPIO_NUM_18 +#define SD_CARD_CS_PIN gpio_num_t::GPIO_NUM_5 + +#include +#define SUPPORT_ETHERNET + +/* + * ETH_CLOCK_GPIO0_IN - default: external clock from crystal oscillator + * ETH_CLOCK_GPIO0_OUT - 50MHz clock from internal APLL output on GPIO0 - possibly an inverter is needed for LAN8720 + * ETH_CLOCK_GPIO16_OUT - 50MHz clock from internal APLL output on GPIO16 - possibly an inverter is needed for LAN8720 + * ETH_CLOCK_GPIO17_OUT - 50MHz clock from internal APLL inverted output on GPIO17 - tested with LAN8720 +*/ +#define DEFAULT_ETH_CLK_MODE eth_clock_mode_t::ETH_CLOCK_GPIO17_OUT + +// Pin# of the enable signal for the external crystal oscillator (-1 to disable for internal APLL source) +#define DEFAULT_ETH_POWER_PIN gpio_num_t(-1) +#define DEFAULT_ETH_POWER_PIN_ACTIVE HIGH + +// Type of the Ethernet PHY (LAN8720 or TLK110) +#define DEFAULT_ETH_TYPE eth_phy_type_t::ETH_PHY_LAN8720 + +// I2C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110) +// #define ETH_ADDR_PHY_LAN8720 0 +#define ETH_ADDR_PHY_LAN8720 1 +//#define ETH_ADDR_PHY_TLK110 31 +#define DEFAULT_ETH_ADDR ETH_ADDR_PHY_LAN8720 +#define DEFAULT_ETH_TXEN gpio_num_t::GPIO_NUM_21 +#define DEFAULT_ETH_TXD0 gpio_num_t::GPIO_NUM_19 +#define DEFAULT_ETH_TXD1 gpio_num_t::GPIO_NUM_22 +#define DEFAULT_ETH_CRSDV gpio_num_t::GPIO_NUM_27 +#define DEFAULT_ETH_RXD0 gpio_num_t::GPIO_NUM_25 +#define DEFAULT_ETH_RXD1 gpio_num_t::GPIO_NUM_26 +#define DEFAULT_ETH_MDC_PIN gpio_num_t::GPIO_NUM_23 +#define DEFAULT_ETH_MDIO_PIN gpio_num_t::GPIO_NUM_18 + +// Output Types +#define SUPPORT_OutputProtocol_TLS3001 // OM_SERIAL +#define SUPPORT_OutputProtocol_APA102 // OM_SPI +#define SUPPORT_OutputProtocol_DMX // OM_SERIAL +#define SUPPORT_OutputProtocol_GECE // OM_SERIAL +#define SUPPORT_OutputProtocol_GS8208 // OM_SERIAL +#define SUPPORT_OutputProtocol_Renard // OM_SERIAL +#define SUPPORT_OutputProtocol_Serial // OM_SERIAL +#define SUPPORT_OutputProtocol_TM1814 // OM_SERIAL +#define SUPPORT_OutputProtocol_UCS1903 // OM_SERIAL +#define SUPPORT_OutputProtocol_UCS8903 // OM_SERIAL +#define SUPPORT_OutputProtocol_WS2801 // OM_SPI +#define SUPPORT_OutputProtocol_WS2811 // OM_SERIAL +#define SUPPORT_OutputProtocol_Relay // OM_RELAY +#define SUPPORT_OutputProtocol_Servo_PCA9685 // OM_I2C +#define SUPPORT_OutputProtocol_FireGod // OM_SERIAL +#define SUPPORT_OutputProtocol_GRINCH // OM_SPI From 0202320e2d1af23974660ae7303ef6907f7ad399 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Tue, 23 Jun 2026 19:25:50 -0400 Subject: [PATCH 14/31] Updated a comment. --- include/platforms/GPIO_Defs_ESP32_Tetra2go.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/platforms/GPIO_Defs_ESP32_Tetra2go.hpp b/include/platforms/GPIO_Defs_ESP32_Tetra2go.hpp index f4b8ca226..3c06c783f 100644 --- a/include/platforms/GPIO_Defs_ESP32_Tetra2go.hpp +++ b/include/platforms/GPIO_Defs_ESP32_Tetra2go.hpp @@ -34,7 +34,7 @@ const OM_OutputPortDefinition_t OM_OutputPortDefinitions[] = {OM_PortId_t(5), OM_PortType_t::OM_I2C, {gpio_num_t::GPIO_NUM_21, gpio_num_t::GPIO_NUM_22}}, }; -// File Manager +// File Manager - Defnitions must be present even if SD is not supported #define SUPPORT_SD #define SD_CARD_MISO_PIN gpio_num_t::GPIO_NUM_19 #define SD_CARD_MOSI_PIN gpio_num_t::GPIO_NUM_23 From ce22896bf2a0e4a8f9199cf624916fa983012dec Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Tue, 23 Jun 2026 19:29:58 -0400 Subject: [PATCH 15/31] Added platforms for tetra and octa 2go --- .github/workflows/build.yml | 6 ++++ dist/firmware/firmware.json | 70 +++++++++++++++++++++++++++++++++++++ include/GPIO_Defs.hpp | 4 +++ platformio.ini | 22 +++++++++++- 4 files changed, 101 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a247c389f..dacb7d15c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -107,9 +107,15 @@ jobs: - target: "esp32_tetra2go" chip: "esp32" # + - target: "esp32_tetra2go_eth" + chip: "esp32" + # - target: "esp32_octa2go" chip: "esp32" # + - target: "esp32_octa2go_eth" + chip: "esp32" + # - target: "esp32_solo2go" chip: "esp32" # KR Lights diff --git a/dist/firmware/firmware.json b/dist/firmware/firmware.json index 4482331f1..70d26ff5d 100644 --- a/dist/firmware/firmware.json +++ b/dist/firmware/firmware.json @@ -1144,6 +1144,41 @@ "offset": "0x3B0000" } }, + { + "name": "ESP32 Tetra2go ETH", + "description": "D1 ESP32 based quad controller", + "chip": "esp32", + "appbin": "esp32/esp32_tetra2go_eth-app.bin", + "esptool": { + "baudrate": "460800", + "options": "--before default_reset --after hard_reset", + "flashcmd": "write_flash -z" + }, + "binfiles": [ + { + "name": "esp32/esp32_tetra2go_eth-bootloader.bin", + "offset": "0x01000" + }, + { + "name": "esp32/esp32_tetra2go_eth-partitions.bin", + "offset": "0x08000" + }, + { + "name": "esp32/boot_app0.bin", + "offset": "0x0e000" + }, + { + "name": "esp32/esp32_tetra2go_eth-app.bin", + "offset": "0x10000" + } + ], + "filesystem": { + "page": "256", + "block": "4096", + "size": "0x50000", + "offset": "0x3B0000" + } + }, { "name": "ESP32 Octa2go", "description": "D1 ESP32 based quad controller", @@ -1179,6 +1214,41 @@ "offset": "0x3B0000" } }, + { + "name": "ESP32 Octa2go ETH", + "description": "D1 ESP32 based quad controller", + "chip": "esp32", + "appbin": "esp32/esp32_octa2go_eth-app.bin", + "esptool": { + "baudrate": "460800", + "options": "--before default_reset --after hard_reset", + "flashcmd": "write_flash -z" + }, + "binfiles": [ + { + "name": "esp32/esp32_octa2go_eth-bootloader.bin", + "offset": "0x01000" + }, + { + "name": "esp32/esp32_octa2go_eth-partitions.bin", + "offset": "0x08000" + }, + { + "name": "esp32/boot_app0.bin", + "offset": "0x0e000" + }, + { + "name": "esp32/esp32_octa2go_eth-app.bin", + "offset": "0x10000" + } + ], + "filesystem": { + "page": "256", + "block": "4096", + "size": "0x50000", + "offset": "0x3B0000" + } + }, { "name": "ESP32 Solo2go", "description": "D1 ESP32 based quad controller", diff --git a/include/GPIO_Defs.hpp b/include/GPIO_Defs.hpp index 07938eab3..ef65b72c9 100644 --- a/include/GPIO_Defs.hpp +++ b/include/GPIO_Defs.hpp @@ -106,8 +106,12 @@ # include "platforms/GPIO_Defs_ESP32_ESP3DEUXQuattro_DMX.hpp" #elif defined (BOARD_ESP32_OCTA2GO) # include "platforms/GPIO_Defs_ESP32_Octa2go.hpp" +#elif defined (BOARD_ESP32_OCTA2GO_ETH) +# include "platforms/GPIO_Defs_ESP32_Octa2go_ETH.hpp" #elif defined (BOARD_ESP32_TETRA2GO) # include "platforms/GPIO_Defs_ESP32_Tetra2go.hpp" +#elif defined (BOARD_ESP32_TETRA2GO_ETH) +# include "platforms/GPIO_Defs_ESP32_Tetra2go_ETH.hpp" #elif defined (BOARD_ESP32_SOLO2GO) # include "platforms/GPIO_Defs_ESP32_Solo2go.hpp" #elif defined (BOARD_ESP32_KR_LIGHTS_MSM) diff --git a/platformio.ini b/platformio.ini index ecd275409..41f1b905b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -4,7 +4,7 @@ ; Local configuration should be done in platformio_user.ini [platformio] -default_envs = esp32_idftest, esp8266_espsv3, esp8266_wemos_d1_mini, esp8266_wemos_d1_mini_pro, esp8266_esp01s, esp32_lolin_d1_pro, esp32_lolin_d1_pro_eth, esp32_cam, esp32_ttgo_t8, esp32_bong69, esp32_wt32eth01, esp32_quinled_quad, esp32_quinled_quad_p5, esp32_quinled_quad_ae_plus, esp32_quinled_quad_ae_plus_8, esp32_quinled_quad_eth, esp32_quinled_quad_eth_p5, esp32_quinled_uno, esp32_quinled_uno_ae_plus, esp32_quinled_uno_eth, esp32_quinled_dig_octa, esp32_d1_mini_mhetesp32minikit, esp32_olimex_gw, esp32_d1_mini_twilightlord, esp32_d1_mini_twilightlord_eth, esp32_devkitc, esp32_devkitc6, esp32_quinled_uno_eth_espsv3, esp32_quinled_uno_espsv3, esp32_m5stack_atom, esp32_deuxquatro_dmx, esp32_wasatch, esp32_tetra2go, esp32_octa2go, esp32_solo2go, esp32_kr_lights_msm, esp32_ka, esp32_ka_4, esp32_breakdancev2, esp32_foo, esp32s3_seeed_xiao, esp32_wemos_d1_mini32, esp32_wemos_d1_mini32_eth, esp32s3_devkitc, esp32s3_devkitc_Internal_SD, esp32_devkitv_eth, esp32s3_fh4r2, esp32_relayboardx8 +default_envs = esp32_idftest, esp8266_espsv3, esp8266_wemos_d1_mini, esp8266_wemos_d1_mini_pro, esp8266_esp01s, esp32_lolin_d1_pro, esp32_lolin_d1_pro_eth, esp32_cam, esp32_ttgo_t8, esp32_bong69, esp32_wt32eth01, esp32_quinled_quad, esp32_quinled_quad_p5, esp32_quinled_quad_ae_plus, esp32_quinled_quad_ae_plus_8, esp32_quinled_quad_eth, esp32_quinled_quad_eth_p5, esp32_quinled_uno, esp32_quinled_uno_ae_plus, esp32_quinled_uno_eth, esp32_quinled_dig_octa, esp32_d1_mini_mhetesp32minikit, esp32_olimex_gw, esp32_d1_mini_twilightlord, esp32_d1_mini_twilightlord_eth, esp32_devkitc, esp32_devkitc6, esp32_quinled_uno_eth_espsv3, esp32_quinled_uno_espsv3, esp32_m5stack_atom, esp32_deuxquatro_dmx, esp32_wasatch, esp32_tetra2go, esp32_tetra2go_eth, esp32_octa2go, esp32_octa2go_eth, esp32_solo2go, esp32_kr_lights_msm, esp32_ka, esp32_ka_4, esp32_breakdancev2, esp32_foo, esp32s3_seeed_xiao, esp32_wemos_d1_mini32, esp32_wemos_d1_mini32_eth, esp32s3_devkitc, esp32s3_devkitc_Internal_SD, esp32_devkitv_eth, esp32s3_fh4r2, esp32_relayboardx8 ;default_envs = esp32_idftest src_dir = ./src @@ -573,6 +573,16 @@ build_flags = build_unflags = ${esp32.build_unflags} +[env:esp32_tetra2go_eth] +extends = esp32 +board = wemos_d1_mini32 +build_flags = + ${esp32.build_flags} + -D BOARD_NAME='"esp32 tetra2go ETH"' + -D BOARD_ESP32_TETRA2GO_ETH +build_unflags = + ${esp32.build_unflags} + ; https://rgb2go.com/products/octa2go-8-port-wi-fi-pixel-controller [env:esp32_octa2go] extends = esp32 @@ -584,6 +594,16 @@ build_flags = build_unflags = ${esp32.build_unflags} +[env:esp32_octa2go_eth] +extends = esp32 +board = wemos_d1_mini32 +build_flags = + ${esp32.build_flags} + -D BOARD_NAME='"esp32 octa2go ETH"' + -D BOARD_ESP32_OCTA2GO_ETH +build_unflags = + ${esp32.build_unflags} + ; https://rgb2go.com/products/solo2go-1-port-wi-fi-pixel-controller [env:esp32_solo2go] extends = esp32 From 89a81ce06e67b7e3499ada8f7d58d9d1dfcb4fa0 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Tue, 23 Jun 2026 20:19:18 -0400 Subject: [PATCH 16/31] Cleaned up issue with building 8266 and measuring class size --- src/output/OutputMgr.cpp | 58 ++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/src/output/OutputMgr.cpp b/src/output/OutputMgr.cpp index e00e46f28..f18eaf869 100644 --- a/src/output/OutputMgr.cpp +++ b/src/output/OutputMgr.cpp @@ -145,34 +145,35 @@ static const SupportedOutputProtocol_t SupportedOutputProtocolList[] = #endif // def SUPPORT_OutputProtocol_FireGod }; + + +#ifdef ARDUINO_ARCH_ESP8266 +#define AddUartRmtToProtocolClassList(name) \ + c_ ## name ## Uart name ## Uart; +#else +#define AddUartRmtToProtocolClassList(name) \ + c_ ## name ## Uart name ## Uart; \ + c_ ## name ## Uart name ## Rmt; +#endif // def ARDUINO_ARCH_ESP32 + union alignas(32) OutputProtocolClasses_t { c_OutputDisabled OutputDisabled; #ifdef SUPPORT_OutputProtocol_WS2811 - c_OutputWS2811Uart OutputWS2811Uart; - c_OutputWS2811Rmt OutputWS2811Rmt; + AddUartRmtToProtocolClassList(OutputWS2811); #endif // def SUPPORT_OutputProtocol_WS2811 #ifdef SUPPORT_OutputProtocol_GECE - c_OutputGECEUart OutputGECEUart; - c_OutputGECERmt OutputGECERmt; + AddUartRmtToProtocolClassList(OutputGECE); #endif // def SUPPORT_OutputProtocol_GECE - #ifdef SUPPORT_OutputProtocol_DMX - c_OutputSerialUart OutputDMXUart; - c_OutputSerialRmt OutputDMXRmt; - #endif // def SUPPORT_OutputProtocol_DMX - - #ifdef SUPPORT_OutputProtocol_Renard - c_OutputSerialUart OutputRenardUart; - c_OutputSerialRmt OutputRenardRmt; - #endif // def SUPPORT_OutputProtocol_Renard - - #ifdef SUPPORT_OutputProtocol_Serial - c_OutputSerialUart OutputSerialUart; - c_OutputSerialRmt OutputSerialRmt; - #endif // def SUPPORT_OutputProtocol_Serial + #if defined(SUPPORT_OutputProtocol_DMX) || \ + defined(SUPPORT_OutputProtocol_Renard) || \ + defined(SUPPORT_OutputProtocol_Serial) || \ + defined(SUPPORT_OutputProtocol_FireGod) + AddUartRmtToProtocolClassList(OutputSerial); + #endif #ifdef SUPPORT_OutputProtocol_Relay c_OutputRelay OutputRelay; @@ -183,13 +184,11 @@ union alignas(32) OutputProtocolClasses_t #endif // def SUPPORT_OutputProtocol_Servo_PCA9685 #ifdef SUPPORT_OutputProtocol_UCS1903 - c_OutputUCS1903Uart OutputUCS1903Uart; - c_OutputUCS1903Rmt OutputUCS1903Rmt; + AddUartRmtToProtocolClassList(OutputUCS1903); #endif // def SUPPORT_OutputProtocol_UCS1903 #ifdef SUPPORT_OutputProtocol_TM1814 - c_OutputTM1814Uart OutputTM1814Uart; - c_OutputTM1814Rmt OutputTM1814Rmt; + AddUartRmtToProtocolClassList(OutputTM1814); #endif // def SUPPORT_OutputProtocol_TM1814 #ifdef SUPPORT_OutputProtocol_WS2801 @@ -201,29 +200,24 @@ union alignas(32) OutputProtocolClasses_t #endif // def SUPPORT_OutputProtocol_APA102 #ifdef SUPPORT_OutputProtocol_GS8208 - c_OutputGS8208Uart OutputGS8208Uart; - c_OutputGS8208Rmt OutputGS8208Rmt; + AddUartRmtToProtocolClassList(OutputGS8208); #endif // def SUPPORT_OutputProtocol_GS8208 #ifdef SUPPORT_OutputProtocol_UCS8903 - c_OutputUCS8903Uart OutputUCS8903Uart; - c_OutputUCS8903Rmt OutputUCS8903Rmt; + AddUartRmtToProtocolClassList(OutputUCS8903); #endif // def SUPPORT_OutputProtocol_UCS8903 #ifdef SUPPORT_OutputProtocol_TLS3001 // c_OutputTLS3001Uart OutputTLS3001Uart; - c_OutputTLS3001Rmt OutputTLS3001Rmt; + #ifdef ARDUINO_ARCH_ESP32 + c_OutputTLS3001Rmt OutputTLS3001Rmt; + #endif // def ARDUINO_ARCH_ESP32 #endif // def SUPPORT_OutputProtocol_TLS3001 #ifdef SUPPORT_OutputProtocol_GRINCH c_OutputGrinchSpi OutputGrinchSpi; #endif // def SUPPORT_OutputProtocol_GRINCH - #ifdef SUPPORT_OutputProtocol_FireGod - c_OutputSerialUart OutputFireGodUart; - c_OutputSerialRmt OutputFireGodRmt; - #endif // def SUPPORT_OutputProtocol_FireGod - // Add new types here }; From 1cff6aef309c1f53329eae24e9258d2c22cae907 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Wed, 24 Jun 2026 14:01:29 -0400 Subject: [PATCH 17/31] Added Solo2Go Ethernet support --- .github/workflows/build.yml | 3 + dist/firmware/firmware.json | 37 +++++++- include/GPIO_Defs.hpp | 2 + .../platforms/GPIO_Defs_ESP32_Solo2go_ETH.hpp | 91 +++++++++++++++++++ platformio.ini | 13 ++- 5 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 include/platforms/GPIO_Defs_ESP32_Solo2go_ETH.hpp diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dacb7d15c..f5838d0e6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -118,6 +118,9 @@ jobs: # - target: "esp32_solo2go" chip: "esp32" + # + - target: "esp32_solo2go_eth" + chip: "esp32" # KR Lights - target: "esp32_kr_lights_msm" chip: "esp32" diff --git a/dist/firmware/firmware.json b/dist/firmware/firmware.json index 70d26ff5d..8d20eb117 100644 --- a/dist/firmware/firmware.json +++ b/dist/firmware/firmware.json @@ -1251,7 +1251,7 @@ }, { "name": "ESP32 Solo2go", - "description": "D1 ESP32 based quad controller", + "description": "D1 ESP32 based single port controller", "chip": "esp32", "appbin": "esp32/esp32_solo2go-app.bin", "esptool": { @@ -1284,6 +1284,41 @@ "offset": "0x3B0000" } }, + { + "name": "ESP32 Solo2go ETH", + "description": "D1 ESP32 based Single Port controller", + "chip": "esp32", + "appbin": "esp32/esp32_solo2go_eth-app.bin", + "esptool": { + "baudrate": "460800", + "options": "--before default_reset --after hard_reset", + "flashcmd": "write_flash -z" + }, + "binfiles": [ + { + "name": "esp32/esp32_solo2go_eth-bootloader.bin", + "offset": "0x01000" + }, + { + "name": "esp32/esp32_solo2go_eth-partitions.bin", + "offset": "0x08000" + }, + { + "name": "esp32/boot_app0.bin", + "offset": "0x0e000" + }, + { + "name": "esp32/esp32_solo2go_eth-app.bin", + "offset": "0x10000" + } + ], + "filesystem": { + "page": "256", + "block": "4096", + "size": "0x50000", + "offset": "0x3B0000" + } + }, { "name": "ESP32 KR Lights MSM", "description": "ESP32 based 5 port controller", diff --git a/include/GPIO_Defs.hpp b/include/GPIO_Defs.hpp index ef65b72c9..020745738 100644 --- a/include/GPIO_Defs.hpp +++ b/include/GPIO_Defs.hpp @@ -114,6 +114,8 @@ # include "platforms/GPIO_Defs_ESP32_Tetra2go_ETH.hpp" #elif defined (BOARD_ESP32_SOLO2GO) # include "platforms/GPIO_Defs_ESP32_Solo2go.hpp" +#elif defined (BOARD_ESP32_SOLO2GO_ETH) +# include "platforms/GPIO_Defs_ESP32_Solo2go_ETH.hpp" #elif defined (BOARD_ESP32_KR_LIGHTS_MSM) # include "platforms/GPIO_Defs_ESP32_kr_lights_msm.hpp" #elif defined (BOARD_ESP32_BREAKDANCEV2) diff --git a/include/platforms/GPIO_Defs_ESP32_Solo2go_ETH.hpp b/include/platforms/GPIO_Defs_ESP32_Solo2go_ETH.hpp new file mode 100644 index 000000000..6fcf39f67 --- /dev/null +++ b/include/platforms/GPIO_Defs_ESP32_Solo2go_ETH.hpp @@ -0,0 +1,91 @@ +#pragma once +/* +* GPIO_Defs_ESP32_Solo2go_ETH.hpp - Output Management class +* +* Project: ESPixelStick - An ESP8266 / ESP32 and E1.31 based pixel driver +* Copyright (c) 2025-2026 Shelby Merrick +* http://www.forkineye.com +* +* This program is provided free for you to use in any way that you wish, +* subject to the laws and regulations where you are using it. Due diligence +* is strongly suggested before using this code. Please give credit where due. +* +* The Author makes no warranty of any kind, express or implied, with regard +* to this program or the documentation contained in this document. The +* Author shall not be liable in any event for incidental or consequential +* damages in connection with, or arising out of, the furnishing, performance +* or use of these programs. +* +*/ + +// Output Manager +// MAX 8 Serial port on ESP32 +const OM_OutputPortDefinition_t OM_OutputPortDefinitions[] = +{ + {OM_PortId_t(0), OM_PortType_t::OM_SERIAL, {gpio_num_t::GPIO_NUM_2}}, + {OM_PortId_t(0), OM_PortType_t::OM_RELAY, {gpio_num_t::GPIO_NUM_2}}, + {OM_PortId_t(1), OM_PortType_t::OM_RELAY, {gpio_num_t::GPIO_NUM_17}}, + {OM_PortId_t(2), OM_PortType_t::OM_SPI, {gpio_num_t::GPIO_NUM_25, gpio_num_t::GPIO_NUM_26, gpio_num_t::GPIO_NUM_27}}, + {OM_PortId_t(3), OM_PortType_t::OM_I2C, {gpio_num_t::GPIO_NUM_21, gpio_num_t::GPIO_NUM_22}}, +}; + +// File Manager +// #define SUPPORT_SD +#define SD_CARD_MISO_PIN gpio_num_t::GPIO_NUM_19 +#define SD_CARD_MOSI_PIN gpio_num_t::GPIO_NUM_23 +#define SD_CARD_CLK_PIN gpio_num_t::GPIO_NUM_18 +#define SD_CARD_CS_PIN gpio_num_t::GPIO_NUM_5 + +// Temperature Sensor +#define SUPPORT_SENSOR_DS18B20 +#define ONEWIRE_PIN gpio_num_t::GPIO_NUM_4 + +#include +#define SUPPORT_ETHERNET + +/* + * ETH_CLOCK_GPIO0_IN - default: external clock from crystal oscillator + * ETH_CLOCK_GPIO0_OUT - 50MHz clock from internal APLL output on GPIO0 - possibly an inverter is needed for LAN8720 + * ETH_CLOCK_GPIO16_OUT - 50MHz clock from internal APLL output on GPIO16 - possibly an inverter is needed for LAN8720 + * ETH_CLOCK_GPIO17_OUT - 50MHz clock from internal APLL inverted output on GPIO17 - tested with LAN8720 +*/ +#define DEFAULT_ETH_CLK_MODE eth_clock_mode_t::ETH_CLOCK_GPIO17_OUT + +// Pin# of the enable signal for the external crystal oscillator (-1 to disable for internal APLL source) +#define DEFAULT_ETH_POWER_PIN gpio_num_t(-1) +#define DEFAULT_ETH_POWER_PIN_ACTIVE HIGH + +// Type of the Ethernet PHY (LAN8720 or TLK110) +#define DEFAULT_ETH_TYPE eth_phy_type_t::ETH_PHY_LAN8720 + +// I2C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110) +// #define ETH_ADDR_PHY_LAN8720 0 +#define ETH_ADDR_PHY_LAN8720 1 +//#define ETH_ADDR_PHY_TLK110 31 +#define DEFAULT_ETH_ADDR ETH_ADDR_PHY_LAN8720 +#define DEFAULT_ETH_TXEN gpio_num_t::GPIO_NUM_21 +#define DEFAULT_ETH_TXD0 gpio_num_t::GPIO_NUM_19 +#define DEFAULT_ETH_TXD1 gpio_num_t::GPIO_NUM_22 +#define DEFAULT_ETH_CRSDV gpio_num_t::GPIO_NUM_27 +#define DEFAULT_ETH_RXD0 gpio_num_t::GPIO_NUM_25 +#define DEFAULT_ETH_RXD1 gpio_num_t::GPIO_NUM_26 +#define DEFAULT_ETH_MDC_PIN gpio_num_t::GPIO_NUM_23 +#define DEFAULT_ETH_MDIO_PIN gpio_num_t::GPIO_NUM_18 + +// Output Types +#define SUPPORT_OutputProtocol_TLS3001 // OM_SERIAL +#define SUPPORT_OutputProtocol_APA102 // OM_SPI +#define SUPPORT_OutputProtocol_DMX // OM_SERIAL +#define SUPPORT_OutputProtocol_GECE // OM_SERIAL +#define SUPPORT_OutputProtocol_GS8208 // OM_SERIAL +#define SUPPORT_OutputProtocol_Renard // OM_SERIAL +#define SUPPORT_OutputProtocol_Serial // OM_SERIAL +#define SUPPORT_OutputProtocol_TM1814 // OM_SERIAL +#define SUPPORT_OutputProtocol_UCS1903 // OM_SERIAL +#define SUPPORT_OutputProtocol_UCS8903 // OM_SERIAL +#define SUPPORT_OutputProtocol_WS2801 // OM_SPI +#define SUPPORT_OutputProtocol_WS2811 // OM_SERIAL +#define SUPPORT_OutputProtocol_Relay // OM_RELAY +#define SUPPORT_OutputProtocol_Servo_PCA9685 // OM_I2C +#define SUPPORT_OutputProtocol_FireGod // OM_SERIAL +#define SUPPORT_OutputProtocol_GRINCH // OM_SPI diff --git a/platformio.ini b/platformio.ini index 41f1b905b..44a08c82e 100644 --- a/platformio.ini +++ b/platformio.ini @@ -4,7 +4,7 @@ ; Local configuration should be done in platformio_user.ini [platformio] -default_envs = esp32_idftest, esp8266_espsv3, esp8266_wemos_d1_mini, esp8266_wemos_d1_mini_pro, esp8266_esp01s, esp32_lolin_d1_pro, esp32_lolin_d1_pro_eth, esp32_cam, esp32_ttgo_t8, esp32_bong69, esp32_wt32eth01, esp32_quinled_quad, esp32_quinled_quad_p5, esp32_quinled_quad_ae_plus, esp32_quinled_quad_ae_plus_8, esp32_quinled_quad_eth, esp32_quinled_quad_eth_p5, esp32_quinled_uno, esp32_quinled_uno_ae_plus, esp32_quinled_uno_eth, esp32_quinled_dig_octa, esp32_d1_mini_mhetesp32minikit, esp32_olimex_gw, esp32_d1_mini_twilightlord, esp32_d1_mini_twilightlord_eth, esp32_devkitc, esp32_devkitc6, esp32_quinled_uno_eth_espsv3, esp32_quinled_uno_espsv3, esp32_m5stack_atom, esp32_deuxquatro_dmx, esp32_wasatch, esp32_tetra2go, esp32_tetra2go_eth, esp32_octa2go, esp32_octa2go_eth, esp32_solo2go, esp32_kr_lights_msm, esp32_ka, esp32_ka_4, esp32_breakdancev2, esp32_foo, esp32s3_seeed_xiao, esp32_wemos_d1_mini32, esp32_wemos_d1_mini32_eth, esp32s3_devkitc, esp32s3_devkitc_Internal_SD, esp32_devkitv_eth, esp32s3_fh4r2, esp32_relayboardx8 +default_envs = esp32_idftest, esp8266_espsv3, esp8266_wemos_d1_mini, esp8266_wemos_d1_mini_pro, esp8266_esp01s, esp32_lolin_d1_pro, esp32_lolin_d1_pro_eth, esp32_cam, esp32_ttgo_t8, esp32_bong69, esp32_wt32eth01, esp32_quinled_quad, esp32_quinled_quad_p5, esp32_quinled_quad_ae_plus, esp32_quinled_quad_ae_plus_8, esp32_quinled_quad_eth, esp32_quinled_quad_eth_p5, esp32_quinled_uno, esp32_quinled_uno_ae_plus, esp32_quinled_uno_eth, esp32_quinled_dig_octa, esp32_d1_mini_mhetesp32minikit, esp32_olimex_gw, esp32_d1_mini_twilightlord, esp32_d1_mini_twilightlord_eth, esp32_devkitc, esp32_devkitc6, esp32_quinled_uno_eth_espsv3, esp32_quinled_uno_espsv3, esp32_m5stack_atom, esp32_deuxquatro_dmx, esp32_wasatch, esp32_tetra2go, esp32_tetra2go_eth, esp32_octa2go, esp32_octa2go_eth, esp32_solo2go, esp32_solo2go_eth, esp32_kr_lights_msm, esp32_ka, esp32_ka_4, esp32_breakdancev2, esp32_foo, esp32s3_seeed_xiao, esp32_wemos_d1_mini32, esp32_wemos_d1_mini32_eth, esp32s3_devkitc, esp32s3_devkitc_Internal_SD, esp32_devkitv_eth, esp32s3_fh4r2, esp32_relayboardx8 ;default_envs = esp32_idftest src_dir = ./src @@ -615,6 +615,17 @@ build_flags = build_unflags = ${esp32.build_unflags} +; https://rgb2go.com/products/solo2go-1-port-wi-fi-pixel-controller +[env:esp32_solo2go_eth] +extends = esp32 +board = wemos_d1_mini32 +build_flags = + ${esp32.build_flags} + -D BOARD_NAME='"esp32 solo2go ETH"' + -D BOARD_ESP32_SOLO2GO_ETH +build_unflags = + ${esp32.build_unflags} + ; KR Lights SEED Matrix [env:esp32_kr_lights_msm] extends = esp32 From 65e18db28fe275facdd889c1bff0f162398fe610 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Sun, 28 Jun 2026 23:00:03 -0400 Subject: [PATCH 18/31] Fixed defaults for the user console GPIOs --- include/platforms/GPIO_Defs_ESP32S3_seed_XIAO.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/platforms/GPIO_Defs_ESP32S3_seed_XIAO.hpp b/include/platforms/GPIO_Defs_ESP32S3_seed_XIAO.hpp index 0d3115d7e..4713bc26e 100644 --- a/include/platforms/GPIO_Defs_ESP32S3_seed_XIAO.hpp +++ b/include/platforms/GPIO_Defs_ESP32S3_seed_XIAO.hpp @@ -41,6 +41,10 @@ const OM_OutputPortDefinition_t OM_OutputPortDefinitions[] = #define SD_CARD_CLK_PIN gpio_num_t::GPIO_NUM_7 #define SD_CARD_CS_PIN gpio_num_t::GPIO_NUM_43 +// Special settings for the ESP32S3 Processors +#define DEFAULT_CONSOLE_TX_GPIO gpio_num_t::GPIO_NUM_43 +#define DEFAULT_CONSOLE_RX_GPIO gpio_num_t::GPIO_NUM_44 + // Output Types #define SUPPORT_OutputProtocol_TLS3001 // OM_SERIAL // #define SUPPORT_OutputProtocol_APA102 // OM_SPI From a8baf731ae8e20f451009ad7d558a31b43cc0e2f Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Wed, 1 Jul 2026 15:26:41 -0400 Subject: [PATCH 19/31] Forced Writing to rmt buffer to be inlined. Removed un-needed ISRAM attribute from other functions that are also inlined and not saved to IRAM --- include/output/OutputRmt.hpp | 22 ++++++++++++++++++---- src/output/OutputRmtV4.cpp | 16 +--------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/include/output/OutputRmt.hpp b/include/output/OutputRmt.hpp index aa2126157..0ccda999c 100644 --- a/include/output/OutputRmt.hpp +++ b/include/output/OutputRmt.hpp @@ -106,7 +106,6 @@ class c_OutputRmt void ISR_TransferIntensityDataToRMT (uint32_t NumEntriesToTransfer); size_t ISR_TransferIntensityDataToRMT (rmt_item32_t *symbols, uint32_t MaxNumEntriesToTransfer); void ISR_CreateIntensityData (); - void ISR_WriteToBuffer(rmt_item32_t value); bool ISR_MoreDataToSend(); void StartNewDataFrame(); void ISR_ResetRmtBlockPointers(); @@ -131,7 +130,7 @@ class c_OutputRmt #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) __attribute__((always_inline)) -inline void IRAM_ATTR DisableRmtInterrupts() +inline void DisableRmtInterrupts() { rmt_ll_enable_tx_thres_interrupt(&RMT, OutputRmtConfig.RmtChannelId, false); rmt_ll_enable_tx_end_interrupt(&RMT, OutputRmtConfig.RmtChannelId, false); @@ -140,7 +139,7 @@ inline void IRAM_ATTR DisableRmtInterrupts() } __attribute__((always_inline)) -inline void IRAM_ATTR EnableRmtInterrupts() +inline void EnableRmtInterrupts() { rmt_ll_enable_tx_thres_interrupt(&RMT, OutputRmtConfig.RmtChannelId, true); rmt_ll_enable_tx_end_interrupt(&RMT, OutputRmtConfig.RmtChannelId, true); @@ -148,7 +147,7 @@ inline void IRAM_ATTR EnableRmtInterrupts() } __attribute__((always_inline)) -inline void IRAM_ATTR ClearRmtInterrupts() +inline void ClearRmtInterrupts() { rmt_ll_clear_tx_thres_interrupt(&RMT, OutputRmtConfig.RmtChannelId); rmt_ll_clear_tx_end_interrupt(&RMT, OutputRmtConfig.RmtChannelId); @@ -203,5 +202,20 @@ inline void IRAM_ATTR ClearRmtInterrupts() #endif // def USE_RMT_DEBUG_COUNTERS +private: +__attribute__((always_inline)) +inline void WriteToBuffer(rmt_item32_t value) +{ + /// DEBUG_START; + + RMT_DEBUG_COUNTER(WriteToBuffer++); + + SendBuffer[SendBufferWriteIndex++] = value; + SendBufferWriteIndex &= uint32_t(NumSendBufferSlots - 1); + ++NumUsedEntriesInSendBuffer; + + ///DEBUG_END; +} + }; #endif // def #ifdef ARDUINO_ARCH_ESP32 \ No newline at end of file diff --git a/src/output/OutputRmtV4.cpp b/src/output/OutputRmtV4.cpp index 3c64f2855..7ec66103f 100644 --- a/src/output/OutputRmtV4.cpp +++ b/src/output/OutputRmtV4.cpp @@ -361,7 +361,7 @@ void IRAM_ATTR c_OutputRmt::ISR_CreateIntensityData () // no more data to send break; } - ISR_WriteToBuffer(Data); + WriteToBuffer(Data); --NumAvailableBufferSlotsToFill; }; @@ -503,20 +503,6 @@ void IRAM_ATTR c_OutputRmt::ISR_TransferIntensityDataToRMT (uint32_t MaxNumEntri } // ISR_TransferIntensityDataToRMT -//---------------------------------------------------------------------------- -inline void IRAM_ATTR c_OutputRmt::ISR_WriteToBuffer(rmt_item32_t value) -{ - /// DEBUG_START; - - RMT_DEBUG_COUNTER(WriteToBuffer++); - - SendBuffer[SendBufferWriteIndex++] = value; - SendBufferWriteIndex &= uint32_t(NumSendBufferSlots - 1); - ++NumUsedEntriesInSendBuffer; - - ///DEBUG_END; -} - //---------------------------------------------------------------------------- void c_OutputRmt::PauseOutput(bool PauseOutput) { From 255736f9a134d0d4e9553dabda95b5ab76c3931b Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Thu, 2 Jul 2026 22:55:04 -0400 Subject: [PATCH 20/31] Refactored to remove magic numbers and questionable calculations to determine RMT capabilities. --- include/output/OutputRmt.hpp | 33 ++++++++++++--------------------- src/output/OutputRmtV4.cpp | 20 +++++++++----------- 2 files changed, 21 insertions(+), 32 deletions(-) diff --git a/include/output/OutputRmt.hpp b/include/output/OutputRmt.hpp index 0ccda999c..58a07cb0f 100644 --- a/include/output/OutputRmt.hpp +++ b/include/output/OutputRmt.hpp @@ -62,14 +62,11 @@ class c_OutputRmt }; private: -#ifdef CONFIG_IDF_TARGET_ESP32S3 -# define MAX_NUM_RMT_CHANNELS 4 -#else -# define MAX_NUM_RMT_CHANNELS 8 -#endif // def CONFIG_IDF_TARGET_ESP32S3 + +#define MAX_NUM_RMT_CHANNELS SOC_RMT_TX_CANDIDATES_PER_GROUP +#define NUM_RMT_SLOTS SOC_RMT_MEM_WORDS_PER_CHANNEL #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) - #define _NUM_RMT_SLOTS 64 rmt_channel_handle_t rmt_channel_handle; rmt_encoder_handle_t rmt_encoder_handle; rmt_transmit_config_t tx_config = @@ -84,19 +81,17 @@ class c_OutputRmt #else #define RMT_INT_BIT uint32_t(1 << uint32_t (OutputRmtConfig.RmtChannelId)) #define InterrupsAreEnabled (0 != (RMT.int_ena.val & RMT_INT_BIT)) - - #define _NUM_RMT_SLOTS (sizeof(RMTMEM.chan[0].data32) / sizeof(RMTMEM.chan[0].data32[0])) + rmt_item32_t * RmtChanData = nullptr; #endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) - const uint32_t NUM_RMT_SLOTS = _NUM_RMT_SLOTS; OutputRmtConfig_t OutputRmtConfig; bool OutputIsPaused = false; uint32_t NumRmtSlotOverruns = 0; - const uint32_t MaxNumRmtSlotsPerInterrupt = (_NUM_RMT_SLOTS/2); + const uint32_t MaxNumRmtSlotsPerInterrupt = (NUM_RMT_SLOTS/2); - #define NumSendBufferSlots 64 // Must be a power of 2 + #define NumSendBufferSlots 64 rmt_item32_t SendBuffer[NumSendBufferSlots]; uint32_t RmtBufferWriteIndex = 0; uint32_t SendBufferWriteIndex = 0; @@ -136,7 +131,7 @@ inline void DisableRmtInterrupts() rmt_ll_enable_tx_end_interrupt(&RMT, OutputRmtConfig.RmtChannelId, false); rmt_ll_enable_tx_err_interrupt(&RMT, OutputRmtConfig.RmtChannelId, false); ClearRmtInterrupts(); -} +} // DisableRmtInterrupts __attribute__((always_inline)) inline void EnableRmtInterrupts() @@ -144,7 +139,7 @@ inline void EnableRmtInterrupts() rmt_ll_enable_tx_thres_interrupt(&RMT, OutputRmtConfig.RmtChannelId, true); rmt_ll_enable_tx_end_interrupt(&RMT, OutputRmtConfig.RmtChannelId, true); rmt_ll_enable_tx_err_interrupt(&RMT, OutputRmtConfig.RmtChannelId, true); -} +} // EnableRmtInterrupts __attribute__((always_inline)) inline void ClearRmtInterrupts() @@ -152,7 +147,7 @@ inline void ClearRmtInterrupts() rmt_ll_clear_tx_thres_interrupt(&RMT, OutputRmtConfig.RmtChannelId); rmt_ll_clear_tx_end_interrupt(&RMT, OutputRmtConfig.RmtChannelId); rmt_ll_clear_tx_err_interrupt(&RMT, OutputRmtConfig.RmtChannelId); -} +} // ClearRmtInterrupts #endif // ndef rmt_ll_clear_tx_thres_interrupt #define RMT_ClockRate 80000000.0 @@ -206,16 +201,12 @@ inline void ClearRmtInterrupts() __attribute__((always_inline)) inline void WriteToBuffer(rmt_item32_t value) { - /// DEBUG_START; - RMT_DEBUG_COUNTER(WriteToBuffer++); - SendBuffer[SendBufferWriteIndex++] = value; - SendBufferWriteIndex &= uint32_t(NumSendBufferSlots - 1); + SendBuffer[SendBufferWriteIndex] = value; + if(++SendBufferWriteIndex >= NumSendBufferSlots) {SendBufferWriteIndex = 0;} ++NumUsedEntriesInSendBuffer; - - ///DEBUG_END; -} +} // WriteToBuffer }; #endif // def #ifdef ARDUINO_ARCH_ESP32 \ No newline at end of file diff --git a/src/output/OutputRmtV4.cpp b/src/output/OutputRmtV4.cpp index 7ec66103f..1eb7ce3a6 100644 --- a/src/output/OutputRmtV4.cpp +++ b/src/output/OutputRmtV4.cpp @@ -204,6 +204,8 @@ void c_OutputRmt::Begin (OutputRmtConfig_t config, c_OutputCommon * _pParent ) ResetGpio(OutputRmtConfig.DataPin); ESP_ERROR_CHECK(rmt_config(&RmtConfig)); + RmtChanData = (rmt_item32_t *)&(RMTMEM.chan[OutputRmtConfig.RmtChannelId].data32[0]); + // DEBUG_V(); if(NULL == RMT_intr_handle) @@ -471,27 +473,23 @@ void IRAM_ATTR c_OutputRmt::ISR_TransferIntensityDataToRMT (uint32_t MaxNumEntri { // DEBUG_START; - uint32_t NumEntriesToTransfer = min(NumUsedEntriesInSendBuffer, MaxNumEntriesToTransfer); + uint32_t NumEntriesToTransfer = NumUsedEntriesInSendBuffer; + if(NumEntriesToTransfer > MaxNumEntriesToTransfer) {NumEntriesToTransfer = MaxNumEntriesToTransfer;} RMT_DEBUG_COUNTER(RmtXmtFills++); #ifdef USE_RMT_DEBUG_COUNTERS RmtEntriesTransfered = NumEntriesToTransfer; #endif // def USE_RMT_DEBUG_COUNTERS - rmt_item32_t * RmtChanData = (rmt_item32_t *)&(RMTMEM.chan[OutputRmtConfig.RmtChannelId].data32[0]); - while(NumEntriesToTransfer) { - // DEBUG_V(String(" Data.level0: ") + String(SendBuffer[SendBufferReadIndex].level0)); - // DEBUG_V(String("Data.duration0: ") + String(SendBuffer[SendBufferReadIndex].duration0)); - // DEBUG_V(String(" Data.level1: ") + String(SendBuffer[SendBufferReadIndex].level1)); - // DEBUG_V(String("Data.duration1: ") + String(SendBuffer[SendBufferReadIndex].duration1)); - RMT_DEBUG_COUNTER(WriteToRmt++); - RmtChanData[RmtBufferWriteIndex++].val = SendBuffer[SendBufferReadIndex++].val; - RmtBufferWriteIndex = (RmtBufferWriteIndex >= NUM_RMT_SLOTS ? 0 : RmtBufferWriteIndex); // do wrap - SendBufferReadIndex &= (NumSendBufferSlots - 1); // do wrap + RmtChanData[RmtBufferWriteIndex] = SendBuffer[SendBufferReadIndex]; + + if(++RmtBufferWriteIndex >= NUM_RMT_SLOTS) {RmtBufferWriteIndex = 0;} // do wrap + if(++SendBufferReadIndex >= NumSendBufferSlots) {SendBufferReadIndex = 0;} // do wrap + --NumEntriesToTransfer; --NumUsedEntriesInSendBuffer; } From 491e7b1487980accf9d8506bbdaa92d285c7b869 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Fri, 10 Jul 2026 15:24:20 -0400 Subject: [PATCH 21/31] Refactored RMT Debug counter support in preparation for supporting S3 --- include/output/OutputRmt.hpp | 58 ++++++++++++----------- include/output/OutputWS2811Rmt.hpp | 8 ++-- src/output/OutputRmtV4.cpp | 74 +++++++++++++++--------------- src/output/OutputWS2811Rmt.cpp | 8 ++-- 4 files changed, 75 insertions(+), 73 deletions(-) diff --git a/include/output/OutputRmt.hpp b/include/output/OutputRmt.hpp index 58a07cb0f..bc9cc94d9 100644 --- a/include/output/OutputRmt.hpp +++ b/include/output/OutputRmt.hpp @@ -130,7 +130,6 @@ inline void DisableRmtInterrupts() rmt_ll_enable_tx_thres_interrupt(&RMT, OutputRmtConfig.RmtChannelId, false); rmt_ll_enable_tx_end_interrupt(&RMT, OutputRmtConfig.RmtChannelId, false); rmt_ll_enable_tx_err_interrupt(&RMT, OutputRmtConfig.RmtChannelId, false); - ClearRmtInterrupts(); } // DisableRmtInterrupts __attribute__((always_inline)) @@ -165,31 +164,36 @@ inline void ClearRmtInterrupts() #ifdef USE_RMT_DEBUG_COUNTERS // #define IncludeBufferData // debug counters - uint32_t DataCallbackCounter = 0; - uint32_t DataTaskcounter = 0; - uint32_t ISRcounter = 0; - uint32_t FrameStartCounter = 0; - uint32_t SendBlockIsrCounter = 0; - uint32_t RanOutOfData = 0; - uint32_t UnknownISRcounter = 0; - uint32_t IntTxEndIsrCounter = 0; - uint32_t IntTxThrIsrCounter = 0; - uint32_t RxIsr = 0; - uint32_t ErrorIsr = 0; - uint32_t IntensityValuesSent = 0; - uint32_t IntensityBitsSent = 0; - uint32_t IntensityValuesSentLastFrame = 0; - uint32_t IntensityBitsSentLastFrame = 0; - uint32_t IncompleteFrame = 0; - uint32_t RmtEntriesTransfered = 0; - uint32_t RmtXmtFills = 0; - uint32_t ISRpaused = 0; - uint32_t RmtWhiteDetected = 0; - uint32_t FailedToSendAllData = 0; - uint32_t WriteToBuffer = 0; - uint32_t WriteToRmt = 0; - -#define RMT_DEBUG_COUNTER(p) p + struct RmtDebugCounters_t + { + uint32_t DataCallbackCounter = 0; + uint32_t DataTaskcounter = 0; + uint32_t ISRcounter = 0; + uint32_t FrameStartCounter = 0; + uint32_t SendBlockIsrCounter = 0; + uint32_t RanOutOfData = 0; + uint32_t UnknownISRcounter = 0; + uint32_t IntTxEndIsrCounter = 0; + uint32_t IntTxThrIsrCounter = 0; + uint32_t RxIsr = 0; + uint32_t ErrorIsr = 0; + uint32_t IntensityValuesSent = 0; + uint32_t IntensityBitsSent = 0; + uint32_t IntensityValuesSentLastFrame = 0; + uint32_t IntensityBitsSentLastFrame = 0; + uint32_t IncompleteFrame = 0; + uint32_t RmtEntriesTransfered = 0; + uint32_t RmtXmtFills = 0; + uint32_t ISRpaused = 0; + uint32_t RmtWhiteDetected = 0; + uint32_t FailedToSendAllData = 0; + uint32_t WriteToBuffer = 0; + uint32_t WriteToRmt = 0; + } ; + RmtDebugCounters_t RmtDebugCounters; + +#define RMT_DEBUG_INC_COUNTER(p) (++RmtDebugCounters.p) +#define RMT_DEBUG_COUNTER(p) (RmtDebugCounters.p) #else @@ -201,7 +205,7 @@ inline void ClearRmtInterrupts() __attribute__((always_inline)) inline void WriteToBuffer(rmt_item32_t value) { - RMT_DEBUG_COUNTER(WriteToBuffer++); + RMT_DEBUG_INC_COUNTER(WriteToBuffer); SendBuffer[SendBufferWriteIndex] = value; if(++SendBufferWriteIndex >= NumSendBufferSlots) {SendBufferWriteIndex = 0;} diff --git a/include/output/OutputWS2811Rmt.hpp b/include/output/OutputWS2811Rmt.hpp index 261cfaa66..ee73bb67a 100644 --- a/include/output/OutputWS2811Rmt.hpp +++ b/include/output/OutputWS2811Rmt.hpp @@ -48,11 +48,7 @@ class c_OutputWS2811Rmt : public c_OutputWS2811 private: -#ifdef USE_RMT_DEBUG_COUNTERS - uint32_t CanRefresh = 0; - uint32_t CannotRefresh = 0; -#endif // def USE_RMT_DEBUG_COUNTERS -// The adjustments compensate for rounding errors in the calculations + // The adjustments compensate for rounding errors in the calculations #define WS2811_PIXEL_RMT_TICKS_BIT_0_HIGH uint16_t ( (WS2811_PIXEL_NS_BIT_0_HIGH / RMT_TickLengthNS) + 0.0) #define WS2811_PIXEL_RMT_TICKS_BIT_0_LOW uint16_t ( (WS2811_PIXEL_NS_BIT_0_LOW / RMT_TickLengthNS) + 0.0) #define WS2811_PIXEL_RMT_TICKS_BIT_1_HIGH uint16_t ( (WS2811_PIXEL_NS_BIT_1_HIGH / RMT_TickLengthNS) - 1.0) @@ -81,6 +77,8 @@ class c_OutputWS2811Rmt : public c_OutputWS2811 uint32_t DataBytes = 0; uint32_t StopBits = 0; uint32_t Underrun = 0; + uint32_t CanRefresh = 0; + uint32_t CannotRefresh = 0; } RmtDebugCounters; #else #define INC_WS2811_RMT_DEBUG_COUNTERS(c) diff --git a/src/output/OutputRmtV4.cpp b/src/output/OutputRmtV4.cpp index 1eb7ce3a6..76e79c4de 100644 --- a/src/output/OutputRmtV4.cpp +++ b/src/output/OutputRmtV4.cpp @@ -119,7 +119,7 @@ c_OutputRmt::~c_OutputRmt () */ static void IRAM_ATTR rmt_intr_handler (void* param) { - RMT_DEBUG_COUNTER(RawIsrCounter++); + RawIsrCounter++; #ifdef DEBUG_GPIO // digitalWrite(DEBUG_GPIO, HIGH); #endif // def DEBUG_GPIO @@ -265,30 +265,30 @@ void c_OutputRmt::GetStatus (ArduinoJson::JsonObject& jsonStatus) #endif // def CONFIG_IDF_TARGET_ESP32S3 - debugStatus["ErrorIsr"] = ErrorIsr; + debugStatus["ErrorIsr"] = RMT_DEBUG_COUNTER(ErrorIsr); debugStatus["FrameCompletes"] = FrameCompletes; - debugStatus["FrameStartCounter"] = FrameStartCounter; + debugStatus["FrameStartCounter"] = RMT_DEBUG_COUNTER(FrameStartCounter); debugStatus["FrameTimeouts"] = FrameTimeouts; - debugStatus["FailedToSendAllData"] = FailedToSendAllData; - debugStatus["IncompleteFrame"] = IncompleteFrame; - debugStatus["IntensityValuesSent"] = IntensityValuesSent; - debugStatus["IntensityValuesSentLastFrame"] = IntensityValuesSentLastFrame; - debugStatus["IntensityBitsSent"] = IntensityBitsSent; - debugStatus["IntensityBitsSentLastFrame"] = IntensityBitsSentLastFrame; - debugStatus["IntTxEndIsrCounter"] = IntTxEndIsrCounter; - debugStatus["IntTxThrIsrCounter"] = IntTxThrIsrCounter; - debugStatus["ISRcounter"] = ISRcounter; - debugStatus["RanOutOfData"] = RanOutOfData; + debugStatus["FailedToSendAllData"] = RMT_DEBUG_COUNTER(FailedToSendAllData); + debugStatus["IncompleteFrame"] = RMT_DEBUG_COUNTER(IncompleteFrame); + debugStatus["IntensityValuesSent"] = RMT_DEBUG_COUNTER(IntensityValuesSent); + debugStatus["IntensityValuesSentLastFrame"] = RMT_DEBUG_COUNTER(IntensityValuesSentLastFrame); + debugStatus["IntensityBitsSent"] = RMT_DEBUG_COUNTER(IntensityBitsSent); + debugStatus["IntensityBitsSentLastFrame"] = RMT_DEBUG_COUNTER(IntensityBitsSentLastFrame); + debugStatus["IntTxEndIsrCounter"] = RMT_DEBUG_COUNTER(IntTxEndIsrCounter); + debugStatus["IntTxThrIsrCounter"] = RMT_DEBUG_COUNTER(IntTxThrIsrCounter); + debugStatus["ISRcounter"] = RMT_DEBUG_COUNTER(ISRcounter); + debugStatus["RanOutOfData"] = RMT_DEBUG_COUNTER(RanOutOfData); debugStatus["RawIsrCounter"] = RawIsrCounter; debugStatus["RMT_INT_BIT"] = "0x" + String (RMT_INT_BIT, HEX); - debugStatus["RmtEntriesTransfered"] = RmtEntriesTransfered; - debugStatus["RmtWhiteDetected"] = RmtWhiteDetected; - debugStatus["RmtXmtFills"] = RmtXmtFills; - debugStatus["RxIsr"] = RxIsr; - debugStatus["SendBlockIsrCounter"] = SendBlockIsrCounter; - debugStatus["UnknownISRcounter"] = UnknownISRcounter; - debugStatus["WriteToBuffer"] = WriteToBuffer; - debugStatus["WriteToRmt"] = WriteToRmt; + debugStatus["RmtEntriesTransfered"] = RMT_DEBUG_COUNTER(RmtEntriesTransfered); + debugStatus["RmtWhiteDetected"] = RMT_DEBUG_COUNTER(RmtWhiteDetected); + debugStatus["RmtXmtFills"] = RMT_DEBUG_COUNTER(RmtXmtFills); + debugStatus["RxIsr"] = RMT_DEBUG_COUNTER(RxIsr); + debugStatus["SendBlockIsrCounter"] = RMT_DEBUG_COUNTER(SendBlockIsrCounter); + debugStatus["UnknownISRcounter"] = RMT_DEBUG_COUNTER(UnknownISRcounter); + debugStatus["WriteToBuffer"] = RMT_DEBUG_COUNTER(WriteToBuffer); + debugStatus["WriteToRmt"] = RMT_DEBUG_COUNTER(WriteToRmt); #ifdef IncludeBufferData { @@ -381,7 +381,7 @@ void IRAM_ATTR c_OutputRmt::ISR_Handler (isrTxFlags_t isrTxFlags) ///DEBUG_V(String(" RMT_INT_BIT: 0x") + String(RMT_INT_BIT, HEX)); // ClearRmtInterrupts; - RMT_DEBUG_COUNTER(++ISRcounter); + RMT_DEBUG_INC_COUNTER(ISRcounter); if(OutputIsPaused) { DisableRmtInterrupts(); @@ -389,12 +389,12 @@ void IRAM_ATTR c_OutputRmt::ISR_Handler (isrTxFlags_t isrTxFlags) // did the transmitter stall? else if (isrTxFlags.End & RMT_INT_BIT ) { - RMT_DEBUG_COUNTER(++IntTxEndIsrCounter); + RMT_DEBUG_INC_COUNTER(IntTxEndIsrCounter); DisableRmtInterrupts(); if(NumUsedEntriesInSendBuffer) { - RMT_DEBUG_COUNTER(++FailedToSendAllData); + RMT_DEBUG_INC_COUNTER(FailedToSendAllData); } // tell the background task to start the next output @@ -403,13 +403,13 @@ void IRAM_ATTR c_OutputRmt::ISR_Handler (isrTxFlags_t isrTxFlags) } else if (isrTxFlags.Thres & RMT_INT_BIT ) { - RMT_DEBUG_COUNTER(++IntTxThrIsrCounter); + RMT_DEBUG_INC_COUNTER(IntTxThrIsrCounter); // do we still have data to send? if(NumUsedEntriesInSendBuffer) { // LOG_PORT.println(String("NumUsedEntriesInSendBuffer1: ") + String(NumUsedEntriesInSendBuffer)); - RMT_DEBUG_COUNTER(++SendBlockIsrCounter); + RMT_DEBUG_INC_COUNTER(SendBlockIsrCounter); // transfer any prefetched data to the hardware transmitter ISR_TransferIntensityDataToRMT( MaxNumRmtSlotsPerInterrupt ); // LOG_PORT.println(String("NumUsedEntriesInSendBuffer2: ") + String(NumUsedEntriesInSendBuffer)); @@ -421,7 +421,7 @@ void IRAM_ATTR c_OutputRmt::ISR_Handler (isrTxFlags_t isrTxFlags) // is there any data left to enqueue? if (0 == NumUsedEntriesInSendBuffer) { - RMT_DEBUG_COUNTER(++RanOutOfData); + RMT_DEBUG_INC_COUNTER(RanOutOfData); DisableRmtInterrupts(); // tell the background task to start the next output @@ -433,10 +433,10 @@ void IRAM_ATTR c_OutputRmt::ISR_Handler (isrTxFlags_t isrTxFlags) #ifdef USE_RMT_DEBUG_COUNTERS else { - RMT_DEBUG_COUNTER(++UnknownISRcounter); + RMT_DEBUG_INC_COUNTER(UnknownISRcounter); if (isrTxFlags.Err & RMT_INT_BIT) { - ErrorIsr++; + RMT_DEBUG_INC_COUNTER(ErrorIsr); } } #endif // def USE_RMT_DEBUG_COUNTERS @@ -476,14 +476,14 @@ void IRAM_ATTR c_OutputRmt::ISR_TransferIntensityDataToRMT (uint32_t MaxNumEntri uint32_t NumEntriesToTransfer = NumUsedEntriesInSendBuffer; if(NumEntriesToTransfer > MaxNumEntriesToTransfer) {NumEntriesToTransfer = MaxNumEntriesToTransfer;} - RMT_DEBUG_COUNTER(RmtXmtFills++); + RMT_DEBUG_INC_COUNTER(RmtXmtFills); #ifdef USE_RMT_DEBUG_COUNTERS - RmtEntriesTransfered = NumEntriesToTransfer; + RMT_DEBUG_COUNTER(RmtEntriesTransfered) = NumEntriesToTransfer; #endif // def USE_RMT_DEBUG_COUNTERS while(NumEntriesToTransfer) { - RMT_DEBUG_COUNTER(WriteToRmt++); + RMT_DEBUG_INC_COUNTER(WriteToRmt); RmtChanData[RmtBufferWriteIndex] = SendBuffer[SendBufferReadIndex]; @@ -551,11 +551,11 @@ bool c_OutputRmt::StartNewFrame () // DEBUG_V(); #ifdef USE_RMT_DEBUG_COUNTERS - FrameStartCounter++; - IntensityValuesSentLastFrame = IntensityValuesSent; - IntensityValuesSent = 0; - IntensityBitsSentLastFrame = IntensityBitsSent; - IntensityBitsSent = 0; + RMT_DEBUG_INC_COUNTER(FrameStartCounter); + RMT_DEBUG_COUNTER(IntensityValuesSentLastFrame) = RMT_DEBUG_COUNTER(IntensityValuesSent); + RMT_DEBUG_COUNTER(IntensityValuesSent) = 0; + RMT_DEBUG_COUNTER(IntensityBitsSentLastFrame) = RMT_DEBUG_COUNTER(IntensityBitsSent); + RMT_DEBUG_COUNTER(IntensityBitsSent) = 0; #endif // def USE_RMT_DEBUG_COUNTERS // set up to send a new frame diff --git a/src/output/OutputWS2811Rmt.cpp b/src/output/OutputWS2811Rmt.cpp index 7718123fd..528937ddc 100644 --- a/src/output/OutputWS2811Rmt.cpp +++ b/src/output/OutputWS2811Rmt.cpp @@ -124,8 +124,6 @@ void c_OutputWS2811Rmt::GetStatus (ArduinoJson::JsonObject& jsonStatus) c_OutputWS2811::GetStatus (jsonStatus); Rmt.GetStatus (jsonStatus); #ifdef USE_RMT_DEBUG_COUNTERS - jsonStatus[F("Can Refresh")] = CanRefresh; - jsonStatus[F("Cannot Refresh")] = CannotRefresh; jsonStatus[F("FrameDurationInMicroSec")] = FrameDurationInMicroSec; jsonStatus[F("FrameStartTimeInMicroSec")] = GetFrameStartTimeInMicroSec(); uint32_t now = micros(); @@ -142,6 +140,8 @@ void c_OutputWS2811Rmt::GetStatus (ArduinoJson::JsonObject& jsonStatus) JsonWrite(JsonCounters, "DataBits", RmtDebugCounters.DataBits); JsonWrite(JsonCounters, "StopBits", RmtDebugCounters.StopBits); JsonWrite(JsonCounters, "Underrun", RmtDebugCounters.Underrun); + JsonWrite(JsonCounters, "Can Refresh", CanRefresh); + JsonWrite(JsonCounters, "Cannot Refresh", Cannot); #endif // def WS2811_RMT_DEBUG_COUNTERS // // DEBUG_END; @@ -171,12 +171,12 @@ bool c_OutputWS2811Rmt::RmtPoll () if(!canRefresh()) { - RMT_DEBUG_COUNTER(CannotRefresh++); + INC_WS2811_RMT_DEBUG_COUNTERS(CannotRefresh); // DEBUG_V ("not ready to send yet"); break; } - RMT_DEBUG_COUNTER(CanRefresh++); + INC_WS2811_RMT_DEBUG_COUNTERS(CanRefresh); // DEBUG_V(String("get the next frame started on ") + String(DataPin)); Response = Rmt.StartNewFrame (); From ce4bfda8e720e41200ae9e4f3eee4d380846f337 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Fri, 17 Jul 2026 07:29:29 -0400 Subject: [PATCH 22/31] Fixed missing options flags on some platforms --- dist/firmware/firmware.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dist/firmware/firmware.json b/dist/firmware/firmware.json index 8d20eb117..63a20a067 100644 --- a/dist/firmware/firmware.json +++ b/dist/firmware/firmware.json @@ -1326,7 +1326,7 @@ "appbin": "esp32/esp32_kr_lights_msm-app.bin", "esptool": { "baudrate": "460800", - "options": "", + "options": "--before default_reset --after hard_reset", "flashcmd": "write_flash -z" }, "binfiles": [ @@ -1361,7 +1361,7 @@ "appbin": "esp32/esp32_ka-app.bin", "esptool": { "baudrate": "460800", - "options": "", + "options": "--before default_reset --after hard_reset", "flashcmd": "write_flash -z" }, "binfiles": [ @@ -1396,7 +1396,7 @@ "appbin": "esp32/esp32_ka_4-app.bin", "esptool": { "baudrate": "460800", - "options": "", + "options": "--before default_reset --after hard_reset", "flashcmd": "write_flash -z" }, "binfiles": [ @@ -1431,7 +1431,7 @@ "appbin": "esp32/esp32_breakdancev2-app.bin", "esptool": { "baudrate": "460800", - "options": "", + "options": "--before default_reset --after hard_reset", "flashcmd": "write_flash -z" }, "binfiles": [ @@ -1466,7 +1466,7 @@ "appbin": "esp32/esp32_relayboardx8-app.bin", "esptool": { "baudrate": "460800", - "options": "", + "options": "--before default_reset --after hard_reset", "flashcmd": "write_flash -z" }, "binfiles": [ @@ -1501,7 +1501,7 @@ "appbin": "esp32s3/esp32s3_devkitc-app.bin", "esptool": { "baudrate": "460800", - "options": "", + "options": "--before default_reset --after hard_reset", "flashcmd": "write_flash -z" }, "binfiles": [ @@ -1536,7 +1536,7 @@ "appbin": "esp32s3/esp32s3_devkitc_Internal_SD-app.bin", "esptool": { "baudrate": "460800", - "options": "", + "options": "--before default_reset --after hard_reset", "flashcmd": "write_flash -z" }, "binfiles": [ @@ -1606,7 +1606,7 @@ "appbin": "esp32/esp32_devkitv_eth-app.bin", "esptool": { "baudrate": "460800", - "options": "", + "options": "--before default_reset --after hard_reset", "flashcmd": "write_flash -z" }, "binfiles": [ From 6cd93efae9810092bb2a4d51e00cd2685bac3fef Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Fri, 17 Jul 2026 23:45:08 -0400 Subject: [PATCH 23/31] Added missing definition for RMT debug increment when debug is turned off --- include/output/OutputRmt.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/output/OutputRmt.hpp b/include/output/OutputRmt.hpp index bc9cc94d9..d55c686b7 100644 --- a/include/output/OutputRmt.hpp +++ b/include/output/OutputRmt.hpp @@ -197,6 +197,7 @@ inline void ClearRmtInterrupts() #else +#define RMT_DEBUG_INC_COUNTER(p) #define RMT_DEBUG_COUNTER(p) #endif // def USE_RMT_DEBUG_COUNTERS From 632ed124764f38447e91922b3789c49b1c0cbf00 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Fri, 17 Jul 2026 23:45:51 -0400 Subject: [PATCH 24/31] Updated IDF version output --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index fd432c7fc..c17a813b6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -198,7 +198,7 @@ void setup() #ifdef ARDUINO_ARCH_ESP8266 logcon (ESP.getFullVersion ()); #else - logcon (ESP.getSdkVersion ()); + logcon (String("ESP_IDF_VERSION:") + String(esp_get_idf_version())); #endif // TestHeap(uint32_t(10)); @@ -707,7 +707,7 @@ void FeedWDT () // esp_task_wdt_reset (); rtc_wdt_protect_off(); rtc_wdt_disable(); - esp_task_wdt_deinit(); + // esp_task_wdt_deinit(); #else esp_task_wdt_reset (); #endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) From afb98e73b3e803e207f1962be63bbb29735ae6ac Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Fri, 17 Jul 2026 23:47:07 -0400 Subject: [PATCH 25/31] Updated RMT debug counter macros. --- src/output/OutputRmtV5.cpp | 82 ++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 48 deletions(-) diff --git a/src/output/OutputRmtV5.cpp b/src/output/OutputRmtV5.cpp index a1f6e16c3..287d982d1 100644 --- a/src/output/OutputRmtV5.cpp +++ b/src/output/OutputRmtV5.cpp @@ -117,7 +117,7 @@ static size_t IRAM_ATTR ISR_encoder_callback(const void *data, size_t data_size, size_t symbols_written, size_t symbols_free, rmt_item32_t *symbols, bool *done, void *arg) { - RMT_DEBUG_COUNTER(RawIsrCounter++); + ++RawIsrCounter; return reinterpret_cast(arg)->ISR_Handler(data, data_size, symbols_written, symbols_free, @@ -153,8 +153,8 @@ void c_OutputRmt::Begin (OutputRmtConfig_t config, c_OutputCommon * _pParent ) .gpio_num = OutputRmtConfig.DataPin, .clk_src = RMT_CLK_SRC_DEFAULT, // select source clock .resolution_hz = uint32_t(RMT_TICK_RESOLUTION_HZ), - .mem_block_symbols = _NUM_RMT_SLOTS, // increase the block size can make the LED less flickering - .trans_queue_depth = _NUM_RMT_SLOTS, // set the number of transactions that can be pending in the background + .mem_block_symbols = NUM_RMT_SLOTS, // increase the block size can make the LED less flickering + .trans_queue_depth = NUM_RMT_SLOTS, // set the number of transactions that can be pending in the background .intr_priority = 0, // auto set interrupt priority .flags = { @@ -222,28 +222,28 @@ void c_OutputRmt::GetStatus (ArduinoJson::JsonObject& jsonStatus) #endif // def CONFIG_IDF_TARGET_ESP32S3 - debugStatus["ErrorIsr"] = ErrorIsr; + debugStatus["ErrorIsr"] = RMT_DEBUG_COUNTER(ErrorIsr); debugStatus["FrameCompletes"] = FrameCompletes; - debugStatus["FrameStartCounter"] = FrameStartCounter; + debugStatus["FrameStartCounter"] = RMT_DEBUG_COUNTER(FrameStartCounter); debugStatus["FrameTimeouts"] = FrameTimeouts; - debugStatus["FailedToSendAllData"] = FailedToSendAllData; - debugStatus["IncompleteFrame"] = IncompleteFrame; - debugStatus["IntensityValuesSent"] = IntensityValuesSent; - debugStatus["IntensityValuesSentLastFrame"] = IntensityValuesSentLastFrame; - debugStatus["IntensityBitsSent"] = IntensityBitsSent; - debugStatus["IntensityBitsSentLastFrame"] = IntensityBitsSentLastFrame; - debugStatus["IntTxEndIsrCounter"] = IntTxEndIsrCounter; - debugStatus["IntTxThrIsrCounter"] = IntTxThrIsrCounter; - debugStatus["ISRcounter"] = ISRcounter; - debugStatus["RanOutOfData"] = RanOutOfData; + debugStatus["FailedToSendAllData"] = RMT_DEBUG_COUNTER(FailedToSendAllData); + debugStatus["IncompleteFrame"] = RMT_DEBUG_COUNTER(IncompleteFrame); + debugStatus["IntensityValuesSent"] = RMT_DEBUG_COUNTER(IntensityValuesSent); + debugStatus["IntensityValuesSentLastFrame"] = RMT_DEBUG_COUNTER(IntensityValuesSentLastFrame); + debugStatus["IntensityBitsSent"] = RMT_DEBUG_COUNTER(IntensityBitsSent); + debugStatus["IntensityBitsSentLastFrame"] = RMT_DEBUG_COUNTER(IntensityBitsSentLastFrame); + debugStatus["IntTxEndIsrCounter"] = RMT_DEBUG_COUNTER(IntTxEndIsrCounter); + debugStatus["IntTxThrIsrCounter"] = RMT_DEBUG_COUNTER(IntTxThrIsrCounter); + debugStatus["ISRcounter"] = RMT_DEBUG_COUNTER(ISRcounter); + debugStatus["RanOutOfData"] = RMT_DEBUG_COUNTER(RanOutOfData); debugStatus["RawIsrCounter"] = RawIsrCounter; - debugStatus["RmtEntriesTransfered"] = RmtEntriesTransfered; - debugStatus["RmtWhiteDetected"] = RmtWhiteDetected; - debugStatus["RmtXmtFills"] = RmtXmtFills; - debugStatus["ISRpaused"] = ISRpaused; - debugStatus["SendBlockIsrCounter"] = SendBlockIsrCounter; - debugStatus["UnknownISRcounter"] = UnknownISRcounter; - debugStatus["WriteToBuffer"] = WriteToBuffer; + debugStatus["RmtEntriesTransfered"] = RMT_DEBUG_COUNTER(RmtEntriesTransfered); + debugStatus["RmtWhiteDetected"] = RMT_DEBUG_COUNTER(RmtWhiteDetected); + debugStatus["RmtXmtFills"] = RMT_DEBUG_COUNTER(RmtXmtFills); + debugStatus["ISRpaused"] = RMT_DEBUG_COUNTER(ISRpaused); + debugStatus["SendBlockIsrCounter"] = RMT_DEBUG_COUNTER(SendBlockIsrCounter); + debugStatus["UnknownISRcounter"] = RMT_DEBUG_COUNTER(UnknownISRcounter); + debugStatus["WriteToBuffer"] = RMT_DEBUG_COUNTER(WriteToBuffer); #ifdef IncludeBufferData { @@ -318,7 +318,7 @@ void IRAM_ATTR c_OutputRmt::ISR_CreateIntensityData () // no more data to send break; } - ISR_WriteToBuffer(Data); + WriteToBuffer(Data); --NumAvailableBufferSlotsToFill; }; @@ -339,19 +339,19 @@ size_t IRAM_ATTR c_OutputRmt::ISR_Handler (const void *data, size_t data_size, ///DEBUG_V(String(" RMT_INT_BIT: 0x") + String(RMT_INT_BIT, HEX)); // ClearRmtInterrupts; - RMT_DEBUG_COUNTER(++ISRcounter); + RMT_DEBUG_INC_COUNTER(ISRcounter); do // once { if(OutputIsPaused) { - RMT_DEBUG_COUNTER(++ISRpaused); + RMT_DEBUG_INC_COUNTER(ISRpaused); // nothing more to send *done = true; break; } - RMT_DEBUG_COUNTER(++SendBlockIsrCounter); + RMT_DEBUG_INC_COUNTER(SendBlockIsrCounter); // transfer any prefetched data to the hardware transmitter NumSymbolsTransfered = ISR_TransferIntensityDataToRMT( symbols, symbols_free ); @@ -361,7 +361,7 @@ size_t IRAM_ATTR c_OutputRmt::ISR_Handler (const void *data, size_t data_size, // is there any data left to enqueue? if (0 == NumUsedEntriesInSendBuffer) { - RMT_DEBUG_COUNTER(++RanOutOfData); + RMT_DEBUG_INC_COUNTER(RanOutOfData); *done = true; // tell the background task to start the next output vTaskNotifyGiveFromISR( SendFrameTaskHandle, &xHigherPriorityTaskWoken ); @@ -408,8 +408,8 @@ size_t IRAM_ATTR c_OutputRmt::ISR_TransferIntensityDataToRMT (rmt_item32_t *symb #ifdef USE_RMT_DEBUG_COUNTERS if(NumEntriesToTransfer) { - ++RmtXmtFills; - RmtEntriesTransfered = NumEntriesToTransfer; + RMT_DEBUG_INC_COUNTER(RmtXmtFills); + RMT_DEBUG_COUNTER(RmtEntriesTransfered) = NumEntriesToTransfer; } #endif // def USE_RMT_DEBUG_COUNTERS while(NumEntriesToTransfer) @@ -425,20 +425,6 @@ size_t IRAM_ATTR c_OutputRmt::ISR_TransferIntensityDataToRMT (rmt_item32_t *symb } // ISR_TransferIntensityDataToRMT -//---------------------------------------------------------------------------- -inline void IRAM_ATTR c_OutputRmt::ISR_WriteToBuffer(rmt_item32_t value) -{ - /// DEBUG_START; - - RMT_DEBUG_COUNTER(WriteToBuffer++); - - SendBuffer[SendBufferWriteIndex++] = value; - SendBufferWriteIndex &= uint32_t(NumSendBufferSlots - 1); - ++NumUsedEntriesInSendBuffer; - - ///DEBUG_END; -} - //---------------------------------------------------------------------------- void c_OutputRmt::PauseOutput(bool PauseOutput) { @@ -480,11 +466,11 @@ bool c_OutputRmt::StartNewFrame () ISR_ResetRmtBlockPointers (); #ifdef USE_RMT_DEBUG_COUNTERS - FrameStartCounter++; - IntensityValuesSentLastFrame = IntensityValuesSent; - IntensityValuesSent = 0; - IntensityBitsSentLastFrame = IntensityBitsSent; - IntensityBitsSent = 0; + RMT_DEBUG_INC_COUNTER(FrameStartCounter); + RMT_DEBUG_COUNTER(IntensityValuesSentLastFrame) = RMT_DEBUG_COUNTER(IntensityValuesSent); + RMT_DEBUG_COUNTER(IntensityValuesSent) = 0; + RMT_DEBUG_COUNTER(IntensityBitsSentLastFrame) = RMT_DEBUG_COUNTER(IntensityBitsSent); + RMT_DEBUG_COUNTER(IntensityBitsSent) = 0; #endif // def USE_RMT_DEBUG_COUNTERS // set up to send a new frame From 12cb21a0416542e803642d1aab6f6fd20ef4a595 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Fri, 17 Jul 2026 23:49:38 -0400 Subject: [PATCH 26/31] Another debug counter fix --- src/output/OutputRmtV4.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/output/OutputRmtV4.cpp b/src/output/OutputRmtV4.cpp index 76e79c4de..1392a74bb 100644 --- a/src/output/OutputRmtV4.cpp +++ b/src/output/OutputRmtV4.cpp @@ -119,7 +119,9 @@ c_OutputRmt::~c_OutputRmt () */ static void IRAM_ATTR rmt_intr_handler (void* param) { +#ifdef USE_RMT_DEBUG_COUNTERS RawIsrCounter++; +#endif // def USE_RMT_DEBUG_COUNTERS #ifdef DEBUG_GPIO // digitalWrite(DEBUG_GPIO, HIGH); #endif // def DEBUG_GPIO From b60801cf6d77a878ae149a9ae7e26db1f614d40d Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Sat, 18 Jul 2026 00:12:24 -0400 Subject: [PATCH 27/31] Fixed incorrect I2C pin definition. --- include/platforms/GPIO_Defs_ESP32_QUINLED_UNO.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/platforms/GPIO_Defs_ESP32_QUINLED_UNO.hpp b/include/platforms/GPIO_Defs_ESP32_QUINLED_UNO.hpp index 32df5ce70..78a113ecd 100644 --- a/include/platforms/GPIO_Defs_ESP32_QUINLED_UNO.hpp +++ b/include/platforms/GPIO_Defs_ESP32_QUINLED_UNO.hpp @@ -28,7 +28,7 @@ const OM_OutputPortDefinition_t OM_OutputPortDefinitions[] = {OM_PortId_t(1), OM_PortType_t::OM_RELAY, {gpio_num_t::GPIO_NUM_3}}, {OM_PortId_t(2), OM_PortType_t::OM_SERIAL, {gpio_num_t::GPIO_NUM_15}}, {OM_PortId_t(2), OM_PortType_t::OM_RELAY, {gpio_num_t::GPIO_NUM_15}}, - {OM_PortId_t(3), OM_PortType_t::OM_I2C, {gpio_num_t::GPIO_NUM_2, gpio_num_t::GPIO_NUM_2}}, + {OM_PortId_t(3), OM_PortType_t::OM_I2C, {gpio_num_t::GPIO_NUM_2, gpio_num_t::GPIO_NUM_32}}, }; // File Manager - Defnitions must be present even if SD is not supported From 69636241c4ef247f40221134b44a508cf8055cbb Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Tue, 21 Jul 2026 17:20:16 -0400 Subject: [PATCH 28/31] Updated asyncTCP to allow the newer version to be brough in. Fixes a build issue with an included library. --- platformio.ini | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 44a08c82e..5c082a1fc 100644 --- a/platformio.ini +++ b/platformio.ini @@ -147,7 +147,7 @@ build_unflags = lib_deps = ${env.lib_deps} - https://github.com/ESP32Async/AsyncTCP @ 3.4.10 + https://github.com/ESP32Async/AsyncTCP @ ^3.4.10 mathieucarbou/OneWire @ ^2.3.9 https://github.com/MartinMueller2003/DS18B20 https://github.com/bitbank2/unzipLIB @@ -195,7 +195,7 @@ build_unflags = lib_deps = ${env.lib_deps} - https://github.com/ESP32Async/AsyncTCP @ 3.4.10 + https://github.com/ESP32Async/AsyncTCP @ ^3.4.10 mathieucarbou/OneWire @ ^2.3.9 https://github.com/MartinMueller2003/DS18B20 https://github.com/bitbank2/unzipLIB @@ -688,6 +688,8 @@ build_unflags = [env:esp32s3_seeed_xiao] extends = esp32 board = seeed_xiao_esp32s3-custom +; board = seeed_xiao_esp32s3 +; platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.39/platform-espressif32.zip build_flags = ${esp32.build_flags} -D BOARD_NAME='"ESP32S3 seed XIAO"' From e5b1023aa228ae2c40ecc555029855f2225f7b76 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Tue, 21 Jul 2026 17:21:50 -0400 Subject: [PATCH 29/31] Changed how the channel buffer is allocated. --- src/output/OutputMgr.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/output/OutputMgr.cpp b/src/output/OutputMgr.cpp index f18eaf869..9fbaf1c91 100644 --- a/src/output/OutputMgr.cpp +++ b/src/output/OutputMgr.cpp @@ -239,6 +239,7 @@ struct alignas(32) DriverInfo_t static DriverInfo_t * pOutputChannelDrivers = nullptr;; +static uint8_t OutputBuffer[OM_MAX_NUM_CHANNELS]; //----------------------------------------------------------------------------- // Methods //----------------------------------------------------------------------------- @@ -248,7 +249,8 @@ c_OutputMgr::c_OutputMgr () ConfigFileName = String ("/") + String (CN_output_config) + CN_Dotjson; // clear the input data buffer - pOutputBuffer = (uint8_t*)malloc(GetBufferSize() + 1); + pOutputBuffer = OutputBuffer; + // pOutputBuffer = (uint8_t*)malloc(GetBufferSize() + 1); memset (pOutputBuffer, 0, GetBufferSize()); uint32_t SizeOfProtocolEntry = uint32_t(&SupportedOutputProtocolList[1]) - uint32_t(&SupportedOutputProtocolList[0]); From 77f426d4697b2745dbcbf518269dc6ef50fd05a4 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Tue, 21 Jul 2026 17:23:10 -0400 Subject: [PATCH 30/31] Fixed compile error when debug counters are not used --- src/output/OutputRmtV5.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/output/OutputRmtV5.cpp b/src/output/OutputRmtV5.cpp index 287d982d1..fb2ca5683 100644 --- a/src/output/OutputRmtV5.cpp +++ b/src/output/OutputRmtV5.cpp @@ -117,7 +117,9 @@ static size_t IRAM_ATTR ISR_encoder_callback(const void *data, size_t data_size, size_t symbols_written, size_t symbols_free, rmt_item32_t *symbols, bool *done, void *arg) { +#ifdef USE_RMT_DEBUG_COUNTERS ++RawIsrCounter; +#endif // def USE_RMT_DEBUG_COUNTERS return reinterpret_cast(arg)->ISR_Handler(data, data_size, symbols_written, symbols_free, From c25bb140ebee45193ffd90e68c47f26a46e3f476 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Tue, 21 Jul 2026 20:39:19 -0400 Subject: [PATCH 31/31] Removed misleading comment --- include/platforms/GPIO_Defs_ESP32_M5Stack_Atom.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/platforms/GPIO_Defs_ESP32_M5Stack_Atom.hpp b/include/platforms/GPIO_Defs_ESP32_M5Stack_Atom.hpp index c01558cb0..108f33e2e 100644 --- a/include/platforms/GPIO_Defs_ESP32_M5Stack_Atom.hpp +++ b/include/platforms/GPIO_Defs_ESP32_M5Stack_Atom.hpp @@ -21,10 +21,6 @@ /* * M5Stack Atom driver, boards are ESP32-PICO-D4 based, no PSRAM * -* Note: These boards lack PSRAM. So if you need more outputs, you probably need to -* raise the WebSocketFrameCollectionBufferSize a bit e.g. 12*1024. Otherwise you'll -* face an issue that the webUI is not rendering the output configutation section. -* * Tested: * - Atom Lite * - Atom Matrix