← 블로그 목록
임베디드작성 · 8분 읽기dev.to 영문판

ESP32가 시리얼 모니터를 열 때마다 리셋되는 이유와 해결

펌웨어를 올리고 동작을 확인하려고 시리얼 모니터를 여는 순간 보드가 재부팅되면서, 보고 싶던 상태가 사라집니다. 고장이 아닙니다. 업로드를 편하게 하려고 보드에 넣어 둔 자동 리셋 회로가 모니터에도 똑같이 반응하는 것입니다. 원리를 알면 해결은 한두 줄이고, 쓰는 도구마다 끄는 방법이 정해져 있습니다.

이 글에서 소개하는 무료 도구
CNTerminal — 무료 포터블 시리얼 터미널

DTR 토글로 포트를 열어도 ESP32 가 리셋되지 않게 할 수 있습니다. 설치 없는 8MB 단일 실행 파일.

무료 다운로드

왜 포트를 열기만 해도 리셋될까

ESP32 개발보드(DevKitC 등)에는 USB-시리얼 변환 칩(CP2102, CH340 등)이 있고, 이 칩의 DTR·RTS 핀이 트랜지스터 두 개를 거쳐 ESP32 의 EN(리셋)과 IO0(부팅 모드)에 연결돼 있습니다. 업로드 도구가 이 두 신호로 '다운로드 모드 진입 → 리셋'을 자동으로 해 주기 때문에, 버튼을 누르지 않아도 펌웨어가 올라가는 것입니다.

문제는 업로드 도구만 이 신호를 쓰는 게 아니라는 점입니다. 대부분의 터미널 프로그램과 드라이버는 포트를 열 때 DTR·RTS 를 켜거나 끕니다. 회로는 그 신호가 업로드용인지 모니터용인지 구분하지 못하므로, 똑같이 리셋을 겁니다.

포트를 여는 동작 자체가 리셋 버튼을 누르는 것과 같아집니다. 신호를 건드리지 않게 하면 실행 중인 상태를 그대로 볼 수 있습니다.

회로는 두 신호가 서로 다를 때만 반응하도록 짜여 있습니다. 업로드 도구가 널리 쓰는 자동 부트로더 회로 기준으로 정리하면 다음과 같습니다.

DTRRTSENIO0결과
1111정상 실행
0011정상 실행
1001리셋이 걸린 상태
0110부팅 모드 선택 (IO0 LOW)
ℹ️

포트를 여는 순간 두 신호가 정확히 동시에 바뀌지 않고 잠깐이라도 값이 엇갈리면 그 사이에 리셋이 걸립니다. 그래서 해결의 핵심은 '두 신호를 아예 건드리지 않는 것'입니다. 보드 제조사마다 회로가 조금씩 달라 반응이 다를 수 있습니다.

도구별 해결법

PlatformIO

platformio.ini 에 두 줄을 추가하면 모니터가 포트를 열 때 신호를 내리지 않습니다. 업로드에는 영향이 없습니다 — 업로드는 별도로 신호를 제어합니다.

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

ESP-IDF

idf.py monitor 는 부팅 로그부터 보여 주려고 시작할 때 일부러 보드를 리셋합니다. 이미 돌고 있는 보드에 리셋 없이 붙으려면 최근 버전에서 --no-reset 옵션을 씁니다.

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

파이썬 pyserial

포트를 연 뒤에 신호를 끄면 이미 늦습니다. 포트 객체를 먼저 만들고, 신호 값을 정한 다음에 open() 해야 합니다.

python
import serial

ser = serial.Serial()        # 아직 열지 않음
ser.port = "COM5"
ser.baudrate = 115200
ser.dtr = False              # 열기 전에 정한다
ser.rts = False
ser.open()

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

Arduino IDE

Arduino IDE 의 시리얼 모니터에는 보통 이 신호를 끄는 옵션이 없습니다. 리셋 없이 보고 싶다면 위의 PlatformIO 나 DTR 을 직접 끌 수 있는 터미널 프로그램을 쓰는 편이 빠릅니다.

전용 시리얼 터미널

