DEV Community

코딩나우(하늘아래)
코딩나우(하늘아래)

Posted on Originally published at coding-now.com

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.

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 press the buttons.

But 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.

For the auto-bootloader circuit most boards use, it only reacts when the two lines differ:

DTR RTS EN IO0 Result
1 1 1 1 Normal run
0 0 1 1 Normal run
1 0 0 1 Held in reset
0 1 1 0 Boot-mode select (IO0 low)

If the two lines don't change at exactly the same instant when the port opens, that brief mismatch is enough to reset the chip. So 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, because the uploader controls them separately.

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
monitor_dtr = 0
monitor_rts = 0
Enter fullscreen mode Exit fullscreen mode

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, recent versions accept --no-reset:

idf.py -p COM5 monitor --no-reset
Enter fullscreen mode Exit fullscreen mode

Python (pyserial)

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

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="")
Enter fullscreen mode Exit fullscreen mode

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.

Stuck on waiting for download

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

rst:0x1 (POWERON_RESET),boot:0x3 (DOWNLOAD_BOOT(UART0/UART1/SDIO_REI_REO_V2))
waiting for download
Enter fullscreen mode Exit fullscreen mode

DOWNLOAD_BOOT means IO0 was low at the moment of reset, so the chip skipped your firmware and is waiting for a new one. That is the last row of the table (DTR 0, RTS 1).

  1. Close the monitor and press EN (RST) once. With the lines released, it boots normally.
  2. Reopen the monitor with RTS off, using the settings above.
  3. If 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, like crash reasons or init logs, the auto-reset is a feature. Keep the defaults, or open the monitor with the lines off and press EN yourself.

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: every upload needs BOOT held while you tap EN.

Quick answers

  • Arduino Uno does this too? Similar idea. DTR reaches the reset pin through a capacitor, so opening the port resets it once. Around 10 µF between RESET and GND prevents it, but remove it before uploading.
  • Won't DTR/RTS off break uploads? No. monitor_dtr / monitor_rts only apply to the monitor.
  • Wrong boot mode detected on upload? The auto-reset failed to enter download mode. Suspect charge-only cables and flaky hubs, or hold BOOT until Connecting... appears.
  • ESP32-S3 / C3 native USB? Same fix. The built-in USB-Serial/JTAG port also resets on DTR/RTS, so the monitor settings above apply. The difference is on the upload side: its reset doesn't re-sample the strapping pins, so if a board stays in download mode after flashing, press EN once or use esptool's --after watchdog-reset.

Longer version with a diagram, plus CNTerminal, a free portable serial terminal from the same site whose DTR toggle opens the port without resetting the board:

Which board or tool has caught you out with this?

Top comments (0)