#include // ====== CONFIG ====== // Blink timing (change at runtime with: delay ) static uint32_t BLINK_DELAY_MS = 100; // Conservative "test-safe GPIO" set for ESP32-S3 modules. // Excludes pins that commonly serve boot strapping, USB D-/D+, PSRAM/flash, UART0 console, or JTAG, // which can interfere with programming, boot, or board-level functions during quick tests. // // Notes (summarized from the ESP32-S3 module/chip docs): // - 0, 3, 45, 46 are strapping/boot-related or JTAG-related; driving them can change boot modes or disable debug. // - 19, 20 are the on-chip USB D-/D+ differential pair; toggling them breaks USB comms. // - 35, 36, 37 are wired to Octal PSRAM on some variants; not available as GPIO there. // - 43 (U0TXD), 44 (U0RXD) are UART0 console pins used by Serial; poking them disrupts logs/flashing. // - 47, 48 form a differential SPI clock pair; safe as GPIO but mind 1.8 V I/O level on some R16V variants. const uint8_t TEST_SAFE_GPIO[] = { 1, 2, // ADC/Touch-capable, OK for digital use 4, 5, 6, 7, // " 8, 9, 10, 11, 12, 13, 14, // " 15, 16, 17, 18, // " // 19,20 excluded (USB D-/D+) 21, // plain GPIO // 22..34 don't exist on S3 modules // 35,36,37 excluded (PSRAM on some variants) 38, 39, 40, 41, 42, // JTAG-capable if configured, but OK as GPIO when JTAG is not in use // 43,44 excluded (UART0 TX/RX used by Serial) 47, 48 // differential clock pair; OK as GPIO (watch 1.8 V I/O on some R16V variants) }; const size_t TEST_SAFE_GPIO_COUNT = sizeof(TEST_SAFE_GPIO) / sizeof(TEST_SAFE_GPIO[0]); // ====== RUNTIME STATE ====== static int currentPin = -1; static bool blinking = false; // ====== HELPERS ====== bool isTestSafe(int gpio) { for (size_t i = 0; i < TEST_SAFE_GPIO_COUNT; ++i) { if ((int)TEST_SAFE_GPIO[i] == gpio) return true; } return false; } void printTestSafePins() { Serial.println(F("\nTest-safe GPIOs (ESP32-S3):")); for (size_t i = 0; i < TEST_SAFE_GPIO_COUNT; ++i) { Serial.print(F(i ? ", " : " ")); Serial.print(TEST_SAFE_GPIO[i]); } Serial.println(); Serial.println(F("Excluded (reason): 0,3,45,46 (boot/strap/JTAG) | 19,20 (USB D-/D+) | 35-37 (PSRAM on some) | 43,44 (UART0 console)")); } void stopBlink() { if (currentPin >= 0) { digitalWrite(currentPin, LOW); pinMode(currentPin, INPUT); // leave safe } blinking = false; currentPin = -1; Serial.println(F("Stopped. Pin released to INPUT.")); } void startBlink(int gpio) { if (!isTestSafe(gpio)) { Serial.print(F("Restricted: GPIO ")); Serial.print(gpio); Serial.println(F(" is not in the test-safe set.")); return; } if (blinking && currentPin == gpio) { Serial.print(F("Already blinking GPIO ")); Serial.println(gpio); return; } // switch pin if needed if (blinking && currentPin != gpio) stopBlink(); currentPin = gpio; pinMode(currentPin, OUTPUT); digitalWrite(currentPin, LOW); blinking = true; Serial.print(F("Blinking GPIO ")); Serial.print(currentPin); Serial.print(F(" at ")); Serial.print(BLINK_DELAY_MS); Serial.println(F(" ms.")); } // Parse commands like: // list // pin 10 // delay 250 // stop void handleCommand(String line) { line.trim(); if (line.length() == 0) return; line.toLowerCase(); if (line == "list") { printTestSafePins(); return; } if (line == "stop") { stopBlink(); return; } if (line.startsWith("pin ")) { int gpio = line.substring(4).toInt(); startBlink(gpio); return; } if (line.startsWith("delay ")) { int v = line.substring(6).toInt(); if (v < 10) v = 10; // clamp a bit BLINK_DELAY_MS = (uint32_t)v; Serial.print(F("Set blink delay to ")); Serial.print(BLINK_DELAY_MS); Serial.println(F(" ms.")); return; } // Single-number shortcut: just type the GPIO number bool allDigits = true; for (size_t i = 0; i < (size_t)line.length(); ++i) { if (!isDigit(line[i])) { allDigits = false; break; } } if (allDigits) { startBlink(line.toInt()); return; } Serial.println(F("Commands:")); Serial.println(F(" list -> show test-safe GPIOs")); Serial.println(F(" pin -> start blinking that GPIO")); Serial.println(F(" -> same as 'pin '")); Serial.println(F(" delay -> set blink delay")); Serial.println(F(" stop -> stop and release pin")); } void setup() { Serial.begin(115200); // give USB-Serial/JTAG a moment delay(400); Serial.println(F("\nESP32-S3 GPIO Quick Tester")); Serial.println(F("Type 'list' to see test-safe pins, 'pin ' to blink, 'delay ' to change speed, 'stop' to release.\n")); printTestSafePins(); } void loop() { // Process serial line input static String line; while (Serial.available()) { char c = (char)Serial.read(); if (c == '\r') continue; if (c == '\n') { handleCommand(line); line = ""; } else { line += c; } } // Blink the selected pin if (blinking && currentPin >= 0) { digitalWrite(currentPin, HIGH); delay(BLINK_DELAY_MS); digitalWrite(currentPin, LOW); delay(BLINK_DELAY_MS); } else { delay(5); } }