← All posts
EmbeddedPublished · 8 min readAlso on dev.to

Why your ESP32 resets every time you open the serial monitor (and how to stop it)

You flash the firmware, open a serial monitor to see what it is doing — and the board reboots, wiping out exactly the state you wanted to look at. Nothing is broken. The auto-reset circuit that makes uploading convenient reacts to the monitor in exactly the same way. Once you see how it works the fix is a line or two, and every tool has its own switch for it.

Free tool featured in this guide
CNTerminal — free portable serial terminal

Its DTR toggle lets you open the port without resetting the ESP32. A single 8 MB executable, no install.

Free download

Why opening the port resets the board

ESP32 dev boards (DevKitC and friends) carry a USB-to-serial chip such as a CP2102 or CH340. Its DTR and RTS pins drive EN (reset) and IO0 (boot mode) through two transistors. Upload tools use those lines to put the chip into download mode and reset it automatically, which is why you rarely need to press the buttons.

The catch is that upload tools are not the only software touching those lines. Most terminal programs and drivers raise or drop DTR/RTS when they open a port. The circuit cannot tell an upload from a monitor, so it resets the chip either way.

Opening the port becomes the same as pressing reset. Leave the lines alone and you see the board exactly as it was running.

The circuit only reacts when the two lines differ. For the auto-bootloader circuit most boards use, the states work out like this:

DTRRTSENIO0Result
1111Normal run
0011Normal run
1001Held in reset
0110Boot-mode select (IO0 low)
ℹ️

If the two lines don't change at exactly the same instant when the port opens, the brief mismatch is enough to reset the chip. That is why the fix is to not touch either line at all. Board vendors vary the circuit slightly, so details can differ.

Fixes by tool

PlatformIO

Two lines in platformio.ini stop the monitor from driving the lines. Uploads are unaffected — the uploader controls them separately.

ini
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
monitor_dtr = 0
monitor_rts = 0

ESP-IDF

idf.py monitor deliberately resets the board on start so you see the boot log. To attach to a board that is already running without resetting it, recent versions accept --no-reset.

bash
idf.py -p COM5 monitor --no-reset

Python pyserial

Turning the lines off after opening is too late. Create the port object first, set the line states, then call open().

python
import serial

ser = serial.Serial()        # not opened yet
ser.port = "COM5"
ser.baudrate = 115200
ser.dtr = False              # decide before opening
ser.rts = False
ser.open()

while True:
    line = ser.readline()
    if line:
        print(line.decode(errors="replace"), end="")

Arduino IDE

The Arduino IDE serial monitor generally has no option to leave these lines alone. If you need to watch without a reset, PlatformIO or a terminal with a DTR control is the quicker route.

A dedicated serial terminal

Any terminal that can open the port with DTR off solves it. In CNTerminal, open the port with the DTR toggle off and the ESP32 keeps running, so you pick up the log where it is.

Stuck on 'waiting for download'

Sometimes opening the monitor shows only this, and your program never starts:

text
rst:0x1 (POWERON_RESET),boot:0x3 (DOWNLOAD_BOOT(UART0/UART1/SDIO_REI_REO_V2))
waiting for download

DOWNLOAD_BOOT means IO0 was low at the moment of reset. The chip skips your firmware and waits for a new one — the fourth row of the table above (DTR 0, RTS 1).

  1. 1Close the monitor and press the board's EN (RST) button once. With the lines released, it boots normally.
  2. 2Reopen the monitor with RTS off using the settings above.
  3. 3If you wired buttons or sensors to GPIO0, check that nothing holds it low during boot.

Sometimes you want the reset

If you are after the messages printed right at boot — crash reasons, init logs — the auto-reset is a feature. Keep the defaults, or open the monitor with the lines off and press EN yourself. Switch it per situation.

⚠️

Cutting the board's auto-reset traces, or using a USB-serial adapter wired for TX, RX and GND only, removes monitor resets entirely. The price is that every upload needs BOOT held while you tap EN to enter download mode by hand.

FAQ

Q. My Arduino Uno also resets when I open the monitor — same thing?

Similar. On the Uno, DTR reaches the reset pin through a capacitor, so opening the port resets the board once — by design, for uploads. A capacitor of around 10 µF between RESET and GND prevents it, but it must be removed before uploading.

Q. Won't turning DTR/RTS off break uploading?

No. You are only changing monitor settings. PlatformIO's monitor_dtr and monitor_rts apply to the monitor; the uploader drives the lines itself.

Q. Uploads fail with 'Wrong boot mode detected'.

The auto-reset did not get the chip into download mode. Charge-only USB cables, flaky hubs and a faulty auto-reset circuit are the usual causes. Hold BOOT as the upload starts and release it once 'Connecting...' appears.

Q. Does this apply to ESP32-S3 or C3 boards with native USB?

Yes. The built-in USB-Serial/JTAG port also resets on DTR/RTS, so the monitor settings in this guide apply there too. The difference is on the upload side: its reset is a core reset that doesn't re-sample the strapping pins, so if the board stays in download mode after flashing, press EN once or use esptool's --after watchdog-reset.

Free tool featured in this guide
CNTerminal — free portable serial terminal

Its DTR toggle lets you open the port without resetting the ESP32. A single 8 MB executable, no install.

Free download

More posts