From 5bd981ad4d0d7d5af167706f534ab8552c913bb2 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Sun, 11 Oct 2026 19:51:41 +0200 Subject: [PATCH] fix(touch): hold the GT911 reset line low instead of leaving it floating On the reTerminal E1003, GPIO48 (TOUCH_RES) is the GT911's active-low hardware reset line. Dropping touch_controllers from the device config left it completely untouched, so it floated at whatever level it was last driven. That level is HIGH, meaning the chip stays out of reset and powered, both awake and across deep sleep, since a bare digitalWrite() doesn't survive sleep without a GPIO hold. initTouchInput() now drives the reset pin low for a touch_ic_type == OD_TOUCH_IC_NONE entry instead of skipping it. The new touchPrepareForDeepSleep() latches the reset/enable pin(s) with gpio_hold_en()/gpio_deep_sleep_hold_en() before esp_deep_sleep_start() so the level survives sleep. This also closes the same gap for an actively used touchscreen. It is now held in reset for the sleep window too. --- src/main.cpp | 1 + src/touch_input.cpp | 79 +++++++++++++++++++++++++++++++++++++++++++-- src/touch_input.h | 10 ++++++ 3 files changed, 88 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index d1b6194..81067d5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1243,6 +1243,7 @@ void enterDeepSleep(bool force, uint16_t overrideSleepSeconds) { od_log_flush(); // drain UART/Serial prior to deep sleep delay(100); // Brief delay to ensure serial output is sent powerLatchHoldForSleep(); + touchPrepareForDeepSleep(); esp_deep_sleep_start(); } #endif diff --git a/src/touch_input.cpp b/src/touch_input.cpp index 530b1b7..6be6799 100644 --- a/src/touch_input.cpp +++ b/src/touch_input.cpp @@ -7,6 +7,7 @@ #include #if defined(TARGET_ESP32) +#include "driver/gpio.h" #define TOUCH_ISR_ATTR IRAM_ATTR #else #define TOUCH_ISR_ATTR @@ -306,6 +307,60 @@ static void touch_apply_enable_pin(const TouchController* tc) { digitalWrite(tc->enable_pin, HIGH); } +// A board's touch rail/reset line stays wherever it was last driven across a +// pinMode/digitalWrite-only boundary. Deep sleep is no exception: bare +// digitalWrite() is silently discarded at sleep entry on ESP32-S3, so the +// level must be latched with gpio_hold_en()/gpio_deep_sleep_hold_en(). Without +// the hold, a GT911 reset line left floating reads HIGH (out of reset, chip +// powered) even though nothing ever drove it there on purpose. +#if defined(TARGET_ESP32) +// pin's only "don't touch" sentinel is 0xFF: rst_pin treats GPIO0 as a valid +// reset pin, so callers resolve the enable_pin "0 or 0xFF = unused" sentinel +// themselves before calling in. +static inline void touch_pad_hold_disable(uint8_t pin) { + if (pin == 0xFF) { + return; + } + gpio_hold_dis((gpio_num_t)pin); +} +static inline void touch_pad_hold(uint8_t pin) { + if (pin == 0xFF) { + return; + } +// The ESP32-C6 does not support or need the global hold function, same as +// padHold() in power_latch.cpp. +#if !defined(CONFIG_IDF_TARGET_ESP32C6) + gpio_deep_sleep_hold_en(); +#endif + gpio_hold_en((gpio_num_t)pin); +} +#else +static inline void touch_pad_hold_disable(uint8_t) {} +static inline void touch_pad_hold(uint8_t) {} +#endif + +// Assert and latch the touch IC's reset/enable lines at their off level so a +// board whose touch is force-disabled (touch_ic_type == OD_TOUCH_IC_NONE but +// rst_pin/enable_pin configured) does not leave the chip powered on nothing +// more than a floating GPIO, and so an actively-used GT911 is also taken down +// (not left mid-session) for the sleep window. Call right before +// esp_deep_sleep_start(). +void touchPrepareForDeepSleep(void) { + for (uint8_t i = 0; i < globalConfig.touch_controller_count; i++) { + const TouchController* tc = &globalConfig.touch_controllers[i]; + if (tc->rst_pin != 0xFF) { + pinMode(tc->rst_pin, OUTPUT); + digitalWrite(tc->rst_pin, LOW); // GT911 RST is active-low + touch_pad_hold(tc->rst_pin); + } + if (tc->enable_pin != 0 && tc->enable_pin != 0xFF) { + pinMode(tc->enable_pin, OUTPUT); + digitalWrite(tc->enable_pin, LOW); + touch_pad_hold(tc->enable_pin); + } + } +} + static uint8_t gt911_resolve_and_init(const TouchController* t, TouchRuntime* rt) { const uint8_t a5d = 0x5D; const uint8_t a14 = 0x14; @@ -490,9 +545,29 @@ void initTouchInput(void) { } uint8_t enabled = 0; for (uint8_t j = 0; j < globalConfig.touch_controller_count; j++) { - if (globalConfig.touch_controllers[j].touch_ic_type != OD_TOUCH_IC_NONE) { - enabled++; + const TouchController* tc = &globalConfig.touch_controllers[j]; + // A reset/enable line held across the prior deep sleep ignores + // digitalWrite() until the hold is released. + touch_pad_hold_disable(tc->rst_pin); + if (tc->enable_pin != 0) { + touch_pad_hold_disable(tc->enable_pin); + } + if (tc->touch_ic_type == OD_TOUCH_IC_NONE) { + // Force-disabled: hold the IC in hardware reset instead of + // leaving its reset line floating. On this board's GT911, RST is + // active-low, so floating reads HIGH (out of reset, chip + // powered) even though nothing drove it there on purpose. + if (tc->rst_pin != 0xFF) { + pinMode(tc->rst_pin, OUTPUT); + digitalWrite(tc->rst_pin, LOW); + } + if (tc->enable_pin != 0 && tc->enable_pin != 0xFF) { + pinMode(tc->enable_pin, OUTPUT); + digitalWrite(tc->enable_pin, LOW); + } + continue; } + enabled++; } if (enabled == 0) { return; diff --git a/src/touch_input.h b/src/touch_input.h index 2dd1489..7c7e9af 100644 --- a/src/touch_input.h +++ b/src/touch_input.h @@ -21,4 +21,14 @@ void touchResumeAfterEpdRefresh(void); */ void touchForceResume(void); +/** + * Assert and latch the configured reset/enable line(s) at their off level + * (gpio_hold_en + gpio_deep_sleep_hold_en) so touch stays powered down + * through deep sleep instead of floating back to its idle level. Covers + * both an actively-used controller (taken down for the sleep window) and + * one force-disabled via touch_ic_type == OD_TOUCH_IC_NONE. Call right + * before esp_deep_sleep_start(). + */ +void touchPrepareForDeepSleep(void); + #endif