From b02a66a1b6440b61c0fdb8e2a3e4527a136ed8ba Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 17 Nov 2023 13:02:19 +0100 Subject: [PATCH] Fix ESP32C3 relay toggle on restart Fix ESP32C3 relay toggle on restart (#20030) --- tasmota/tasmota_support/support.ino | 14 -------- tasmota/tasmota_support/support_esp32.ino | 38 +++++++++++++++++++++ tasmota/tasmota_support/support_tasmota.ino | 18 ---------- tasmota/tasmota_support/support_wifi.ino | 7 ++-- 4 files changed, 43 insertions(+), 34 deletions(-) diff --git a/tasmota/tasmota_support/support.ino b/tasmota/tasmota_support/support.ino index 203ffb19d..6790b7090 100755 --- a/tasmota/tasmota_support/support.ino +++ b/tasmota/tasmota_support/support.ino @@ -1442,30 +1442,16 @@ void SetPin(uint32_t lpin, uint32_t gpio) { TasmotaGlobal.gpio_pin[lpin] = gpio; } -#ifdef CONFIG_IDF_TARGET_ESP32C3 -#include "driver/gpio.h" // Include needed for Arduino 3 -#endif - void DigitalWrite(uint32_t gpio_pin, uint32_t index, uint32_t state) { static uint32_t pinmode_init[2] = { 0 }; // Pins 0 to 63 !!! if (PinUsed(gpio_pin, index)) { uint32_t pin = Pin(gpio_pin, index) & 0x3F; // Fix possible overflow over 63 gpios -#ifdef CONFIG_IDF_TARGET_ESP32C3 -// if (GPIO_REL1 == gpio_pin) { - gpio_hold_dis((gpio_num_t)pin); // Allow state change -// } -#endif if (!bitRead(pinmode_init[pin / 32], pin % 32)) { bitSet(pinmode_init[pin / 32], pin % 32); pinMode(pin, OUTPUT); } digitalWrite(pin, state &1); -#ifdef CONFIG_IDF_TARGET_ESP32C3 - if (GPIO_REL1 == gpio_pin) { - gpio_hold_en((gpio_num_t)pin); // Retain the state when the chip or system is reset, for example, when watchdog time-out or Deep-sleep - } -#endif } } diff --git a/tasmota/tasmota_support/support_esp32.ino b/tasmota/tasmota_support/support_esp32.ino index 5a3891663..e3c29dcce 100644 --- a/tasmota/tasmota_support/support_esp32.ino +++ b/tasmota/tasmota_support/support_esp32.ino @@ -978,4 +978,42 @@ uint32_t HwRandom(void) { #endif // ESP_IDF_VERSION_MAJOR >= 5 } +/********************************************************************************************/ +// Since ESP-IDF 4.4, GPIO matrix or I/O is not reset during a restart +// and GPIO configuration can get stuck because of leftovers +// +// This patched version of pinMode forces a full GPIO reset before setting new mode +// +#include "driver/gpio.h" + +extern "C" void ARDUINO_ISR_ATTR __pinMode(uint8_t pin, uint8_t mode); + +extern "C" void ARDUINO_ISR_ATTR pinMode(uint8_t pin, uint8_t mode) { + gpio_reset_pin((gpio_num_t)pin); + __pinMode(pin, mode); +#ifdef CONFIG_IDF_TARGET_ESP32C3 + // See GpioForceHoldRelay() below + gpio_hold_dis((gpio_num_t)pin); // Allow state change +#endif +} + +#ifdef CONFIG_IDF_TARGET_ESP32C3 +void GpioForceHoldRelay(void) { + // Only ESP32-C3 toggles outputs on restart unless gpio_hold_en() is called before restart + // Retain the state when the chip or system is reset, for example, when watchdog time-out or Deep-sleep + +// gpio_force_hold_all(); // This will hold flash/serial too so do not use + + uint16_t real_gpio = GPIO_REL1 << 5; + uint16_t mask = 0xFFE0; + for (uint32_t i = 0; i < nitems(TasmotaGlobal.gpio_pin); i++) { + if ((TasmotaGlobal.gpio_pin[i] & mask) == real_gpio) { + gpio_hold_en((gpio_num_t)i); // Retain the state when the chip or system is reset, for example, when watchdog time-out or Deep-sleep + } + } +} +#endif + +/********************************************************************************************/ + #endif // ESP32 \ No newline at end of file diff --git a/tasmota/tasmota_support/support_tasmota.ino b/tasmota/tasmota_support/support_tasmota.ino index 792c7dc83..6f8c2870a 100644 --- a/tasmota/tasmota_support/support_tasmota.ino +++ b/tasmota/tasmota_support/support_tasmota.ino @@ -1916,24 +1916,6 @@ void TasConsoleInput(void) { /********************************************************************************************/ -#ifdef ESP32 -// Since ESP-IDF 4.4, GPIO matrix or I/O is not reset during a restart -// and GPIO configuration can get stuck because of leftovers -// -// This patched version of pinMode forces a full GPIO reset before setting new mode -// -#include "driver/gpio.h" - -extern "C" void ARDUINO_ISR_ATTR __pinMode(uint8_t pin, uint8_t mode); - -extern "C" void ARDUINO_ISR_ATTR pinMode(uint8_t pin, uint8_t mode) { - gpio_reset_pin((gpio_num_t)pin); - __pinMode(pin, mode); -} -#endif - -/********************************************************************************************/ - void GpioInit(void) { if (!ValidModule(Settings->module)) { diff --git a/tasmota/tasmota_support/support_wifi.ino b/tasmota/tasmota_support/support_wifi.ino index 36527165a..67a291606 100644 --- a/tasmota/tasmota_support/support_wifi.ino +++ b/tasmota/tasmota_support/support_wifi.ino @@ -1149,12 +1149,15 @@ void WifiDisable(void) { TasmotaGlobal.global_state.wifi_down = 1; } -void EspRestart(void) -{ +void EspRestart(void) { ResetPwm(); WifiShutdown(true); CrashDumpClear(); // Clear the stack dump in RTC +#ifdef CONFIG_IDF_TARGET_ESP32C3 + GpioForceHoldRelay(); // Retain the state when the chip or system is reset, for example, when watchdog time-out or Deep-sleep +#endif // CONFIG_IDF_TARGET_ESP32C3 + if (TasmotaGlobal.restart_halt) { // Restart 2 while (1) { OsWatchLoop(); // Feed OsWatch timer to prevent restart