-
-
Notifications
You must be signed in to change notification settings - Fork 11
Tube gyro pir #124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Tube gyro pir #124
Changes from all commits
5e3d35b
66f1d6d
48e3647
77d11ec
c73ab86
62de264
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -14,6 +14,8 @@ | |||||||
|
|
||||||||
| #if FT_MOONBASE == 1 | ||||||||
|
|
||||||||
| #include <Wire.h> // for i2C | ||||||||
|
|
||||||||
| #include "MoonBase/Module.h" | ||||||||
| #include "driver/uart.h" | ||||||||
|
|
||||||||
|
|
@@ -216,6 +218,15 @@ class ModuleIO : public Module { | |||||||
| addControl(rows, "Level", "text", 0, 32, true); // ro | ||||||||
| addControl(rows, "DriveCap", "text", 0, 32, true); // ro | ||||||||
| } | ||||||||
|
|
||||||||
| addControl(controls, "i2cFreq", "number", 0, 65534, false, "kHz"); | ||||||||
|
|
||||||||
| control = addControl(controls, "i2cBus", "rows"); | ||||||||
| control["crud"] = "r"; | ||||||||
| rows = control["n"].to<JsonArray>(); | ||||||||
| { | ||||||||
| addControl(rows, "address", "number", 0, 255, true); // ro | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| class PinAssigner { | ||||||||
|
|
@@ -564,6 +575,30 @@ class ModuleIO : public Module { | |||||||
| #else | ||||||||
| pinAssigner.assignPin(16, pin_LED); | ||||||||
| #endif | ||||||||
| #ifdef CONFIG_IDF_TARGET_ESP32 | ||||||||
| pinAssigner.assignPin(21, pin_I2C_SDA); | ||||||||
| pinAssigner.assignPin(22, pin_I2C_SCL); | ||||||||
| #else | ||||||||
| pinAssigner.assignPin(8, pin_I2C_SDA); | ||||||||
| pinAssigner.assignPin(9, pin_I2C_SCL); | ||||||||
| #endif | ||||||||
| // In setBoardPresetDefaults() for board_none (default case): | ||||||||
| #ifdef CONFIG_IDF_TARGET_ESP32 | ||||||||
| pinAssigner.assignPin(21, pin_I2C_SDA); // ESP32 classic | ||||||||
| pinAssigner.assignPin(22, pin_I2C_SCL); | ||||||||
| #elif defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3) | ||||||||
| pinAssigner.assignPin(8, pin_I2C_SDA); // ESP32-C3 | ||||||||
| pinAssigner.assignPin(9, pin_I2C_SCL); | ||||||||
| #elif defined(CONFIG_IDF_TARGET_ESP32C6) | ||||||||
| pinAssigner.assignPin(23, pin_I2C_SDA); // ESP32-C6 | ||||||||
| pinAssigner.assignPin(22, pin_I2C_SCL); | ||||||||
| #elif defined(CONFIG_IDF_TARGET_ESP32P4) | ||||||||
| pinAssigner.assignPin(7, pin_I2C_SDA); // ESP32-P4 (common board default) | ||||||||
| pinAssigner.assignPin(8, pin_I2C_SCL); | ||||||||
| #else | ||||||||
| pinAssigner.assignPin(21, pin_I2C_SDA); // Fallback | ||||||||
| pinAssigner.assignPin(22, pin_I2C_SCL); | ||||||||
| #endif | ||||||||
|
|
||||||||
| // trying to add more pins, but these pins not liked by esp32-d0-16MB ... 🚧 | ||||||||
| // pinAssigner.assignPin(4, pin_LED_02; | ||||||||
|
|
@@ -609,6 +644,8 @@ class ModuleIO : public Module { | |||||||
| newState["modded"] = true; | ||||||||
| } else if (updatedItem.name == "usage") { | ||||||||
| newState["modded"] = true; | ||||||||
| } else if (updatedItem.name == "i2cFreq") { | ||||||||
| Wire.setClock(updatedItem.value.as<uint16_t>() * 1000); | ||||||||
| } | ||||||||
|
|
||||||||
| if (newState.size()) update(newState, ModuleState::update, _moduleName); // if changes made then update | ||||||||
|
|
@@ -701,6 +738,9 @@ class ModuleIO : public Module { | |||||||
| #endif // ethernet | ||||||||
|
|
||||||||
| #if FT_BATTERY | ||||||||
| pinVoltage = UINT8_MAX; | ||||||||
| pinCurrent = UINT8_MAX; | ||||||||
| pinBattery = UINT8_MAX; | ||||||||
| for (JsonObject pinObject : _state.data["pins"].as<JsonArray>()) { | ||||||||
| uint8_t usage = pinObject["usage"]; | ||||||||
| if (usage == pin_Voltage) { | ||||||||
|
|
@@ -790,7 +830,37 @@ class ModuleIO : public Module { | |||||||
| } | ||||||||
| #endif | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| pinI2CSDA = UINT8_MAX; | ||||||||
| pinI2CSCL = UINT8_MAX; | ||||||||
| for (JsonObject pinObject : _state.data["pins"].as<JsonArray>()) { | ||||||||
| uint8_t usage = pinObject["usage"]; | ||||||||
| if (usage == pin_I2C_SDA) { | ||||||||
| pinI2CSDA = pinObject["GPIO"]; | ||||||||
| EXT_LOGD(ML_TAG, "I2CSDA found %d", pinI2CSDA); | ||||||||
| } | ||||||||
| if (usage == pin_I2C_SCL) { | ||||||||
| pinI2CSCL = pinObject["GPIO"]; | ||||||||
| EXT_LOGD(ML_TAG, "I2CSCL found %d", pinI2CSCL); | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| if (pinI2CSCL != UINT8_MAX && pinI2CSDA != UINT8_MAX) { | ||||||||
| Wire.end(); // Clean up any previous I2C initialization | ||||||||
| delay(100); | ||||||||
| uint16_t frequency = _state.data["i2cFreq"]; | ||||||||
| if (Wire.begin(pinI2CSDA, pinI2CSCL, frequency * 1000)) { | ||||||||
| EXT_LOGI(ML_TAG, "initI2C Wire sda:%d scl:%d freq:%d kHz", pinI2CSDA, pinI2CSCL, frequency); | ||||||||
| // delay(200); // Give I2C bus time to stabilize | ||||||||
| // Wire.setClock(50000); // Explicitly set to 100kHz | ||||||||
| updateDevices(); | ||||||||
| } else | ||||||||
| EXT_LOGE(ML_TAG, "initI2C Wire failed"); | ||||||||
| } | ||||||||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
Comment on lines
+848
to
+859
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Zero The Proposed fix — add a default and guard against zeroIn - addControl(controls, "i2cFreq", "number", 0, 65534, false, "kHz");
+ control = addControl(controls, "i2cFreq", "number", 10, 1000, false, "kHz");
+ control["default"] = 100; // 100 kHz standard modeAnd in uint16_t frequency = _state.data["i2cFreq"];
+ if (frequency == 0) frequency = 100; // fallback to 100 kHz
if (Wire.begin(pinI2CSDA, pinI2CSCL, frequency * 1000)) {🤖 Prompt for AI Agents |
||||||||
| } // readPins | ||||||||
|
|
||||||||
| uint8_t pinI2CSDA = UINT8_MAX; | ||||||||
| uint8_t pinI2CSCL = UINT8_MAX; | ||||||||
|
|
||||||||
| #if FT_BATTERY | ||||||||
| uint8_t pinVoltage = UINT8_MAX; | ||||||||
|
|
@@ -867,6 +937,32 @@ class ModuleIO : public Module { | |||||||
| #endif | ||||||||
| } | ||||||||
|
|
||||||||
| void updateDevices() { | ||||||||
| JsonDocument doc; | ||||||||
| doc["i2cBus"].to<JsonArray>(); | ||||||||
| JsonObject newState = doc.as<JsonObject>(); | ||||||||
|
|
||||||||
| EXT_LOGI(ML_TAG, "Scanning I2C bus..."); | ||||||||
| byte count = 0; | ||||||||
| for (byte i = 1; i < 127; i++) { | ||||||||
| Wire.beginTransmission(i); | ||||||||
| if (Wire.endTransmission() == 0) { | ||||||||
| JsonObject i2cDevice = newState["i2cBus"].as<JsonArray>().add<JsonObject>(); | ||||||||
| i2cDevice["address"] = i; | ||||||||
|
|
||||||||
| EXT_LOGI(ML_TAG, "Found I2C device at address 0x%02X", i); | ||||||||
| count++; | ||||||||
| } | ||||||||
| } | ||||||||
| EXT_LOGI(ML_TAG, "Found %d device(s)", count); | ||||||||
| JsonObject i2cDevice = newState["i2cBus"].as<JsonArray>().add<JsonObject>(); | ||||||||
| i2cDevice["address"] = 255; | ||||||||
|
Comment on lines
+958
to
+959
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sentinel entry with address 255 pollutes the device list. A fake device at address 255 is appended after the real scan results. This is not a valid I2C address (7-bit range is 0–127) and will appear as a spurious device in the UI. If this is meant to ensure the Proposed fix: remove the sentinel EXT_LOGI(ML_TAG, "Found %d device(s)", count);
- JsonObject i2cDevice = newState["i2cBus"].as<JsonArray>().add<JsonObject>();
- i2cDevice["address"] = 255;📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||
|
|
||||||||
| doc["i2cFreq"] = Wire.getClock() / 1000; | ||||||||
|
|
||||||||
| update(newState, ModuleState::update, _moduleName); | ||||||||
| } | ||||||||
|
|
||||||||
| private: | ||||||||
| ESP32SvelteKit* _sveltekit; | ||||||||
| uint8_t current_board_id = UINT8_MAX; | ||||||||
|
|
||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -264,6 +264,9 @@ class NodeManager : public Module { | |
| if (nodeClass != nullptr) { | ||
| nodeClass->on = updatedItem.value.as<bool>(); // set nodeclass on/off | ||
| // EXT_LOGD(ML_TAG, " nodeclass 🔘:%d 🚥:%d 💎:%d", nodeClass->on, nodeClass->hasOnLayout(), nodeClass->hasModifier()); | ||
| xSemaphoreTake(*nodeClass->layerMutex, portMAX_DELAY); | ||
| nodeClass->onUpdate(updatedItem.oldValue, nodeState); // custom onUpdate for the node | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Inconsistent mutex handling and argument semantics for Two observations:
+ xSemaphoreTake(*nodeClass->layerMutex, portMAX_DELAY);
nodeClass->onUpdate(updatedItem.oldValue, nodeState); // custom onUpdate for the node
+ xSemaphoreGive(*nodeClass->layerMutex);
🤖 Prompt for AI Agents |
||
| xSemaphoreGive(*nodeClass->layerMutex); | ||
| nodeClass->requestMappings(); | ||
| } else | ||
| EXT_LOGW(ML_TAG, "Nodeclass %s not found", nodeState["name"].as<const char*>()); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -344,6 +344,8 @@ static struct SharedData { | |
| size_t connectedClients; | ||
| size_t activeClients; | ||
| size_t clientListSize; | ||
|
|
||
| Coord3D gravity; | ||
|
Comment on lines
+347
to
+348
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
As noted in the D_IMU.h review, the MPU6050 gravity vector contains float values in the range [–1.0, 1.0]. If 🤖 Prompt for AI Agents |
||
| } sharedData; | ||
|
|
||
| /** | ||
|
|
@@ -360,6 +362,7 @@ static struct SharedData { | |
| #include "MoonLight/Nodes/Drivers/D_FastLED.h" | ||
| #include "MoonLight/Nodes/Drivers/D_Hub75.h" | ||
| #include "MoonLight/Nodes/Drivers/D_Infrared.h" | ||
| #include "MoonLight/Nodes/Drivers/D_IMU.h" | ||
| #include "MoonLight/Nodes/Drivers/D_ParallelLEDDriver.h" | ||
| #include "MoonLight/Nodes/Drivers/D__Sandbox.h" | ||
| #include "MoonLight/Nodes/Effects/E_FastLED.h" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -106,6 +106,7 @@ class ModuleDrivers : public NodeManager { | |
| addControlValue(control, getNameAndTags<ArtNetOutDriver>()); | ||
| addControlValue(control, getNameAndTags<AudioSyncDriver>()); | ||
| addControlValue(control, getNameAndTags<IRDriver>()); | ||
| addControlValue(control, getNameAndTags<IMUDriver>()); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Build failure: This is the downstream effect of the class name mismatch in 🧰 Tools🪛 GitHub Actions: PlatformIO CI[error] 109-109: 'IMUDriver' was not declared in this scope; did you mean 'IRDriver'? [error] 109-109: no matching function for call to 'getNameAndTags()' (template argument deduction/substitution failed) 🤖 Prompt for AI Agents |
||
| addControlValue(control, getNameAndTags<HUB75Driver>()); | ||
|
|
||
| // board preset specific | ||
|
|
@@ -143,6 +144,7 @@ class ModuleDrivers : public NodeManager { | |
| if (!node) node = checkAndAlloc<ArtNetOutDriver>(name); | ||
| if (!node) node = checkAndAlloc<AudioSyncDriver>(name); | ||
| if (!node) node = checkAndAlloc<IRDriver>(name); | ||
| if (!node) node = checkAndAlloc<IMUDriver>(name); | ||
| if (!node) node = checkAndAlloc<HUB75Driver>(name); | ||
|
|
||
| // board preset specific | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| /** | ||
| @title MoonLight | ||
| @file D_MPU6050.h | ||
| @repo https://github.com/MoonModules/MoonLight, submit changes to this file as PRs | ||
| @Authors https://github.com/MoonModules/MoonLight/commits/main | ||
| @Doc https://moonmodules.org/MoonLight/moonlight/overview/ | ||
| @Copyright © 2026 Github MoonLight Commit Authors | ||
| @license GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 | ||
| @license For non GPL-v3 usage, commercial licenses must be purchased. Contact us for more information. | ||
| **/ | ||
|
|
||
| #if FT_MOONLIGHT | ||
|
|
||
| // #include <BMI160Gen.h> | ||
| #include <MPU6050_6Axis_MotionApps20.h> | ||
|
|
||
| class IMUDriver : public Node { | ||
| public: | ||
| static const char* name() { return "IMU driver"; } // Inertial Measurement Unit | ||
| static uint8_t dim() { return _NoD; } | ||
| static const char* tags() { return "☸️"; } | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| bool motionTrackingReady = false; // set true if DMP init was successful | ||
|
|
||
| Coord3D gyro; // in degrees (not radians) | ||
| Coord3D accell; | ||
| uint8_t board = 0; | ||
|
|
||
| void setup() override { | ||
| addControl(gyro, "gyro", "coord3D"); | ||
| addControl(accell, "accell", "coord3D"); | ||
| // isEnabled = false; // need to enable after fresh setup | ||
| addControl(board, "board", "select"); | ||
| addControlValue("MPU6050"); | ||
| addControlValue("BMI160"); // not supported yet | ||
|
Comment on lines
+29
to
+35
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If a user changes 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| void onUpdate(const Char<20>& oldValue, const JsonObject& control) override { | ||
| // add your custom onUpdate code here | ||
| if (!control["on"].isNull()) { // control is the node n case of on! | ||
| if (control["on"] == true) { | ||
| bool i2cInited = true; // todo: check in moduleIO if successfull | ||
| if (i2cInited) { | ||
| if (board == 0) { // MPU6050 | ||
| mpu.initialize(); | ||
|
|
||
| // delay(100); | ||
|
|
||
| // verify connection | ||
| if (mpu.testConnection()) { | ||
| EXT_LOGI(ML_TAG, "MPU6050 connection successful Initializing DMP..."); | ||
| uint8_t devStatus = mpu.dmpInitialize(); | ||
|
|
||
| if (devStatus == 0) { | ||
| // // Calibration Time: generate offsets and calibrate our MPU6050 | ||
| mpu.CalibrateAccel(6); | ||
| mpu.CalibrateGyro(6); | ||
| // mpu.PrintActiveOffsets(); | ||
|
|
||
| mpu.setDMPEnabled(true); // mandatory | ||
|
|
||
| // mpuIntStatus = mpu.getIntStatus(); | ||
|
|
||
| motionTrackingReady = true; | ||
| } else { | ||
| // ERROR! | ||
| // 1 = initial memory load failed | ||
| // 2 = DMP configuration updates failed | ||
| // (if it's going to break, usually the code will be 1) | ||
| EXT_LOGW(ML_TAG, "DMP Initialization failed (code %d)", devStatus); | ||
| } | ||
| } else | ||
| EXT_LOGW(ML_TAG, "Testing device connections MPU6050 connection failed"); | ||
| } else if (board == 1) { // BMI160 - NEW | ||
|
|
||
| // BMI160.begin(BMI160GenClass::I2C_MODE, 0x68); | ||
|
|
||
| // if (BMI160.getDeviceID() == 0xD1) { // BMI160 device ID | ||
| // EXT_LOGI(ML_TAG, "BMI160 connection successful"); | ||
| // motionTrackingReady = true; | ||
| // } else { | ||
| // EXT_LOGW(ML_TAG, "BMI160 connection failed"); | ||
| // } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
Comment on lines
+38
to
+88
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No cleanup path when the driver is turned off — DMP left running, When Proposed fix sketch if (control["on"] == true) {
// ... existing init code ...
+ } else {
+ if (motionTrackingReady) {
+ mpu.setDMPEnabled(false);
+ motionTrackingReady = false;
+ }
}And in the destructor: - ~IMUDriver() override {};
+ ~IMUDriver() override {
+ if (motionTrackingReady) {
+ mpu.setDMPEnabled(false);
+ motionTrackingReady = false;
+ }
+ };🤖 Prompt for AI Agents |
||
|
|
||
| void loop20ms() override { | ||
| // mpu.getMotion6(&accell.x, &accell.y, &accell.z, &gyro.x, &gyro.y, &gyro.z); | ||
| // // display tab-separated accel/gyro x/y/z values | ||
| // EXT_LOGI(ML_TAG, "mpu6050 %d,%d,%d %d,%d,%d", accell.x, accell.y, accell.z, gyro.x, gyro.y, gyro.z); | ||
|
|
||
| // if programming failed, don't try to do anything | ||
| if (!motionTrackingReady) return; | ||
| // read a packet from FIFO | ||
| if (board == 0) { // MPU6050 | ||
| if (mpu.dmpGetCurrentFIFOPacket(fifoBuffer)) { // Get the Latest packet | ||
| mpu.dmpGetQuaternion(&q, fifoBuffer); | ||
| mpu.dmpGetGravity(&gravity, &q); | ||
| mpu.dmpGetYawPitchRoll(ypr, &q, &gravity); | ||
| gyro.y = ypr[0] * 180 / M_PI; // pan = yaw ! | ||
| gyro.x = ypr[1] * 180 / M_PI; // tilt = pitch ! | ||
| gyro.z = ypr[2] * 180 / M_PI; // roll = roll | ||
| sharedData.gravity.x = gravity.x * INT16_MAX; | ||
| sharedData.gravity.y = gravity.y * INT16_MAX; | ||
| sharedData.gravity.z = gravity.z * INT16_MAX; | ||
| // display real acceleration, adjusted to remove gravity | ||
|
|
||
| EXT_LOGD(ML_TAG, "%f %f %f", gravity.x, gravity.y, gravity.z); | ||
|
|
||
| // needed to repeat the following 3 lines (yes if you look at the output: otherwise not 0) | ||
| // mpu.dmpGetQuaternion(&q, fifoBuffer); | ||
| mpu.dmpGetAccel(&aa, fifoBuffer); | ||
| // mpu.dmpGetGravity(&gravity, &q); | ||
|
|
||
| mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity); | ||
| // mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q); //worked in 0.6.0, not in 1.3.0 anymore | ||
|
|
||
| accell.x = aaReal.x; | ||
| accell.y = aaReal.y; | ||
| accell.z = aaReal.z; | ||
| } | ||
| } else if (board == 1) { // BMI160 - NEW | ||
| // int gx, gy, gz, ax, ay, az; | ||
| // BMI160.readGyro(gx, gy, gz); | ||
| // BMI160.readAccelerometer(ax, ay, az); | ||
|
|
||
| // // Convert raw values to degrees (BMI160 gyro: 16.4 LSB/°/s at ±2000°/s range) | ||
| // gyro.x = gx / 16.4f; | ||
| // gyro.y = gy / 16.4f; | ||
| // gyro.z = gz / 16.4f; | ||
|
|
||
| // // Convert raw accel values (BMI160 accel: 16384 LSB/g at ±2g range) | ||
| // accell.x = ax; | ||
| // accell.y = ay; | ||
| // accell.z = az; | ||
|
|
||
| // // Calculate gravity vector from accelerometer | ||
| // float norm = sqrt(ax*ax + ay*ay + az*az); | ||
| // if (norm > 0) { | ||
| // sharedData.gravity.x = (ax / norm) * INT16_MAX; | ||
| // sharedData.gravity.y = (ay / norm) * INT16_MAX; | ||
| // sharedData.gravity.z = (az / norm) * INT16_MAX; | ||
| // } | ||
| } | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| }; | ||
|
|
||
| ~IMUDriver() override {}; | ||
|
|
||
| private: | ||
| MPU6050 mpu; | ||
|
|
||
| // MPU control/status vars | ||
| uint8_t fifoBuffer[64]; // FIFO storage buffer | ||
|
|
||
| // orientation/motion vars | ||
| Quaternion q; // [w, x, y, z] quaternion container | ||
| VectorInt16 aa; // [x, y, z] accel sensor measurements | ||
| VectorInt16 aaReal; // [x, y, z] gravity-free accel sensor measurements | ||
| // VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements | ||
| VectorFloat gravity; // [x, y, z] gravity vector | ||
| // float euler[3]; // [psi, theta, phi] Euler angle container | ||
| float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector | ||
| }; | ||
|
|
||
| #endif | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicate I2C pin assignments — first block is dead code.
Lines 578–584 assign I2C pins, then lines 586–601 immediately overwrite them with a more granular per-target mapping. The first block is redundant. For
CONFIG_IDF_TARGET_ESP32, pins 21/22 are assigned twice; for other targets (e.g., C6), the first assignment (8/9) is silently overwritten.Proposed fix — remove the first block
🤖 Prompt for AI Agents