From 8ad054f3af4ceb229ec410753d213ced7a07d9ad Mon Sep 17 00:00:00 2001 From: ainyan03 <205502311+ainyan03@users.noreply.github.com> Date: Tue, 13 Oct 2026 02:45:06 +0000 Subject: [PATCH] Fix pin_backup_t missing the input routing of a pin backup() looks for the input signal routed from a pin by reading the input selector of the pin's output signal. It compared that selector with the signal number, but the selector holds the GPIO number routed to the signal, so the match only happened when the two numbers were equal by chance, and restore() left the input routing as the borrower had set it. - Compare the selector with the pin number, and only while SIG_IN_SEL is set. With SIG_IN_SEL clear the signal bypasses the GPIO matrix and the selector is a stale value that does not belong to this pin. - restore() now writes the saved input selector back. Do it after the IO MUX, GPIO_PIN and output selector registers are restored, so the input is not reconnected to a pad still configured by the borrower. - matches_current() compares the input selector too, so a pin whose input routing was changed while borrowed is reported as changed. --- src/lgfx/v1/platforms/esp32/common.inl | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/lgfx/v1/platforms/esp32/common.inl b/src/lgfx/v1/platforms/esp32/common.inl index 00105fb5..50e26d20 100644 --- a/src/lgfx/v1/platforms/esp32/common.inl +++ b/src/lgfx/v1/platforms/esp32/common.inl @@ -709,13 +709,19 @@ namespace lgfx _in_func_num = -1; size_t func_num = ((_gpio_func_out_reg >> GPIO_FUNC0_OUT_SEL_S) & GPIO_FUNC0_OUT_SEL_V); + // The input selector of a signal holds the GPIO number routed to it, + // not a signal number, so the pin is matched against the pin number. + // A selector only counts while the signal goes through the GPIO matrix; + // otherwise it is a stale value and the signal belongs to no pin here. if (func_num < sizeof(GPIO.func_in_sel_cfg) / sizeof(GPIO.func_in_sel_cfg[0])) { #if defined ( GPIO_FUNC0_IN_SEL_CFG_REG ) _gpio_func_in_reg = *reinterpret_cast(GPIO_FUNC0_IN_SEL_CFG_REG + (func_num * 4)); - bool hit = func_num == ((_gpio_func_in_reg >> GPIO_FUNC0_IN_SEL_S) & GPIO_FUNC0_IN_SEL_V); + bool hit = (_gpio_func_in_reg & GPIO_SIG0_IN_SEL) + && pin_num == ((_gpio_func_in_reg >> GPIO_FUNC0_IN_SEL_S) & GPIO_FUNC0_IN_SEL_V); #else _gpio_func_in_reg = *reinterpret_cast(GPIO_FUNC1_IN_SEL_CFG_REG + ((func_num - 1) * 4)); - bool hit = func_num == ((_gpio_func_in_reg >> GPIO_FUNC1_IN_SEL_S) & GPIO_FUNC1_IN_SEL_V); + bool hit = (_gpio_func_in_reg & GPIO_SIG1_IN_SEL) + && pin_num == ((_gpio_func_in_reg >> GPIO_FUNC1_IN_SEL_S) & GPIO_FUNC1_IN_SEL_V); #endif if (hit) { _in_func_num = func_num; @@ -761,11 +767,6 @@ namespace lgfx *gpio_enable_w1tc = pin_mask; *(_gpio_out ? get_gpio_hi_reg(_pin_num) : get_gpio_lo_reg(_pin_num)) = pin_mask; - if ((uint16_t)_in_func_num < 256) { - GPIO.func_in_sel_cfg[_in_func_num].val = _gpio_func_in_reg; - // ESP_LOGD("DEBUG","pin:%d in_func_num:%d", (int)pin_num, (int)_in_func_num); - } - // ESP_LOGD("DEBUG","restore pin:%d ", pin_num); // ESP_LOGD("DEBUG","restore IO_MUX_GPIO0_REG :%08x -> %08x ", *reinterpret_cast(GPIO_PIN_MUX_REG[pin_num] ), _io_mux_gpio_reg ); // ESP_LOGD("DEBUG","restore GPIO_PIN0_REG :%08x -> %08x ", *reinterpret_cast(GPIO_PIN0_REG + (pin_num * 4)), _gpio_pin_reg ); @@ -774,6 +775,13 @@ namespace lgfx *reinterpret_cast(GPIO_PIN0_REG + (pin_num * 4)) = _gpio_pin_reg; *reinterpret_cast(GPIO_FUNC0_OUT_SEL_CFG_REG + (pin_num * 4)) = _gpio_func_out_reg; + // Route the input back only after the pad configuration, so it is not + // reconnected to a pad still set up by the borrower (e.g. with its input + // buffer disabled). + if ((uint16_t)_in_func_num < 256) { + GPIO.func_in_sel_cfg[_in_func_num].val = _gpio_func_in_reg; + } + // The pin drives again only once it is configured and holding the level // it held before. Set and clear go through their own registers so a pin // being restored on another core is not caught in a read-modify-write.