From b29ff1186bf579f8babc9d2f025a89d898c10885 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sun, 8 Jan 2023 19:09:30 +0100 Subject: [PATCH] best of I2CSPI-refactor * cherry-picking my additions to pinmanger * toDo: replace Wire.begin() with pinManager.joinWire() --- wled00/cfg.cpp | 2 +- wled00/pin_manager.cpp | 83 ++++++++++++++++++++++++++++++++++++++++++ wled00/pin_manager.h | 12 +++++- wled00/set.cpp | 2 +- wled00/wled.h | 2 +- 5 files changed, 97 insertions(+), 4 deletions(-) diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 33ce8392..dc52bdb0 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -309,7 +309,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { #ifdef ESP32 Wire.setPins(i2c_sda, i2c_scl); // this will fail if Wire is initilised (Wire.begin() called prior) #endif - Wire.begin(); + // Wire.begin(); // WLEDMM moved into pinManager } else { Serial.printf("pinmgr not success for global i2c %d %d\n", i2c_sda, i2c_scl); } diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 1d2d2599..32773ed9 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -513,6 +513,89 @@ bool PinManagerClass::isPinAllocated(byte gpio, PinOwner tag) return bitRead(pinAlloc[by], bi); } +// +// WLEDMM: central handling of I2C startup (global Wire #0) +// + +bool PinManagerClass::joinWire() { // shortcut in case no parameters provided + #ifdef ARDUINO_ARCH_ESP32 + // ESP32 - i2c pins can be mapped to any GPIO + return joinWire(i2c_sda, i2c_scl); + #else + // ESP8266: I2C pins are fixed + return joinWire(HW_PIN_SDA, HW_PIN_SCL); + #endif +} + +bool PinManagerClass::joinWire(int8_t pinSDA, int8_t pinSCL) { + // reject PIN = -1, reject SDA=SCL, reject "forbidden" pins + if ( (pinSDA < 0) || (pinSCL < 0) + || (pinSDA == pinSCL) + || !isPinOk(pinSDA, true) + || !isPinOk(pinSCL, true)) { + DEBUG_PRINT(F("PIN Manager: invalid GPIO for I2C: SDA=")); + DEBUG_PRINTF("%d, SCL=%d !\n",pinSDA, pinSCL); + return(false); + } + + if ((wire0PinSDA < 0) || (wire0PinSCL < 0)) wire0isStarted = false; // this should not happen + + // if wire already started, reject any other GPIO + if ((wire0isStarted == true) && + (pinSDA != wire0PinSDA) && (pinSDA != wire0PinSCL) && // allow "swapped pins2, i.e. SDA <->SCL + (pinSCL != wire0PinSCL) && (pinSCL != wire0PinSDA)) { + DEBUG_PRINT(F("PIN Manager: invalid GPIO for I2C: SDA=")); + DEBUG_PRINTF("%d, SCL=%d. Wire already started with sda=%d and scl=%d!\n",pinSDA, pinSCL, wirePinSDA, wirePinSCL); + return(false); + } + + // make sure pins are allocated + PinManagerPinType pins[2] = {{pinSCL, true}, {pinSDA, true}}; + if (!allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { // this will only FAIL when pins are invalid, or used already for other purposes + DEBUG_PRINT(F("PIN Manager: failed to allocate GPIO for I2C: SDA=")); + DEBUG_PRINTF("%d, SCL=%d !\n",pinSDA, pinSCL); + return(false); + } + + if(wire0isStarted == true) { + DEBUG_PRINTLN(F("PIN Manager: all good, I2C already started, nothing to do :-)")); + return(true); + } + + // NOW do it - start Wire !!! fire ;-) + + bool wireIsOK = true; + #ifdef ARDUINO_ARCH_ESP32 // ESP32 - i2c pins can be mapped to any GPIO + wireIsOK = Wire.setPins(pinSDA, pinSCL); // this will fail if Wire is initialised already (i.e. Wire.begin() called prior) + #else // 8266 - I2C pins are fixed + if((pinSDA != HW_PIN_SDA) || (pinSCL != HW_PIN_SCL)) { + DEBUG_PRINT(F("PIN Manager: warning ESP8266 I2C pins are fixed. please use SDA=")); + DEBUG_PRINTF("%d, SCL=%d !\n",HW_PIN_SDA, HW_PIN_SCL); + } + #endif + if (wireIsOK == false) { + USER_PRINTLN(F("PIN Manager: warning - wire.setPins failed!")); + } + + wireIsOK = Wire.begin(); // this will fail if wire is already running + + if (wireIsOK == false) { + USER_PRINTLN(F("PIN Manager: warning - wire.begin failed!")); + } else { + USER_PRINTLN(F("PIN Manager: wire.begin successfull.")); + } + +#ifdef ARDUINO_ARCH_ESP32S3 + Wire.setTimeOut(50); // workaround for wire timeout bug on -S3 + Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having wiring difficulties +#endif + + wire0isStarted = true; + wire0PinSDA = pinSDA; + wire0PinSCL = pinSCL; + return(true); +} + /* see https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/gpio.html * The ESP32-S3 chip features 45 physical GPIO pins (GPIO0 ~ GPIO21 and GPIO26 ~ GPIO48). Each pin can be used as a general-purpose I/O * Strapping pins: GPIO0, GPIO3, GPIO45 and GPIO46 are strapping pins. For more infomation, please refer to ESP32-S3 datasheet. diff --git a/wled00/pin_manager.h b/wled00/pin_manager.h index a7d8e1c5..508d9cac 100644 --- a/wled00/pin_manager.h +++ b/wled00/pin_manager.h @@ -83,8 +83,13 @@ class PinManagerClass { uint8_t spiAllocCount : 4; // allow multiple allocation of SPI bus pins but keep track of allocations }; + // WLEDMM: central handling of Wire (only for first bus) + bool wire0isStarted = false; // true is wire.begin() was done already + int8_t wire0PinSDA = -1; // GPIO currently in use for SDA + int8_t wire0PinSCL = -1; // GPIO currently in use for SCL + public: - PinManagerClass() : i2cAllocCount(0), spiAllocCount(0) {} + PinManagerClass() : i2cAllocCount(0), spiAllocCount(0), wire0isStarted(false) {} // WLEDMM: initialize wire0isStarted=false // De-allocates a single pin bool deallocatePin(byte gpio, PinOwner tag); // De-allocates multiple pins but only if all can be deallocated (PinOwner has to be specified) @@ -108,6 +113,11 @@ class PinManagerClass { #endif inline void deallocatePin(byte gpio) { deallocatePin(gpio, PinOwner::None); } + // WLEDMM: central initialization of Wire (Wire1 not supported yet) + bool joinWire(); // shortcut - use global pins when no parameters provided + bool joinWire(int8_t pinSDA, int8_t pinSCL); // use this instead of Wire.begin(SDA, SCL) + // toDo: may need to add calls for Wire.setClock, Wire.setPins Wire.end + // will return true for reserved pins bool isPinAllocated(byte gpio, PinOwner tag = PinOwner::None); // will return false for reserved pins diff --git a/wled00/set.cpp b/wled00/set.cpp index db35b853..61a8c008 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -543,7 +543,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) #ifdef ESP32 Wire.setPins(i2c_sda, i2c_scl); // this will fail if Wire is initilised (Wire.begin() called) #endif - Wire.begin(); + // Wire.begin(); // WLEDMM moved into pinManager } else { // there is no Wire.end() DEBUG_PRINTLN(F("Could not allocate I2C pins.")); diff --git a/wled00/wled.h b/wled00/wled.h index ff061985..bbfa8efe 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2301082 +#define VERSION 2301083 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG