From da79b93387cb80873d5dc65cd864be866a4b70bf Mon Sep 17 00:00:00 2001
From: Brandon502 <105077712+Brandon502@users.noreply.github.com>
Date: Tue, 7 May 2024 18:04:29 -0400
Subject: [PATCH 01/25] Added Pinwheel Expand 1D Effect
---
wled00/FX.h | 3 ++-
wled00/FX_fcn.cpp | 58 +++++++++++++++++++++++++++++++++++++++++++-
wled00/data/index.js | 1 +
3 files changed, 60 insertions(+), 2 deletions(-)
diff --git a/wled00/FX.h b/wled00/FX.h
index 106a6712c..b1e6823ff 100644
--- a/wled00/FX.h
+++ b/wled00/FX.h
@@ -320,7 +320,8 @@ typedef enum mapping1D2D {
M12_Pixels = 0,
M12_pBar = 1,
M12_pArc = 2,
- M12_pCorner = 3
+ M12_pCorner = 3,
+ M12_sPinwheel = 4
} mapping1D2D_t;
// segment, 80 bytes
diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp
index ce510f16e..7f8c1319a 100644
--- a/wled00/FX_fcn.cpp
+++ b/wled00/FX_fcn.cpp
@@ -637,6 +637,14 @@ uint16_t IRAM_ATTR Segment::nrOfVStrips() const {
return vLen;
}
+// Constants for mapping mode "Pinwheel"
+constexpr int Pinwheel_Steps_Medium = 208; // no holes up to 32x32; 60fps
+constexpr int Pinwheel_Size_Medium = 32; // larger than this -> use "Big"
+constexpr int Pinwheel_Steps_Big = 360; // no holes expected up to 58x58; 40fps
+constexpr float Int_to_Rad_Med = (DEG_TO_RAD * 360) / Pinwheel_Steps_Medium; // conversion: from 0...208 to Radians
+constexpr float Int_to_Rad_Big = (DEG_TO_RAD * 360) / Pinwheel_Steps_Big; // conversion: from 0...360 to Radians
+
+
// 1D strip
uint16_t IRAM_ATTR Segment::virtualLength() const {
#ifndef WLED_DISABLE_2D
@@ -652,6 +660,12 @@ uint16_t IRAM_ATTR Segment::virtualLength() const {
case M12_pArc:
vLen = max(vW,vH); // get the longest dimension
break;
+ case M12_sPinwheel:
+ if (max(vW,vH) <= Pinwheel_Size_Medium)
+ vLen = Pinwheel_Steps_Medium;
+ else
+ vLen = Pinwheel_Steps_Big;
+ break;
}
return vLen;
}
@@ -718,6 +732,38 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
for (int x = 0; x <= i; x++) setPixelColorXY(x, i, col);
for (int y = 0; y < i; y++) setPixelColorXY(i, y, col);
break;
+ case M12_sPinwheel: {
+ // i = angle --> 0 through 359 (Big), OR 0 through 208 (Medium)
+ float centerX = roundf((vW-1) / 2.0f);
+ float centerY = roundf((vH-1) / 2.0f);
+ // int maxDistance = sqrt(centerX * centerX + centerY * centerY) + 1;
+ float angleRad = (max(vW,vH) > Pinwheel_Size_Medium) ? float(i) * Int_to_Rad_Big : float(i) * Int_to_Rad_Med; // angle in radians
+ float cosVal = cosf(angleRad);
+ float sinVal = sinf(angleRad);
+
+ // draw line at angle, starting at center and ending at the segment edge
+ // we use fixed point math for better speed. Starting distance is 0.5 for better rounding
+ constexpr int_fast32_t Fixed_Scale = 512; // fixpoint scaling factor
+ int_fast32_t posx = (centerX + 0.5f * cosVal) * Fixed_Scale; // X starting position in fixed point
+ int_fast32_t posy = (centerY + 0.5f * sinVal) * Fixed_Scale; // Y starting position in fixed point
+ int_fast16_t inc_x = cosVal * Fixed_Scale; // X increment per step (fixed point)
+ int_fast16_t inc_y = sinVal * Fixed_Scale; // Y increment per step (fixed point)
+
+ int32_t maxX = vW * Fixed_Scale; // X edge in fixedpoint
+ int32_t maxY = vH * Fixed_Scale; // Y edge in fixedpoint
+ // draw until we hit any edge
+ while ((posx > 0) && (posy > 0) && (posx < maxX) && (posy < maxY)) {
+ // scale down to integer (compiler will replace division with appropriate bitshift)
+ int x = posx / Fixed_Scale;
+ int y = posy / Fixed_Scale;
+ // set pixel
+ setPixelColorXY(x, y, col);
+ // advance to next position
+ posx += inc_x;
+ posy += inc_y;
+ }
+ break;
+ }
}
return;
} else if (Segment::maxHeight!=1 && (width()==1 || height()==1)) {
@@ -833,7 +879,17 @@ uint32_t IRAM_ATTR Segment::getPixelColor(int i)
// use longest dimension
return vW>vH ? getPixelColorXY(i, 0) : getPixelColorXY(0, i);
break;
- }
+ case M12_sPinwheel:
+ // not 100% accurate, returns outer edge of circle
+ float distance = max(1.0f, min(vH-1, vW-1) / 2.0f);
+ float centerX = (vW - 1) / 2.0f;
+ float centerY = (vH - 1) / 2.0f;
+ float angleRad = (max(vW,vH) > Pinwheel_Size_Medium) ? float(i) * Int_to_Rad_Big : float(i) * Int_to_Rad_Med; // angle in radians
+ int x = roundf(centerX + distance * cosf(angleRad));
+ int y = roundf(centerY + distance * sinf(angleRad));
+ return getPixelColorXY(x, y);
+ break;
+ }
return 0;
}
#endif
diff --git a/wled00/data/index.js b/wled00/data/index.js
index d33fb63f7..26d78b284 100644
--- a/wled00/data/index.js
+++ b/wled00/data/index.js
@@ -801,6 +801,7 @@ function populateSegments(s)
``+
``+
``+
+ ``+
``+
``;
let sndSim = `
Sound sim
`+
From bc5aadff7d73931f971b3d1ee534b7a2d4dc7f0a Mon Sep 17 00:00:00 2001
From: Adam Matthews
Date: Thu, 9 May 2024 23:09:45 +0100
Subject: [PATCH 02/25] Update Usermod: Battery
Issue:
When taking the initial voltage reading after first powering on, voltage hasn't had chance to stabilize so the reading can be inaccurate, which in turn may incorrectly trigger the low-power preset. (Manifests when the user has selected a low read interval and/or is using a capacitor).
Resolution:
A non-blocking, fixed 10 second delay has been added to the initial voltage reading to give the voltage time to stabilize.
This is a reworked version of the (now closed) PR here:
https://github.com/Aircoookie/WLED/pull/3959
- Rebased the update for 0_15.
- Added a constant so the delay can be modified via my_config.h.
- Small adjustments to make the PR compatible again after the recent restructuring in this PR: (https://github.com/Aircoookie/WLED/pull/3003).
Thankyou!
---
usermods/Battery/battery_defaults.h | 6 ++++++
usermods/Battery/readme.md | 5 +++++
usermods/Battery/usermod_v2_Battery.h | 28 ++++++++++++++++++++++++---
3 files changed, 36 insertions(+), 3 deletions(-)
diff --git a/usermods/Battery/battery_defaults.h b/usermods/Battery/battery_defaults.h
index 8b56c6014..ddbd114e4 100644
--- a/usermods/Battery/battery_defaults.h
+++ b/usermods/Battery/battery_defaults.h
@@ -14,6 +14,12 @@
#endif
#endif
+// The initial delay before the first battery voltage reading after power-on.
+// This allows the voltage to stabilize before readings are taken, improving accuracy of initial reading.
+#ifndef USERMOD_BATTERY_INITIAL_DELAY
+ #define USERMOD_BATTERY_INITIAL_DELAY 10000 // (milliseconds)
+#endif
+
// the frequency to check the battery, 30 sec
#ifndef USERMOD_BATTERY_MEASUREMENT_INTERVAL
#define USERMOD_BATTERY_MEASUREMENT_INTERVAL 30000
diff --git a/usermods/Battery/readme.md b/usermods/Battery/readme.md
index b3607482a..efe25cc24 100644
--- a/usermods/Battery/readme.md
+++ b/usermods/Battery/readme.md
@@ -37,6 +37,7 @@ define `USERMOD_BATTERY` in `wled00/my_config.h`
| ----------------------------------------------- | ----------- |-------------------------------------------------------------------------------------- |
| `USERMOD_BATTERY` | | define this (in `my_config.h`) to have this usermod included wled00\usermods_list.cpp |
| `USERMOD_BATTERY_MEASUREMENT_PIN` | | defaults to A0 on ESP8266 and GPIO35 on ESP32 |
+| `USERMOD_BATTERY_INITIAL_DELAY` | ms | delay before initial reading. defaults to 10 seconds to allow voltage stabilization
| `USERMOD_BATTERY_MEASUREMENT_INTERVAL` | ms | battery check interval. defaults to 30 seconds |
| `USERMOD_BATTERY_{TYPE}_MIN_VOLTAGE` | v | minimum battery voltage. default is 2.6 (18650 battery standard) |
| `USERMOD_BATTERY_{TYPE}_MAX_VOLTAGE` | v | maximum battery voltage. default is 4.2 (18650 battery standard) |
@@ -88,6 +89,10 @@ Specification from: [Molicel INR18650-M35A, 3500mAh 10A Lithium-ion battery, 3.
2024-04-30
+- improved initial reading accuracy by delaying initial measurement to allow voltage to stabilize at power-on
+
+2024-04-30
+
- integrate factory pattern to make it easier to add other / custom battery types
- update readme
diff --git a/usermods/Battery/usermod_v2_Battery.h b/usermods/Battery/usermod_v2_Battery.h
index 88a879b72..35da337e1 100644
--- a/usermods/Battery/usermod_v2_Battery.h
+++ b/usermods/Battery/usermod_v2_Battery.h
@@ -22,6 +22,10 @@ class UsermodBattery : public Usermod
UMBattery* bat = new UnkownUMBattery();
batteryConfig cfg;
+ // Initial delay before first reading to allow voltage stabilization
+ unsigned long initialDelay = USERMOD_BATTERY_INITIAL_DELAY;
+ bool initialDelayComplete = false;
+ bool isFirstVoltageReading = true;
// how often to read the battery voltage
unsigned long readingInterval = USERMOD_BATTERY_MEASUREMENT_INTERVAL;
unsigned long nextReadTime = 0;
@@ -137,7 +141,6 @@ class UsermodBattery : public Usermod
if (pinManager.allocatePin(batteryPin, false, PinOwner::UM_Battery)) {
DEBUG_PRINTLN(F("Battery pin allocation succeeded."));
success = true;
- bat->setVoltage(readVoltage());
}
if (!success) {
@@ -148,10 +151,10 @@ class UsermodBattery : public Usermod
}
#else //ESP8266 boards have only one analog input pin A0
pinMode(batteryPin, INPUT);
- bat->setVoltage(readVoltage());
#endif
- nextReadTime = millis() + readingInterval;
+ // First voltage reading is delayed to allow voltage stabilization after powering up
+ nextReadTime = millis() + initialDelay;
lastReadTime = millis();
initDone = true;
@@ -178,6 +181,25 @@ class UsermodBattery : public Usermod
lowPowerIndicator();
+ // Handling the initial delay
+ if (!initialDelayComplete && millis() < nextReadTime)
+ return; // Continue to return until the initial delay is over
+
+ // Once the initial delay is over, set it as complete
+ if (!initialDelayComplete)
+ {
+ initialDelayComplete = true;
+ // Set the regular interval after initial delay
+ nextReadTime = millis() + readingInterval;
+ }
+
+ // Make the first voltage reading after the initial delay has elapsed
+ if (isFirstVoltageReading)
+ {
+ bat->setVoltage(readVoltage());
+ isFirstVoltageReading = false;
+ }
+
// check the battery level every USERMOD_BATTERY_MEASUREMENT_INTERVAL (ms)
if (millis() < nextReadTime) return;
From 6a18ce078e3b2f31404d3309b39985638d53fcf4 Mon Sep 17 00:00:00 2001
From: Brandon502 <105077712+Brandon502@users.noreply.github.com>
Date: Thu, 9 May 2024 20:38:41 -0400
Subject: [PATCH 03/25] Pinwheel Expand1D changes
cosf/sinf changed to cos_t/sin_t. int_fast32_t and int_fast_16_t changed to int.
---
wled00/FX_fcn.cpp | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp
index 7f8c1319a..88ec78f3e 100644
--- a/wled00/FX_fcn.cpp
+++ b/wled00/FX_fcn.cpp
@@ -738,16 +738,17 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
float centerY = roundf((vH-1) / 2.0f);
// int maxDistance = sqrt(centerX * centerX + centerY * centerY) + 1;
float angleRad = (max(vW,vH) > Pinwheel_Size_Medium) ? float(i) * Int_to_Rad_Big : float(i) * Int_to_Rad_Med; // angle in radians
- float cosVal = cosf(angleRad);
- float sinVal = sinf(angleRad);
+ float cosVal = cos_t(angleRad);
+ float sinVal = sin_t(angleRad);
// draw line at angle, starting at center and ending at the segment edge
// we use fixed point math for better speed. Starting distance is 0.5 for better rounding
- constexpr int_fast32_t Fixed_Scale = 512; // fixpoint scaling factor
- int_fast32_t posx = (centerX + 0.5f * cosVal) * Fixed_Scale; // X starting position in fixed point
- int_fast32_t posy = (centerY + 0.5f * sinVal) * Fixed_Scale; // Y starting position in fixed point
- int_fast16_t inc_x = cosVal * Fixed_Scale; // X increment per step (fixed point)
- int_fast16_t inc_y = sinVal * Fixed_Scale; // Y increment per step (fixed point)
+ // int_fast16_t and int_fast32_t types changed to int, minimum bits commented
+ constexpr int Fixed_Scale = 512; // fixpoint scaling factor 18 bit
+ int posx = (centerX + 0.5f * cosVal) * Fixed_Scale; // X starting position in fixed point 18 bit
+ int posy = (centerY + 0.5f * sinVal) * Fixed_Scale; // Y starting position in fixed point 18 bit
+ int inc_x = cosVal * Fixed_Scale; // X increment per step (fixed point) 10 bit
+ int inc_y = sinVal * Fixed_Scale; // Y increment per step (fixed point) 10 bit
int32_t maxX = vW * Fixed_Scale; // X edge in fixedpoint
int32_t maxY = vH * Fixed_Scale; // Y edge in fixedpoint
@@ -885,8 +886,8 @@ uint32_t IRAM_ATTR Segment::getPixelColor(int i)
float centerX = (vW - 1) / 2.0f;
float centerY = (vH - 1) / 2.0f;
float angleRad = (max(vW,vH) > Pinwheel_Size_Medium) ? float(i) * Int_to_Rad_Big : float(i) * Int_to_Rad_Med; // angle in radians
- int x = roundf(centerX + distance * cosf(angleRad));
- int y = roundf(centerY + distance * sinf(angleRad));
+ int x = roundf(centerX + distance * cos_t(angleRad));
+ int y = roundf(centerY + distance * sin_t(angleRad));
return getPixelColorXY(x, y);
break;
}
From d3492b5b6c38e6a8cb2136bc8d7654a4594b59df Mon Sep 17 00:00:00 2001
From: Brandon502 <105077712+Brandon502@users.noreply.github.com>
Date: Fri, 10 May 2024 16:06:37 -0400
Subject: [PATCH 04/25] Pinwheel Expand 1D Bug Fix
Removed holes on 31x31 and 32x32 grids.
---
wled00/FX_fcn.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp
index 88ec78f3e..17a504ea0 100644
--- a/wled00/FX_fcn.cpp
+++ b/wled00/FX_fcn.cpp
@@ -639,7 +639,7 @@ uint16_t IRAM_ATTR Segment::nrOfVStrips() const {
// Constants for mapping mode "Pinwheel"
constexpr int Pinwheel_Steps_Medium = 208; // no holes up to 32x32; 60fps
-constexpr int Pinwheel_Size_Medium = 32; // larger than this -> use "Big"
+constexpr int Pinwheel_Size_Medium = 30; // larger than this -> use "Big"
constexpr int Pinwheel_Steps_Big = 360; // no holes expected up to 58x58; 40fps
constexpr float Int_to_Rad_Med = (DEG_TO_RAD * 360) / Pinwheel_Steps_Medium; // conversion: from 0...208 to Radians
constexpr float Int_to_Rad_Big = (DEG_TO_RAD * 360) / Pinwheel_Steps_Big; // conversion: from 0...360 to Radians
From 43d024fe429c5f519fb50f80fe75c8d184c64aea Mon Sep 17 00:00:00 2001
From: Michael Bisbjerg
Date: Fri, 10 May 2024 22:43:55 +0200
Subject: [PATCH 05/25] Make BME280 usermod i2c address changeable
---
usermods/BME280_v2/README.md | 1 +
usermods/BME280_v2/usermod_bme280.h | 11 ++++++++++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/usermods/BME280_v2/README.md b/usermods/BME280_v2/README.md
index 0a4afbf1f..51e93336d 100644
--- a/usermods/BME280_v2/README.md
+++ b/usermods/BME280_v2/README.md
@@ -7,6 +7,7 @@ This Usermod is designed to read a `BME280` or `BMP280` sensor and output the fo
- Dew Point (`BME280` only)
Configuration is performed via the Usermod menu. There are no parameters to set in code! The following settings can be configured in the Usermod Menu:
+- The i2c address in decimal. Set it to either 118 (0x76, the default) or 119 (0x77). **Requires reboot**.
- Temperature Decimals (number of decimal places to output)
- Humidity Decimals
- Pressure Decimals
diff --git a/usermods/BME280_v2/usermod_bme280.h b/usermods/BME280_v2/usermod_bme280.h
index ae6eba89d..0040c5efa 100644
--- a/usermods/BME280_v2/usermod_bme280.h
+++ b/usermods/BME280_v2/usermod_bme280.h
@@ -28,6 +28,7 @@ private:
bool UseCelsius = true; // Use Celsius for Reporting
bool HomeAssistantDiscovery = false; // Publish Home Assistant Device Information
bool enabled = true;
+ BME280I2C::I2CAddr i2cAddress = BME280I2C::I2CAddr_0x76; // Default i2c address for BME280
// set the default pins based on the architecture, these get overridden by Usermod menu settings
#ifdef ESP8266
@@ -48,7 +49,7 @@ private:
BME280I2C::I2CAddr_0x76 // I2C address. I2C specific. Default 0x76
};
- BME280I2C bme{settings};
+ BME280I2C bme;
uint8_t sensorType;
@@ -186,6 +187,9 @@ public:
{
if (i2c_scl<0 || i2c_sda<0) { enabled = false; sensorType = 0; return; }
+ settings.bme280Addr = i2cAddress;
+ bme = BME280I2C(settings);
+
if (!bme.begin())
{
sensorType = 0;
@@ -399,6 +403,7 @@ public:
{
JsonObject top = root.createNestedObject(FPSTR(_name));
top[FPSTR(_enabled)] = enabled;
+ top[F("I2CAddress")] = i2cAddress;
top[F("TemperatureDecimals")] = TemperatureDecimals;
top[F("HumidityDecimals")] = HumidityDecimals;
top[F("PressureDecimals")] = PressureDecimals;
@@ -426,6 +431,10 @@ public:
configComplete &= getJsonValue(top[FPSTR(_enabled)], enabled);
// A 3-argument getJsonValue() assigns the 3rd argument as a default value if the Json value is missing
+ uint8_t tmpI2cAddress;
+ configComplete &= getJsonValue(top[F("I2CAddress")], tmpI2cAddress, 0x76);
+ i2cAddress = static_cast(tmpI2cAddress);
+
configComplete &= getJsonValue(top[F("TemperatureDecimals")], TemperatureDecimals, 1);
configComplete &= getJsonValue(top[F("HumidityDecimals")], HumidityDecimals, 0);
configComplete &= getJsonValue(top[F("PressureDecimals")], PressureDecimals, 0);
From 9e468bd059510c66bbb99e41ed4855193a9cc05c Mon Sep 17 00:00:00 2001
From: Brandon502 <105077712+Brandon502@users.noreply.github.com>
Date: Sat, 11 May 2024 13:57:21 -0400
Subject: [PATCH 06/25] Pinwheel Expand 1D Optimizations
Added small pinwheel size. Adjusts medium and large values.
---
wled00/FX_fcn.cpp | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp
index 17a504ea0..ec0e087bc 100644
--- a/wled00/FX_fcn.cpp
+++ b/wled00/FX_fcn.cpp
@@ -638,9 +638,12 @@ uint16_t IRAM_ATTR Segment::nrOfVStrips() const {
}
// Constants for mapping mode "Pinwheel"
-constexpr int Pinwheel_Steps_Medium = 208; // no holes up to 32x32; 60fps
-constexpr int Pinwheel_Size_Medium = 30; // larger than this -> use "Big"
-constexpr int Pinwheel_Steps_Big = 360; // no holes expected up to 58x58; 40fps
+constexpr int Pinwheel_Steps_Small = 72; // no holes up to 16x16;
+constexpr int Pinwheel_Size_Small = 16;
+constexpr int Pinwheel_Steps_Medium = 200; // no holes up to 32x32; 60fps
+constexpr int Pinwheel_Size_Medium = 32; // larger than this -> use "Big"
+constexpr int Pinwheel_Steps_Big = 296; // no holes expected up to 58x58; 40fps
+constexpr float Int_to_Rad_Small = (DEG_TO_RAD * 360) / Pinwheel_Steps_Small; // conversion: from 0...208 to Radians
constexpr float Int_to_Rad_Med = (DEG_TO_RAD * 360) / Pinwheel_Steps_Medium; // conversion: from 0...208 to Radians
constexpr float Int_to_Rad_Big = (DEG_TO_RAD * 360) / Pinwheel_Steps_Big; // conversion: from 0...360 to Radians
@@ -661,7 +664,9 @@ uint16_t IRAM_ATTR Segment::virtualLength() const {
vLen = max(vW,vH); // get the longest dimension
break;
case M12_sPinwheel:
- if (max(vW,vH) <= Pinwheel_Size_Medium)
+ if (max(vW,vH) <= Pinwheel_Size_Small)
+ vLen = Pinwheel_Steps_Small;
+ else if (max(vW,vH) <= Pinwheel_Size_Medium)
vLen = Pinwheel_Steps_Medium;
else
vLen = Pinwheel_Steps_Big;
@@ -736,8 +741,7 @@ void IRAM_ATTR Segment::setPixelColor(int i, uint32_t col)
// i = angle --> 0 through 359 (Big), OR 0 through 208 (Medium)
float centerX = roundf((vW-1) / 2.0f);
float centerY = roundf((vH-1) / 2.0f);
- // int maxDistance = sqrt(centerX * centerX + centerY * centerY) + 1;
- float angleRad = (max(vW,vH) > Pinwheel_Size_Medium) ? float(i) * Int_to_Rad_Big : float(i) * Int_to_Rad_Med; // angle in radians
+ float angleRad = (max(vW, vH) > Pinwheel_Size_Small ? (max(vW, vH) > Pinwheel_Size_Medium ? float(i) * Int_to_Rad_Big : float(i) * Int_to_Rad_Med) : float(i) * Int_to_Rad_Small); // angle in radians
float cosVal = cos_t(angleRad);
float sinVal = sin_t(angleRad);
@@ -885,7 +889,7 @@ uint32_t IRAM_ATTR Segment::getPixelColor(int i)
float distance = max(1.0f, min(vH-1, vW-1) / 2.0f);
float centerX = (vW - 1) / 2.0f;
float centerY = (vH - 1) / 2.0f;
- float angleRad = (max(vW,vH) > Pinwheel_Size_Medium) ? float(i) * Int_to_Rad_Big : float(i) * Int_to_Rad_Med; // angle in radians
+ float angleRad = (max(vW, vH) > Pinwheel_Size_Small ? (max(vW, vH) > Pinwheel_Size_Medium ? float(i) * Int_to_Rad_Big : float(i) * Int_to_Rad_Med) : float(i) * Int_to_Rad_Small); // angle in radians
int x = roundf(centerX + distance * cos_t(angleRad));
int y = roundf(centerY + distance * sin_t(angleRad));
return getPixelColorXY(x, y);
From 1ff5cb0596d4a355a96570a296b5c7f58ba7cf92 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bla=C5=BE=20Kristan?=
Date: Sun, 12 May 2024 11:12:13 +0200
Subject: [PATCH 07/25] Experimental parallel I2S support for ESP32 - increased
outputs to 17 - increased max possible color order overrides - use
WLED_USE_PARALLEL_I2S during compile
WARNING: Do not set up more than 256 LEDs per output when using parallel I2S with NeoPixelBus less than 2.9.0
---
wled00/bus_wrapper.h | 65 +++++++++++++++++++++-----
wled00/cfg.cpp | 14 +++---
wled00/const.h | 6 ++-
wled00/data/settings_leds.htm | 86 ++++++++++++++++++-----------------
wled00/set.cpp | 51 +++++++++++----------
wled00/xml.cpp | 36 ++++++++-------
6 files changed, 156 insertions(+), 102 deletions(-)
diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h
index 99ae4c5ef..57e98467e 100644
--- a/wled00/bus_wrapper.h
+++ b/wled00/bus_wrapper.h
@@ -224,8 +224,11 @@
//#define B_32_I0_NEO_3 NeoPixelBusLg // parallel I2S
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_NEO_3 NeoPixelBusLg
-//#define B_32_I1_NEO_3 NeoPixelBusLg // parallel I2S
+ #else
+#define B_32_I1_NEO_3 NeoPixelBusLg // parallel I2S
+ #endif
#endif
//RGBW
#define B_32_RN_NEO_4 NeoPixelBusLg
@@ -234,8 +237,11 @@
//#define B_32_I0_NEO_4 NeoPixelBusLg // parallel I2S
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_NEO_4 NeoPixelBusLg
-//#define B_32_I1_NEO_4 NeoPixelBusLg // parallel I2S
+ #else
+#define B_32_I1_NEO_4 NeoPixelBusLg // parallel I2S
+ #endif
#endif
//400Kbps
#define B_32_RN_400_3 NeoPixelBusLg
@@ -244,8 +250,11 @@
//#define B_32_I0_400_3 NeoPixelBusLg // parallel I2S
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_400_3 NeoPixelBusLg
-//#define B_32_I1_400_3 NeoPixelBusLg // parallel I2S
+ #else
+#define B_32_I1_400_3 NeoPixelBusLg // parallel I2S
+ #endif
#endif
//TM1814 (RGBW)
#define B_32_RN_TM1_4 NeoPixelBusLg
@@ -254,8 +263,11 @@
//#define B_32_I0_TM1_4 NeoPixelBusLg // parallel I2S
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_TM1_4 NeoPixelBusLg
-//#define B_32_I1_TM1_4 NeoPixelBusLg // parallel I2S
+ #else
+#define B_32_I1_TM1_4 NeoPixelBusLg // parallel I2S
+ #endif
#endif
//TM1829 (RGB)
#define B_32_RN_TM2_3 NeoPixelBusLg
@@ -264,8 +276,11 @@
//#define B_32_I0_TM2_3 NeoPixelBusLg // parallel I2S
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_TM2_3 NeoPixelBusLg
-//#define B_32_I1_TM2_3 NeoPixelBusLg // parallel I2S
+ #else
+#define B_32_I1_TM2_3 NeoPixelBusLg // parallel I2S
+ #endif
#endif
//UCS8903
#define B_32_RN_UCS_3 NeoPixelBusLg
@@ -274,8 +289,11 @@
//#define B_32_I0_UCS_3 NeoPixelBusLg // parallel I2S
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_UCS_3 NeoPixelBusLg
-//#define B_32_I1_UCS_3 NeoPixelBusLg // parallel I2S
+ #else
+#define B_32_I1_UCS_3 NeoPixelBusLg // parallel I2S
+ #endif
#endif
//UCS8904
#define B_32_RN_UCS_4 NeoPixelBusLg
@@ -284,8 +302,11 @@
//#define B_32_I0_UCS_4 NeoPixelBusLg// parallel I2S
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_UCS_4 NeoPixelBusLg
-//#define B_32_I1_UCS_4 NeoPixelBusLg// parallel I2S
+ #else
+#define B_32_I1_UCS_4 NeoPixelBusLg// parallel I2S
+ #endif
#endif
#define B_32_RN_APA106_3 NeoPixelBusLg
#ifndef WLED_NO_I2S0_PIXELBUS
@@ -293,8 +314,11 @@
//#define B_32_I0_APA106_3 NeoPixelBusLg // parallel I2S
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_APA106_3 NeoPixelBusLg
-//#define B_32_I1_APA106_3 NeoPixelBusLg // parallel I2S
+ #else
+#define B_32_I1_APA106_3 NeoPixelBusLg // parallel I2S
+ #endif
#endif
//FW1906 GRBCW
#define B_32_RN_FW6_5 NeoPixelBusLg
@@ -303,8 +327,11 @@
//#define B_32_I0_FW6_5 NeoPixelBusLg // parallel I2S
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_FW6_5 NeoPixelBusLg
-//#define B_32_I1_FW6_5 NeoPixelBusLg // parallel I2S
+ #else
+#define B_32_I1_FW6_5 NeoPixelBusLg // parallel I2S
+ #endif
#endif
//WS2805 RGBWC
#define B_32_RN_2805_5 NeoPixelBusLg
@@ -313,8 +340,11 @@
//#define B_32_I0_2805_5 NeoPixelBusLg // parallel I2S
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_2805_5 NeoPixelBusLg
-//#define B_32_I1_2805_5 NeoPixelBusLg // parallel I2S
+ #else
+#define B_32_I1_2805_5 NeoPixelBusLg // parallel I2S
+ #endif
#endif
//TM1914 (RGB)
#define B_32_RN_TM1914_3 NeoPixelBusLg
@@ -323,8 +353,11 @@
//#define B_32_I0_TM1914_3 NeoPixelBusLg
#endif
#ifndef WLED_NO_I2S1_PIXELBUS
+ #ifndef WLED_USE_PARALLEL_I2S
#define B_32_I1_TM1914_3 NeoPixelBusLg
-//#define B_32_I1_TM1914_3 NeoPixelBusLg
+ #else
+#define B_32_I1_TM1914_3 NeoPixelBusLg
+ #endif
#endif
#endif
@@ -541,7 +574,11 @@ class PolyBus {
#if defined(ARDUINO_ARCH_ESP32) && !(defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3))
// NOTE: "channel" is only used on ESP32 (and its variants) for RMT channel allocation
// since 0.15.0-b3 I2S1 is favoured for classic ESP32 and moved to position 0 (channel 0) so we need to subtract 1 for correct RMT allocation
+ #ifdef WLED_USE_PARALLEL_I2S
+ if (channel > 7) channel -= 8; // accommodate parallel I2S1 which is used 1st on classic ESP32
+ #else
if (channel > 0) channel--; // accommodate I2S1 which is used as 1st bus on classic ESP32
+ #endif
#endif
void* busPtr = nullptr;
switch (busType) {
@@ -1619,9 +1656,15 @@ class PolyBus {
//if (num > 3) offset = num -4; // I2S not supported yet
#else
// standard ESP32 has 8 RMT and 2 I2S channels
+ #ifdef WLED_USE_PARALLEL_I2S
+ if (num > 16) return I_NONE;
+ if (num < 8) offset = 2; // prefer 8 parallel I2S1 channels
+ if (num == 16) offset = 1;
+ #else
if (num > 9) return I_NONE;
if (num > 8) offset = 1;
if (num == 0) offset = 2; // prefer I2S1 for 1st bus (less flickering but more RAM needed)
+ #endif
#endif
switch (busType) {
case TYPE_WS2812_1CH_X3:
diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp
index 22bfe577a..addd3fc5e 100644
--- a/wled00/cfg.cpp
+++ b/wled00/cfg.cpp
@@ -124,7 +124,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
CJSON(strip.panels, matrix[F("mpc")]);
strip.panel.clear();
JsonArray panels = matrix[F("panels")];
- uint8_t s = 0;
+ int s = 0;
if (!panels.isNull()) {
strip.panel.reserve(max(1U,min((size_t)strip.panels,(size_t)WLED_MAX_PANELS))); // pre-allocate memory for panels
for (JsonObject pnl : panels) {
@@ -156,7 +156,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
JsonArray ins = hw_led["ins"];
if (fromFS || !ins.isNull()) {
- uint8_t s = 0; // bus iterator
+ int s = 0; // bus iterator
if (fromFS) BusManager::removeAll(); // can't safely manipulate busses directly in network callback
uint32_t mem = 0, globalBufMem = 0;
uint16_t maxlen = 0;
@@ -790,7 +790,7 @@ void serializeConfig() {
JsonObject matrix = hw_led.createNestedObject(F("matrix"));
matrix[F("mpc")] = strip.panels;
JsonArray panels = matrix.createNestedArray(F("panels"));
- for (uint8_t i=0; igetLength()==0) break;
JsonObject ins = hw_led_ins.createNestedObject();
@@ -815,7 +815,7 @@ void serializeConfig() {
JsonArray ins_pin = ins.createNestedArray("pin");
uint8_t pins[5];
uint8_t nPins = bus->getPins(pins);
- for (uint8_t i = 0; i < nPins; i++) ins_pin.add(pins[i]);
+ for (int i = 0; i < nPins; i++) ins_pin.add(pins[i]);
ins[F("order")] = bus->getColorOrder();
ins["rev"] = bus->isReversed();
ins[F("skip")] = bus->skippedLeds();
@@ -829,7 +829,7 @@ void serializeConfig() {
JsonArray hw_com = hw.createNestedArray(F("com"));
const ColorOrderMap& com = BusManager::getColorOrderMap();
- for (uint8_t s = 0; s < com.count(); s++) {
+ for (int s = 0; s < com.count(); s++) {
const ColorOrderMapEntry *entry = com.get(s);
if (!entry) break;
@@ -846,7 +846,7 @@ void serializeConfig() {
JsonArray hw_btn_ins = hw_btn.createNestedArray("ins");
// configuration for all buttons
- for (uint8_t i=0; i
LED Settings