mirror of
https://github.com/micropython/micropython.git
synced 2026-01-09 13:40:31 +01:00
tools/mpremote: Workaround ESP DTR/RTS reset quirk at disconnect time.
The problem with ESP board spurious reset happens at disconnect time on Windows (clearing DTR before RTS triggers a reset). Previous workarounds tried to detect possible ESP boards and apply the correct DTR and RTS settings when opening the port. Instead, we can manually clear RTS before closing the port and thereby avoid the reset issue. Opening the port can keep the default behaviour (RTS & DTR both set). close() is called from a finally block in the mpremote main module (via do_disconnect()) - so this should always happen provided the Python process isn't terminated by the OS. One additional workaround is needed to prevent a spurious reset first time a Silicon Labs CP210x-based ESP board is opened by mpremote after enumeration. Signed-off-by: Angus Gratton <angus@redyak.com.au>
This commit is contained in:
committed by
Damien George
parent
a563592b11
commit
3dd8073c29
@@ -42,31 +42,8 @@ from errno import EPERM
|
||||
from .console import VT_ENABLED
|
||||
from .transport import TransportError, TransportExecError, Transport
|
||||
|
||||
VID_ESPRESSIF = 0x303A # Espressif Incorporated
|
||||
PID_ESPRESSIF_SERIAL_JTAG = 0x1001 # Serial/JTAG peripheral of ESP32-S3,C3,C6
|
||||
|
||||
|
||||
def has_espressif_dtr_quirk(devicename):
|
||||
"""ESP8266 and ESP32 dev boards use the DTR and RTS lines to trigger reset &
|
||||
reset into bootloader mode. This can causes spurious reset issues on Windows.
|
||||
|
||||
Apply the quirk to any USB/Serial chip on Windows that isn't using the
|
||||
Microsoft CDC-ACM driver, or to the integrated Espressif Serial/JTAG device.
|
||||
|
||||
Don't apply it to Espressif boards running TinyUSB, as TinyUSB uses DTR
|
||||
to determine if the CDC port is open (and there's no spurious reset issue).
|
||||
"""
|
||||
portinfo = list(serial.tools.list_ports.grep(devicename)) # type: ignore
|
||||
if not portinfo:
|
||||
return False
|
||||
|
||||
def port_attr(name):
|
||||
return getattr(portinfo[0], name, None)
|
||||
|
||||
return (port_attr("vid"), port_attr("pid")) == (
|
||||
VID_ESPRESSIF,
|
||||
PID_ESPRESSIF_SERIAL_JTAG,
|
||||
) or port_attr("manufacturer") != "Microsoft"
|
||||
VID_SILICON_LABS = 0x10C4
|
||||
|
||||
|
||||
class SerialTransport(Transport):
|
||||
@@ -90,19 +67,27 @@ class SerialTransport(Transport):
|
||||
delayed = False
|
||||
for attempt in range(wait + 1):
|
||||
try:
|
||||
if device.startswith("rfc2217://"):
|
||||
self.serial = serial.serial_for_url(device, **serial_kwargs)
|
||||
elif os.name == "nt":
|
||||
self.serial = serial.Serial(**serial_kwargs)
|
||||
self.serial.port = device
|
||||
if has_espressif_dtr_quirk(device):
|
||||
# DTR False: to avoid using the reset button will hang the MCU in bootloader mode
|
||||
# RTS False: to prevent pulses on rts on serial.close() that would POWERON_RESET an ESPxx
|
||||
self.serial.dtr = False # DTR False = gpio0 High = Normal boot
|
||||
self.serial.rts = False # RTS False = EN High = MCU enabled
|
||||
self.serial = serial.serial_for_url(device, do_not_open=True, **serial_kwargs)
|
||||
if os.name == "nt":
|
||||
portinfo = list(serial.tools.list_ports.grep(device)) # type: ignore
|
||||
if portinfo and getattr(portinfo[0], "vid", None) == VID_SILICON_LABS:
|
||||
# Silicon Labs CP210x driver on Windows has a quirk
|
||||
# where after a power on reset it will set DTR and RTS
|
||||
# at different times when the port is opened (it doesn't
|
||||
# happen on subsequent openings).
|
||||
#
|
||||
# To avoid issues with spurious reset on Espressif boards we clear DTR and RTS,
|
||||
# open the port, and then set them in an order which prevents triggering a reset.
|
||||
self.serial.dtr = False
|
||||
self.serial.rts = False
|
||||
self.serial.open()
|
||||
self.serial.dtr = True
|
||||
self.serial.rts = True
|
||||
|
||||
# On all other host/driver combinations we keep the default
|
||||
# behaviour (pyserial will set DTR and RTS automatically on open)
|
||||
if not self.serial.isOpen():
|
||||
self.serial.open()
|
||||
else:
|
||||
self.serial = serial.Serial(device, **serial_kwargs)
|
||||
break
|
||||
except OSError:
|
||||
if wait == 0:
|
||||
@@ -121,6 +106,9 @@ class SerialTransport(Transport):
|
||||
print("")
|
||||
|
||||
def close(self):
|
||||
# ESP Windows quirk: Prevent target from resetting when Windows clears DTR before RTS
|
||||
self.serial.rts = False
|
||||
self.serial.dtr = False
|
||||
self.serial.close()
|
||||
|
||||
def read_until(
|
||||
|
||||
Reference in New Issue
Block a user