From acc2d3aa10d0d38db43d90033bfc56ee0ca86bd7 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 19 Sep 2023 19:33:36 +0200 Subject: [PATCH] clean up I2C pin handling in audioreactive (ES7243+ES8388) * remove double Wire.begin() - Wire cannot be re-initialized; its already started by pinManager.joinWire() * Only use global I2C pins; make sure that audireactive I2C settings are aligned with global I2C pins * minor cleanup * remove I2C pins from AudioSource::initialize() Note to self: sdaPin, sclPin are just dummy values now, good for UI consistency, but unused otherwise. Could be removed. --- usermods/audioreactive/audio_reactive.h | 27 +++++- usermods/audioreactive/audio_source.h | 109 ++++++------------------ 2 files changed, 49 insertions(+), 87 deletions(-) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index ffe6e8ad..c4669869 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -1687,7 +1687,13 @@ class AudioReactive : public Usermod { //useInputFilter = 0; // in case you need to disable low-cut software filtering audioSource = new ES7243(SAMPLE_RATE, BLOCK_SIZE); delay(100); - if (audioSource) audioSource->initialize(sdaPin, sclPin, i2swsPin, i2ssdPin, i2sckPin, mclkPin); + // WLEDMM align global pins + if ((sdaPin >= 0) && (i2c_sda < 0)) i2c_sda = sdaPin; // copy usermod prefs into globals (if globals not defined) + if ((sclPin >= 0) && (i2c_scl < 0)) i2c_scl = sclPin; + if (i2c_sda >= 0) sdaPin = -1; // -1 = use global + if (i2c_scl >= 0) sclPin = -1; + + if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin); break; case 3: DEBUGSR_PRINT(F("AR: SPH0645 Microphone - ")); DEBUGSR_PRINTLN(F(I2S_MIC_CHANNEL_TEXT)); @@ -1719,11 +1725,21 @@ class AudioReactive : public Usermod { break; #endif case 6: - DEBUGSR_PRINTLN(F("AR: ES8388 Source")); + #ifdef use_es8388_mic + DEBUGSR_PRINTLN(F("AR: ES8388 Source (Mic)")); + #else + DEBUGSR_PRINTLN(F("AR: ES8388 Source (Line-In)")); + #endif audioSource = new ES8388Source(SAMPLE_RATE, BLOCK_SIZE, 1.0f); //useInputFilter = 0; // to disable low-cut software filtering and restore previous behaviour delay(100); - if (audioSource) audioSource->initialize(sdaPin, sclPin, i2swsPin, i2ssdPin, i2sckPin, mclkPin); + // WLEDMM align global pins + if ((sdaPin >= 0) && (i2c_sda < 0)) i2c_sda = sdaPin; // copy usermod prefs into globals (if globals not defined) + if ((sclPin >= 0) && (i2c_scl < 0)) i2c_scl = sclPin; + if (i2c_sda >= 0) sdaPin = -1; // -1 = use global + if (i2c_scl >= 0) sclPin = -1; + + 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) @@ -2366,6 +2382,11 @@ class AudioReactive : public Usermod { JsonObject dmic = top.createNestedObject(FPSTR(_digitalmic)); dmic[F("type")] = dmType; + // WLEDMM: align with globals I2C pins + if ((dmType == 2) || (dmType == 6)) { // only for ES7243 and ES8388 + if (i2c_sda >= 0) sdaPin = -1; // -1 = use global + if (i2c_scl >= 0) sclPin = -1; // -1 = use global + } JsonArray pinArray = dmic.createNestedArray("pin"); pinArray.add(i2ssdPin); pinArray.add(i2swsPin); diff --git a/usermods/audioreactive/audio_source.h b/usermods/audioreactive/audio_source.h index a0982381..8aa7c44d 100644 --- a/usermods/audioreactive/audio_source.h +++ b/usermods/audioreactive/audio_source.h @@ -126,7 +126,7 @@ class AudioSource { This function needs to take care of anything that needs to be done before samples can be obtained from the microphone. */ - virtual void initialize(int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) = 0; + virtual void initialize(int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) = 0; /* Deinitialize Release all resources and deactivate any functionality that is used @@ -205,7 +205,7 @@ class I2SSource : public AudioSource { }; } - virtual void initialize(int8_t i2swsPin = I2S_PIN_NO_CHANGE, int8_t i2ssdPin = I2S_PIN_NO_CHANGE, int8_t i2sckPin = I2S_PIN_NO_CHANGE, int8_t mclkPin = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) { + virtual void initialize(int8_t i2swsPin = I2S_PIN_NO_CHANGE, int8_t i2ssdPin = I2S_PIN_NO_CHANGE, int8_t i2sckPin = I2S_PIN_NO_CHANGE, int8_t mclkPin = I2S_PIN_NO_CHANGE) { DEBUGSR_PRINTLN("I2SSource:: initialize()."); if (i2swsPin != I2S_PIN_NO_CHANGE && i2ssdPin != I2S_PIN_NO_CHANGE) { if (!pinManager.allocatePin(i2swsPin, true, PinOwner::UM_Audioreactive) || @@ -425,19 +425,14 @@ class ES7243 : public I2SSource { private: // I2C initialization functions for ES7243 void _es7243I2cBegin() { - bool i2c_initialized = Wire.begin(pin_ES7243_SDA, pin_ES7243_SCL, 100000U); - if (i2c_initialized == false) { - ERRORSR_PRINTLN(F("AR: ES7243 failed to initialize I2C bus driver.")); - } + Wire.setClock(100000); } void _es7243I2cWrite(uint8_t reg, uint8_t val) { -#ifndef ES7243_ADDR - Wire.beginTransmission(0x13); - #define ES7243_ADDR 0x13 // default address -#else + #ifndef ES7243_ADDR + #define ES7243_ADDR 0x13 // default address + #endif Wire.beginTransmission(ES7243_ADDR); -#endif Wire.write((uint8_t)reg); Wire.write((uint8_t)val); uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK @@ -462,54 +457,30 @@ public: _config.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT; }; - void initialize(int8_t sdaPin, int8_t sclPin, int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) { + void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) { DEBUGSR_PRINTLN("ES7243:: initialize();"); - // check that pins are valid - if ((sdaPin < 0) || (sclPin < 0)) { - ERRORSR_PRINTF("\nAR: invalid ES7243 I2C pins: SDA=%d, SCL=%d\n", sdaPin, sclPin); - return; - } - if ((i2c_sda < 0) || (i2c_scl < 0)) { // check that global I2C pins are not "undefined" + // if ((i2sckPin < 0) || (mclkPin < 0)) { // WLEDMM not sure if this check is needed here, too + // ERRORSR_PRINTF("\nAR: invalid I2S pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin); + // return; + // } + if ((i2c_sda < 0) || (i2c_scl < 0)) { // check that global I2C pins are not "undefined" ERRORSR_PRINTF("\nAR: invalid ES7243 global I2C pins: SDA=%d, SCL=%d\n", i2c_sda, i2c_scl); return; } - if (!pinManager.joinWire()) { // WLEDMM specific: start I2C with globally defined pins + if (!pinManager.joinWire(i2c_sda, i2c_scl)) { // WLEDMM specific: start I2C with globally defined pins ERRORSR_PRINTF("\nAR: failed to join I2C bus with SDA=%d, SCL=%d\n", i2c_sda, i2c_scl); return; } - if ((i2sckPin < 0) || (mclkPin < 0)) { - ERRORSR_PRINTF("\nAR: invalid I2S pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin); - return; - } - - // Reserve SDA and SCL pins of the I2C interface - PinManagerPinType es7243Pins[2] = { { sdaPin, true }, { sclPin, true } }; - if (!pinManager.allocateMultiplePins(es7243Pins, 2, PinOwner::HW_I2C)) { - pinManager.deallocateMultiplePins(es7243Pins, 2, PinOwner::HW_I2C); - ERRORSR_PRINTF("\nAR: Failed to allocate ES7243 I2C pins: SDA=%d, SCL=%d\n", sdaPin, sclPin); - return; - } - - pin_ES7243_SDA = sdaPin; - pin_ES7243_SCL = sclPin; - // First route mclk, then configure ADC over I2C, then configure I2S _es7243InitAdc(); I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin); } void deinitialize() { - // Release SDA and SCL pins of the I2C interface - PinManagerPinType es7243Pins[2] = { { pin_ES7243_SDA, true }, { pin_ES7243_SCL, true } }; - pinManager.deallocateMultiplePins(es7243Pins, 2, PinOwner::HW_I2C); I2SSource::deinitialize(); } - - private: - int8_t pin_ES7243_SDA; - int8_t pin_ES7243_SCL; }; /* ES8388 Sound Modude @@ -520,19 +491,14 @@ class ES8388Source : public I2SSource { private: // I2C initialization functions for ES8388 void _es8388I2cBegin() { - bool i2c_initialized = Wire.begin(pin_ES8388_SDA, pin_ES8388_SCL, 100000U); - if (i2c_initialized == false) { - ERRORSR_PRINTLN(F("AR: ES8388 failed to initialize I2C bus driver.")); - } + Wire.setClock(100000); } void _es8388I2cWrite(uint8_t reg, uint8_t val) { -#ifndef ES8388_ADDR - Wire.beginTransmission(0x10); - #define ES8388_ADDR 0x10 // default address -#else + #ifndef ES8388_ADDR + #define ES8388_ADDR 0x10 // default address + #endif Wire.beginTransmission(ES8388_ADDR); -#endif Wire.write((uint8_t)reg); Wire.write((uint8_t)val); uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK @@ -619,59 +585,34 @@ class ES8388Source : public I2SSource { _config.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT; }; - void initialize(int8_t sdaPin, int8_t sclPin, int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) { + void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) { DEBUGSR_PRINTLN("ES8388Source:: initialize();"); + // if ((i2sckPin < 0) || (mclkPin < 0)) { // WLEDMM not sure if this check is needed here, too + // ERRORSR_PRINTF("\nAR: invalid I2S ES8388 pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin); + // return; + // } // BUG: "use global I2C pins" are valid as -1, and -1 is seen as invalid here. // Workaround: Set I2C pins here, which will also set them globally. // Bug also exists in ES7243. - - // check that pins are valid - if ((sdaPin < 0) || (sclPin < 0)) { - ERRORSR_PRINTF("\nAR: invalid ES8388 I2C pins: SDA=%d, SCL=%d\n", sdaPin, sclPin); - return; - } - if ((i2c_sda < 0) || (i2c_scl < 0)) { // check that global I2C pins are not "undefined" ERRORSR_PRINTF("\nAR: invalid ES8388 global I2C pins: SDA=%d, SCL=%d\n", i2c_sda, i2c_scl); return; } - if (!pinManager.joinWire()) { // WLEDMM specific: start I2C with globally defined pins + if (!pinManager.joinWire(i2c_sda, i2c_scl)) { // WLEDMM specific: start I2C with globally defined pins ERRORSR_PRINTF("\nAR: failed to join I2C bus with SDA=%d, SCL=%d\n", i2c_sda, i2c_scl); return; } - if ((i2sckPin < 0) || (mclkPin < 0)) { - ERRORSR_PRINTF("\nAR: invalid I2S pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin); - return; - } - - // Reserve SDA and SCL pins of the I2C interface - PinManagerPinType es8388Pins[2] = { { sdaPin, true }, { sclPin, true } }; - if (!pinManager.allocateMultiplePins(es8388Pins, 2, PinOwner::HW_I2C)) { - pinManager.deallocateMultiplePins(es8388Pins, 2, PinOwner::HW_I2C); - ERRORSR_PRINTF("\nAR: Failed to allocate ES8388 I2C pins: SDA=%d, SCL=%d\n", sdaPin, sclPin); - return; - } - - pin_ES8388_SDA = sdaPin; - pin_ES8388_SCL = sclPin; - // First route mclk, then configure ADC over I2C, then configure I2S _es8388InitAdc(); I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin); } void deinitialize() { - // Release SDA and SCL pins of the I2C interface - PinManagerPinType es8388Pins[2] = { { pin_ES8388_SDA, true }, { pin_ES8388_SCL, true } }; - pinManager.deallocateMultiplePins(es8388Pins, 2, PinOwner::HW_I2C); I2SSource::deinitialize(); } - private: - int8_t pin_ES8388_SDA; - int8_t pin_ES8388_SCL; }; #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) @@ -714,7 +655,7 @@ class I2SAdcSource : public I2SSource { /* identify Audiosource type - I2S-ADC*/ AudioSourceType getType(void) {return(Type_I2SAdc);} - void initialize(int8_t audioPin, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) { + void initialize(int8_t audioPin, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) { DEBUGSR_PRINTLN("I2SAdcSource:: initialize()."); _myADCchannel = 0x0F; if(!pinManager.allocatePin(audioPin, false, PinOwner::UM_Audioreactive)) { @@ -886,7 +827,7 @@ class SPH0654 : public I2SSource { I2SSource(sampleRate, blockSize, sampleScale, i2sMaster) {} - void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE, int8_t = I2S_PIN_NO_CHANGE) { + void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t = I2S_PIN_NO_CHANGE) { DEBUGSR_PRINTLN("SPH0654:: initialize();"); I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin); #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)