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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel1> Ne
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel1> NeoEsp32RmtHI1400KbpsMethod;
typedef NeoEsp32RmtHI1Ws2805Method NeoEsp32RmtHI1Ws2814Method;

#if !defined(CONFIG_IDF_TARGET_ESP32C3)
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5)

typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Ws2811Method;
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Ws2812xMethod;
Expand Down Expand Up @@ -321,7 +321,7 @@ typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel7> Ne
typedef NeoEsp32RmtHI7Ws2805Method NeoEsp32RmtHI7Ws2814Method;

#endif // !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3)
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3)
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5)

// inverted
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannelN> NeoEsp32RmtHINWs2811InvertedMethod;
Expand Down Expand Up @@ -369,7 +369,7 @@ typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChan
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel1> NeoEsp32RmtHI1400KbpsInvertedMethod;
typedef NeoEsp32RmtHI1Ws2805InvertedMethod NeoEsp32RmtHI1Ws2814InvertedMethod;

#if !defined(CONFIG_IDF_TARGET_ESP32C3)
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5)

typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Ws2811InvertedMethod;
typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel2> NeoEsp32RmtHI2Ws2812xInvertedMethod;
Expand Down Expand Up @@ -464,6 +464,6 @@ typedef NeoEsp32RmtHIMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChan
typedef NeoEsp32RmtHI7Ws2805InvertedMethod NeoEsp32RmtHI7Ws2814InvertedMethod;

#endif // !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3)
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3)
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5)

#endif
11 changes: 9 additions & 2 deletions lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,14 @@ License along with NeoPixel. If not, see

#if defined(ARDUINO_ARCH_ESP32)

#include <algorithm>
#include "esp_idf_version.h"

// NeoEsp32RmtHI uses the legacy (IDF 4.x) low-level RMT API which is incompatible with IDF 5.x.
// On IDF 5+ builds (pioarduino / Arduino-ESP32 v3.x), WLED selects standard NeoEsp32RmtN methods
// for RISC-V targets anyway (see bus_wrapper.h), so this implementation is not needed.
#if ESP_IDF_VERSION_MAJOR < 5

#include <algorithm>
Comment on lines +35 to +41
Copy link
Contributor

@coderabbitai coderabbitai bot Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

fd -t f "bus_wrapper.h" --exec cat {} \;

Repository: wled/WLED

Length of output: 50366


🏁 Script executed:

rg -n "RmtHI|NeoEsp32RmtHI|ESP_IDF_VERSION" wled00/bus_wrapper.h -A 3 -B 3

Repository: wled/WLED

Length of output: 386


🏁 Script executed:

# Check the header file to see if it has any IDF version guards
fd -t f "NeoEsp32RmtHIMethod.h" --exec cat {} \;

Repository: wled/WLED

Length of output: 35417


🏁 Script executed:

# Check if there are any other references to NeoEsp32RmtHI that might guard instantiation
rg -n "NeoEsp32RmtHI|RmtHI" --type cpp --type h | grep -E "(ifdef|if defined|ESP_IDF)" | head -20

Repository: wled/WLED

Length of output: 35


Add IDF version guard to bus_wrapper.h RMT method selection.

The .cpp implementation correctly gates legacy RMT code behind #if ESP_IDF_VERSION_MAJOR < 5, preventing incompatible code from being compiled on IDF 5.x. However, bus_wrapper.h does not gate the header inclusion by IDF version—it only checks target chip (CONFIG_IDF_TARGET_ESP32C5) and architecture (__riscv).

On classic ESP32 with IDF 5.x (Arduino-ESP32 v3.x), the current logic will:

  1. Include NeoEsp32RmtHIMethod.h (not gated by IDF version)
  2. Expose all HI method typedefs via #define NeoEsp32RmtMethod(x) NeoEsp32RmtHIN...
  3. Attempt to instantiate these types in bus creation
  4. Hit unresolved symbol errors at link time because the driver implementation is compiled out

Add an ESP_IDF_VERSION_MAJOR < 5 check around the HI method path in bus_wrapper.h (near line 269) to fall through to standard RmtN methods on IDF 5.x, matching the intent of the .cpp gate.

🤖 Prompt for AI Agents
In `@lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp` around lines 35 - 41,
bus_wrapper.h is including and aliasing the legacy HI RMT types even when the
.cpp is compiled out on IDF 5+, causing unresolved symbols; wrap the entire
HI-specific include/typedef block (the NeoEsp32RmtHIMethod.h inclusion and the
NeoEsp32RmtMethod(x) macro mappings) with an `#if` ESP_IDF_VERSION_MAJOR < 5 guard
(in addition to the existing CONFIG_IDF_TARGET_ESP32C5 / __riscv checks) so that
on IDF 5+ the HI path is skipped and the code falls through to the standard RmtN
methods used at link time.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonny190 the rabbit is right, this is a quite dangerous change. it means that the code will still have the high prio interrupt driver for RMT (NeoEsp32RmtHI.S), but the C++ support code will be missing. Its one of the things that the "V5" branch should handle, hopefully with a better and more generic approach.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