DTR 을 끄고 연결하는 옵션이 있는 터미널이라면 그걸로 끝납니다. CNTerminal 은 화면의 DTR 토글을 끈 상태로 포트를 열면 ESP32 가 리셋되지 않아, 이미 돌고 있는 보드의 로그를 그대로 이어 볼 수 있습니다.

'waiting for download' 에서 멈췄을 때

모니터를 열었더니 아래 메시지만 나오고 프로그램이 시작되지 않는 경우가 있습니다.

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

DOWNLOAD_BOOT 는 리셋 순간 IO0 가 LOW 였다는 뜻입니다. 칩은 펌웨어를 실행하지 않고 새 펌웨어를 받을 준비만 한 채 기다립니다. 표의 네 번째 줄(DTR 0, RTS 1) 상태로 리셋이 풀린 경우입니다.

  1. 1모니터를 닫고 보드의 EN(RST) 버튼을 한 번 누릅니다. 신호가 풀린 상태에서 리셋되므로 정상 실행됩니다.
  2. 2위 도구별 설정으로 RTS 를 끈 채 모니터를 엽니다.
  3. 3GPIO0 에 버튼·센서 같은 외부 회로를 연결했다면, 부팅 순간 LOW 로 잡히지 않는지 확인합니다.

반대로 리셋이 필요할 때도 있습니다

부팅 직후 출력되는 로그(크래시 원인, 초기화 메시지)를 보고 싶다면 자동 리셋은 오히려 편한 기능입니다. 그럴 때는 설정을 기본값으로 두거나, 신호를 끈 채 모니터를 연 다음 EN 버튼을 직접 한 번 누르면 됩니다. 상황에 따라 켜고 끄는 것이 정답입니다.

⚠️

보드의 자동 리셋 배선을 끊거나, TX·RX·GND 만 연결된 USB-시리얼 어댑터를 쓰면 모니터로 인한 리셋은 완전히 사라집니다. 다만 업로드할 때마다 BOOT 버튼을 누른 채 EN 을 눌러 다운로드 모드로 직접 들어가야 합니다.

자주 묻는 질문

Q. 아두이노 우노도 시리얼 모니터를 열면 리셋되던데 같은 원리인가요?

비슷합니다. 우노는 DTR 신호가 콘덴서를 거쳐 리셋 핀에 연결돼 있어, 포트를 열 때 한 번 리셋됩니다. 업로드를 위한 설계입니다. 막으려면 RESET 과 GND 사이에 10µF 정도의 콘덴서를 달면 되지만, 업로드할 때는 반드시 떼야 합니다.

Q. DTR·RTS 를 끄면 업로드가 안 되지 않나요?

모니터 설정만 바꾸는 것이라 업로드에는 영향이 없습니다. PlatformIO 의 monitor_dtr·monitor_rts 는 모니터에만 적용되고, 업로드는 도구가 신호를 따로 제어합니다.

Q. 업로드할 때 'Wrong boot mode detected' 오류가 납니다.

자동 리셋이 다운로드 모드로 넘어가지 못한 경우입니다. 충전 전용 USB 케이블, 불안정한 USB 허브, 보드의 자동 리셋 회로 불량이 흔한 원인입니다. 우선 BOOT 버튼을 누른 채로 업로드를 시작하고 'Connecting...' 이 보이면 손을 떼 보세요.

Q. ESP32-S3·C3 처럼 USB 가 칩에 내장된 보드도 같나요?

네, 같습니다. 칩 내장 USB(USB-Serial/JTAG) 포트도 DTR·RTS 신호에 반응해 리셋되므로, 이 글의 모니터 설정(DTR·RTS 끄기)이 그대로 적용됩니다. 차이는 업로드 쪽에 있습니다. 이 방식의 리셋은 부팅 모드 핀을 다시 읽지 않는 코어 리셋이라, 업로드 후에도 다운로드 모드에 머물러 있으면 EN 버튼을 한 번 누르거나 esptool 의 --after watchdog-reset 옵션을 쓰세요.

이 글에서 소개하는 무료 도구
CNTerminal — 무료 포터블 시리얼 터미널

DTR 토글로 포트를 열어도 ESP32 가 리셋되지 않게 할 수 있습니다. 설치 없는 8MB 단일 실행 파일.

무료 다운로드

다른 글