Preview build — page text is a draft awaiting human review. Code badges come from real compiles. The flasher is real but not yet hardware-tested; the Playground is still a preview.
After upload · ESP32

Fix: ESP32 does nothing after “Hard resetting via RTS pin...”

Upload finished, but the sketch doesn't run until you press EN — or never runs. Check GPIO0/GPIO2/GPIO12, the Serial Monitor baud rate and USB CDC settings.

ESP32ESP32-CAMESP32-C3ESP32-S3NodeMCU ESP8266Updated 3 Nov 2026

Community draft — report a mistake

What you see

OutputOutput
Writing at 0x0003f2a8... (100 %)
Wrote 271904 bytes (151346 compressed) at 0x00010000 in 2.4 seconds (effective 905.8 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...

(Serial Monitor stays empty; the sketch only starts after pressing EN)

“Hard resetting via RTS pin…” is the last line of a successful upload. esptool has written and verified your code and is now asking the USB-serial chip to reset the board so the sketch starts.

If nothing seems to happen, the board either restarted into download mode (strapping pins or a jumper), or it is running but its output is going somewhere you are not looking. The diagnostic sketch below tells the two apart.

Quick fix — try in order

  1. 1

    Press EN/RESET once and watch Serial Monitor

    Set the monitor to 115200. If text appears after pressing EN, the upload is fine and only the automatic reset did not happen.

  2. 2

    Remove the ESP32-CAM IO0 jumper

    If IO0 is still tied to GND, every reset goes straight back into download mode. Remove it, then press RST.

  3. 3

    Free the strapping pins

    GPIO0, GPIO2, GPIO12 and GPIO15 must be at their default levels at reset. A module that pulls GPIO2 high or GPIO12 high can stop a normal boot. The pin checker marks them.

  4. 4

    ESP32-C3/S3: enable USB CDC On Boot

    On native-USB boards your Serial output goes nowhere unless Tools → USB CDC On Boot → Enabled. The sketch is running; you just cannot see it.

  5. 5

    Upload the reset-reason sketch below

    It prints why the chip last reset and a heartbeat every 5 s, so you can tell “not running” from “running but silent”.

Diagnostic sketch

Verified — core esp32 3.3.12, 3 Nov 2026Compile-only
esp32-reset-reason.inoArduino C++Open in PlaygroundOpen in PlaygroundFlash
// FlashReady diagnostic: why did my ESP32 reset?
// Prints the reset reason, chip, flash and PSRAM details once at boot, then a heartbeat
// every 5 s. If the uptime keeps going back to 0, the board is rebooting - and the
// "Reset reason" line tells you which kind of reset it was.
// Works on ESP32, ESP32-C3 and ESP32-S3 (on C3/S3 native USB set Tools -> USB CDC On Boot -> Enabled).
#include <esp_system.h>
#include <esp_flash.h>

const char *reasonText(esp_reset_reason_t r) {
  switch (r) {
    case ESP_RST_POWERON:   return "POWERON - power applied or EN/RST pressed";
    case ESP_RST_EXT:       return "EXT - external reset pin";
    case ESP_RST_SW:        return "SW - ESP.restart() or a library called esp_restart()";
    case ESP_RST_PANIC:     return "PANIC - crash (Guru Meditation); scroll up for the backtrace";
    case ESP_RST_INT_WDT:   return "INT_WDT - interrupt watchdog (an ISR or critical section ran too long)";
    case ESP_RST_TASK_WDT:  return "TASK_WDT - task watchdog (loop() blocked too long)";
    case ESP_RST_WDT:       return "WDT - other watchdog (RTC or timer group)";
    case ESP_RST_DEEPSLEEP: return "DEEPSLEEP - woke from deep sleep";
    case ESP_RST_BROWNOUT:  return "BROWNOUT - supply dipped below ~2.4 V; fix the power";
    case ESP_RST_SDIO:      return "SDIO - reset over SDIO";
    default:                return "other / unknown";
  }
}

void setup() {
  Serial.begin(115200);
  delay(1500);  // give native-USB boards time to enumerate before printing
  esp_reset_reason_t r = esp_reset_reason();
  Serial.println();
  Serial.println("=== FlashReady reset-reason report ===");
  Serial.printf("Reset reason : %d (%s)\n", (int)r, reasonText(r));
  Serial.printf("Chip         : %s rev %d, %d core(s), %lu MHz\n", ESP.getChipModel(), ESP.getChipRevision(),
                ESP.getChipCores(), (unsigned long)ESP.getCpuFreqMHz());

  uint32_t physical = 0;
  esp_flash_get_physical_size(esp_flash_default_chip, &physical);
  uint32_t header = ESP.getFlashChipSize();
  Serial.printf("Flash (chip) : %lu KB\n", (unsigned long)(physical / 1024));
  Serial.printf("Flash (IDE)  : %lu KB at %lu MHz\n", (unsigned long)(header / 1024),
                (unsigned long)(ESP.getFlashChipSpeed() / 1000000));
  if (physical && header > physical) {
    Serial.println("WARNING      : Tools -> Flash Size is larger than the real chip. Lower it.");
  }
  Serial.printf("PSRAM        : %lu KB%s\n", (unsigned long)(ESP.getPsramSize() / 1024),
                ESP.getPsramSize() ? "" : " (none found or PSRAM disabled in Tools)");
  Serial.printf("Sketch       : %lu KB used, %lu KB free in app partition\n",
                (unsigned long)(ESP.getSketchSize() / 1024), (unsigned long)(ESP.getFreeSketchSpace() / 1024));
  Serial.printf("Free heap    : %lu bytes\n", (unsigned long)ESP.getFreeHeap());
  Serial.println("======================================");
}

void loop() {
  static uint32_t last = 0;
  if (millis() - last >= 5000) {
    last = millis();
    Serial.printf("alive, uptime %lu s, free heap %lu\n", (unsigned long)(millis() / 1000),
                  (unsigned long)ESP.getFreeHeap());
  }
}

Why it happens

Why does it need EN pressed?

esptool pulses RTS to reset the chip. On some clone boards the auto-reset transistors and capacitor leave GPIO0 low a little too long, so the chip restarts into download mode instead of your sketch.

Serial Monitor holds it in reset

Some terminals assert DTR/RTS when they open, which holds EN low. Arduino IDE 2's monitor handles this; PuTTY and older tools may not — turn off flow control.

The board really is crashing

If you see a boot message repeating, read it: brownout, Guru Meditation and watchdog resets each have their own page in the list.

Board-specific notes

ESP32-CAM: Most “not running after upload” reports are the IO0 jumper still in place.

NodeMCU ESP8266: The same message appears on ESP8266. If nothing runs, check GPIO15 (D8) is low and GPIO0 (D3)/GPIO2 (D4) are high at reset.

↑↓ to move · Enter to open