#include "NeoEsp32RmtHIMethod.h"
#include "soc/soc.h"
#include "soc/rmt_reg.h"
Expand Down Expand Up @@ -504,4 +510,5 @@ esp_err_t NeoEsp32RmtHiMethodDriver::WaitForTxDone(rmt_channel_t channel, TickTy
return rv;
}

#endif
#endif // ESP_IDF_VERSION_MAJOR < 5
#endif // ARDUINO_ARCH_ESP32
32 changes: 16 additions & 16 deletions usermods/audioreactive/audio_reactive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,7 @@ class AudioReactive : public Usermod {
static const char _dynamics[];
static const char _frequency[];
static const char _inputLvl[];
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32S3)
static const char _analogmic[];
#endif
static const char _digitalmic[];
Expand Down Expand Up @@ -1160,23 +1160,23 @@ class AudioReactive : public Usermod {

// Reset I2S peripheral for good measure
i2s_driver_uninstall(I2S_NUM_0); // E (696) I2S: i2s_driver_uninstall(2006): I2S port 0 has not installed
#if !defined(CONFIG_IDF_TARGET_ESP32C3)
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5)
delay(100);
periph_module_reset(PERIPH_I2S0_MODULE); // not possible on -C3
periph_module_reset(PERIPH_I2S0_MODULE); // not possible on -C3/-C5
#endif
delay(100); // Give that poor microphone some time to setup.

useBandPassFilter = false;

#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5)
if ((i2sckPin == I2S_PIN_NO_CHANGE) && (i2ssdPin >= 0) && (i2swsPin >= 0) && ((dmType == 1) || (dmType == 4)) ) dmType = 5; // dummy user support: SCK == -1 --means--> PDM microphone
#endif

