Fix trackball dead after USB web flash

After ESP32-S3 USB download mode, GPIO peripheral state may persist
across soft reset. The trackball interrupts silently fail because
pins are in an unknown state from the bootloader.

Fix: call gpio_reset_pin() and detachInterrupt() before configuring
the trackball GPIOs, ensuring a clean state regardless of how the
device was reset (power cycle, RTS toggle, or software reset).
This commit is contained in:
DeFiDude
2026-03-06 15:43:13 -07:00
parent 03d51d5c52
commit 5d038aec9e
+19 -1
View File
@@ -1,4 +1,5 @@
#include "Trackball.h"
#include <driver/gpio.h>
volatile int8_t Trackball::_deltaX = 0;
volatile int8_t Trackball::_deltaY = 0;
@@ -8,6 +9,20 @@ Trackball* Trackball::_instance = nullptr;
bool Trackball::begin() {
_instance = this;
// Detach any stale interrupts (GPIO state may persist after USB download mode reset)
detachInterrupt(digitalPinToInterrupt(TBALL_UP));
detachInterrupt(digitalPinToInterrupt(TBALL_DOWN));
detachInterrupt(digitalPinToInterrupt(TBALL_LEFT));
detachInterrupt(digitalPinToInterrupt(TBALL_RIGHT));
detachInterrupt(digitalPinToInterrupt(TBALL_CLICK));
// Reset pins to a known state before configuring
gpio_reset_pin((gpio_num_t)TBALL_UP);
gpio_reset_pin((gpio_num_t)TBALL_DOWN);
gpio_reset_pin((gpio_num_t)TBALL_LEFT);
gpio_reset_pin((gpio_num_t)TBALL_RIGHT);
gpio_reset_pin((gpio_num_t)TBALL_CLICK);
// Configure trackball GPIOs as inputs with pullup
pinMode(TBALL_UP, INPUT_PULLUP);
pinMode(TBALL_DOWN, INPUT_PULLUP);
@@ -15,6 +30,9 @@ bool Trackball::begin() {
pinMode(TBALL_RIGHT, INPUT_PULLUP);
pinMode(TBALL_CLICK, INPUT_PULLUP);
// Small delay to let pullups stabilize
delay(5);
// Attach interrupts for movement detection
attachInterrupt(digitalPinToInterrupt(TBALL_UP), isrUp, FALLING);
attachInterrupt(digitalPinToInterrupt(TBALL_DOWN), isrRight, FALLING); // Physical down pin = rightward
@@ -22,7 +40,7 @@ bool Trackball::begin() {
attachInterrupt(digitalPinToInterrupt(TBALL_RIGHT), isrDown, FALLING); // Physical right pin = downward
attachInterrupt(digitalPinToInterrupt(TBALL_CLICK), isrClick, FALLING);
Serial.println("[TRACKBALL] Initialized");
Serial.println("[TRACKBALL] Initialized (GPIO reset + interrupts attached)");
return true;
}