switch (dmType) {
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3)
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32S3)
// stub cases for not-yet-supported I2S modes on other ESP32 chips
case 0: //ADC analog
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5)
case 5: //PDM Microphone
#endif
#endif
Expand Down Expand Up @@ -1204,7 +1204,7 @@ class AudioReactive : public Usermod {
delay(100);
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
break;
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5)
case 5:
DEBUGSR_PRINT(F("AR: I2S PDM Microphone - ")); DEBUGSR_PRINTLN(F(I2S_PDM_MIC_CHANNEL_TEXT));
audioSource = new I2SSource(SAMPLE_RATE, BLOCK_SIZE, 1.0f/4.0f);
Expand All @@ -1220,7 +1220,7 @@ class AudioReactive : public Usermod {
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
break;

#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32S3)
// ADC over I2S is only possible on "classic" ESP32
case 0:
DEBUGSR_PRINTLN(F("AR: Analog Microphone (left channel only)."));
Expand Down Expand Up @@ -1797,7 +1797,7 @@ class AudioReactive : public Usermod {
top[FPSTR(_addPalettes)] = addPalettes;

#ifdef ARDUINO_ARCH_ESP32
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32S3)
JsonObject amic = top.createNestedObject(FPSTR(_analogmic));
amic["pin"] = audioPin;
#endif
Expand Down Expand Up @@ -1856,16 +1856,16 @@ class AudioReactive : public Usermod {
configComplete &= getJsonValue(top[FPSTR(_addPalettes)], addPalettes);

#ifdef ARDUINO_ARCH_ESP32
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32S3)
configComplete &= getJsonValue(top[FPSTR(_analogmic)]["pin"], audioPin);
#else
audioPin = -1; // MCU does not support analog mic
#endif

configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["type"], dmType);
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3)
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32S3)
if (dmType == 0) dmType = SR_DMTYPE; // MCU does not support analog
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5)
if (dmType == 5) dmType = SR_DMTYPE; // MCU does not support PDM
#endif
#endif
Expand Down Expand Up @@ -1903,14 +1903,14 @@ class AudioReactive : public Usermod {
#ifdef ARDUINO_ARCH_ESP32
uiScript.print(F("uxp=ux+':digitalmic:pin[]';")); // uxp = shortcut for AudioReactive:digitalmic:pin[]
uiScript.print(F("dd=addDropdown(ux,'digitalmic:type');"));
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32S3)
uiScript.print(F("addOption(dd,'Generic Analog',0);"));
#endif
uiScript.print(F("addOption(dd,'Generic I2S',1);"));
uiScript.print(F("addOption(dd,'ES7243',2);"));
uiScript.print(F("addOption(dd,'SPH0654',3);"));
uiScript.print(F("addOption(dd,'Generic I2S with Mclk',4);"));
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5)
uiScript.print(F("addOption(dd,'Generic I2S PDM',5);"));
#endif
uiScript.print(F("addOption(dd,'ES8388',6);"));
Expand Down Expand Up @@ -1946,7 +1946,7 @@ class AudioReactive : public Usermod {
uiScript.print(F("addInfo(uxp,0,'<i>sd/data/dout</i>','I2S SD');"));
uiScript.print(F("addInfo(uxp,1,'<i>ws/clk/lrck</i>','I2S WS');"));
uiScript.print(F("addInfo(uxp,2,'<i>sck/bclk</i>','I2S SCK');"));
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32S3)
uiScript.print(F("addInfo(uxp,3,'<i>only use -1, 0, 1 or 3</i>','I2S MCLK');"));
#else
uiScript.print(F("addInfo(uxp,3,'<i>master clock</i>','I2S MCLK');"));
Expand Down Expand Up @@ -2069,7 +2069,7 @@ const char AudioReactive::_config[] PROGMEM = "config";
const char AudioReactive::_dynamics[] PROGMEM = "dynamics";
const char AudioReactive::_frequency[] PROGMEM = "frequency";
const char AudioReactive::_inputLvl[] PROGMEM = "inputLevel";
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32S3)
const char AudioReactive::_analogmic[] PROGMEM = "analogmic";
#endif
const char AudioReactive::_digitalmic[] PROGMEM = "digitalmic";
Expand Down
8 changes: 4 additions & 4 deletions wled00/FX.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@ extern byte realtimeMode; // used in getMappedPixelIndex()
#define WLED_FPS 42
#define FRAMETIME_FIXED (1000/WLED_FPS)
#define FRAMETIME strip.getFrameTime()
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S2)
#define MIN_FRAME_DELAY 2 // minimum wait between repaints, to keep other functions like WiFi alive
#elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
#define MIN_FRAME_DELAY 3 // S2/C3 are slower than normal esp32, and only have one core
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(CONFIG_IDF_TARGET_ESP32S2)
#define MIN_FRAME_DELAY 2 // minimum wait between repaints, to keep other functions like WiFi alive
#elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5)
#define MIN_FRAME_DELAY 3 // S2/C3/C5 are slower than normal esp32, and only have one core
#else
#define MIN_FRAME_DELAY 8 // 8266 legacy MIN_SHOW_DELAY
#endif
Expand Down
10 changes: 5 additions & 5 deletions wled00/FX_fcn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1161,7 +1161,7 @@ void WS2812FX::finalizeInit() {
BusManager::removeAll();

unsigned digitalCount = 0;
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5)
// determine if it is sensible to use parallel I2S outputs on ESP32 (i.e. more than 5 outputs = 1 I2S + 4 RMT)
unsigned maxLedsOnBus = 0;
unsigned busType = 0;
Expand Down Expand Up @@ -1191,7 +1191,7 @@ void WS2812FX::finalizeInit() {
bool use_placeholder = false;
unsigned busMemUsage = bus.memUsage(Bus::isDigital(bus.type) && !Bus::is2Pin(bus.type) ? digitalCount++ : 0); // does not include DMA/RMT buffer
// estimate maximum I2S memory usage (only relevant for digital non-2pin busses)
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(ESP8266)
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C5) && !defined(ESP8266)
#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S3)
const bool usesI2S = ((useParallelI2S && digitalCount <= 8) || (!useParallelI2S && digitalCount == 1));
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
Expand Down Expand Up @@ -1340,8 +1340,8 @@ static uint8_t _add (uint8_t a, uint8_t b) { unsigned t = a + b; return t
static uint8_t _subtract (uint8_t a, uint8_t b) { return b > a ? (b - a) : 0; }
static uint8_t _difference(uint8_t a, uint8_t b) { return b > a ? (b - a) : (a - b); }
static uint8_t _average (uint8_t a, uint8_t b) { return (a + b) >> 1; }
#if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3)
static uint8_t _multiply (uint8_t a, uint8_t b) { return ((a * b) + 255) >> 8; } // faster than division on C3 but slightly less accurate
#if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5)
static uint8_t _multiply (uint8_t a, uint8_t b) { return ((a * b) + 255) >> 8; } // faster than division on C3/C5 but slightly less accurate
#else
static uint8_t _multiply (uint8_t a, uint8_t b) { return (a * b) / 255; } // origianl uses a & b in range [0,1]
#endif
Expand All @@ -1351,7 +1351,7 @@ static uint8_t _darken (uint8_t a, uint8_t b) { return a < b ? a : b; }
static uint8_t _screen (uint8_t a, uint8_t b) { return 255 - _multiply(~a,~b); } // 255 - (255-a)*(255-b)/255
static uint8_t _overlay (uint8_t a, uint8_t b) { return b < 128 ? 2 * _multiply(a,b) : (255 - 2 * _multiply(~a,~b)); }
static uint8_t _hardlight (uint8_t a, uint8_t b) { return a < 128 ? 2 * _multiply(a,b) : (255 - 2 * _multiply(~a,~b)); }
#if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3)
#if defined(ESP8266) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C5)
static uint8_t _softlight (uint8_t a, uint8_t b) { return (((b * b * (255 - 2 * a))) + ((2 * a * b + 256) << 8)) >> 16; } // Pegtop's formula (1 - 2a)b^2
#else
static uint8_t _softlight (uint8_t a, uint8_t b) { return (b * b * (255 - 2 * a) + 255 * 2 * a * b) / (255 * 255); } // Pegtop's formula (1 - 2a)b^2 + 2ab
Expand Down
Loading