fix detect chiptype

This commit is contained in:
Bob 2025-11-09 20:15:41 -08:00
parent 811ef6829b
commit 1a05445931
1 changed files with 69 additions and 45 deletions

View File

@ -7,40 +7,64 @@ Detects and lists ESP32 devices connected via USB
import serial.tools.list_ports import serial.tools.list_ports
import subprocess import subprocess
import sys import sys
import time
import serial
def detect_chip_type(port): def detect_chip_type(port):
""" """
Try to detect the ESP32 chip type using esptool.py Try to detect the ESP32 chip type using esptool.py
Returns chip type string or 'Unknown' Returns chip type string or 'Unknown'
""" """
# Try to enter ROM bootloader via DTR/RTS before probing
try_enter_bootloader(port)
cmd = ['esptool.py', '--port', port, '--chip', 'auto', '--before', 'default_reset',
'--after', 'no_reset', 'chip_id']
try :
result = subprocess.run(cmd, capture_output=True, text=True, timeout=20)
output = (result.stdout or '') + (result.stderr or '')
if result.returncode != 0:
last = output.strip().splitlines()[-1] if output.strip().splitlines() else 'esptool failed'
print(f" esptool on {port} failed: {last}")
return 'Unknown'
# Prefer exact "Chip is ..." line (e.g., ESP32-D0WD-V3)
for line in output.splitlines():
if line.startswith('Chip is '):
return line.replace('Chip is ', '').split(' (', 1)[0].strip()
# Fallback loose matches
for name in ('ESP32-S3','ESP32-S2','ESP32-C6','ESP32-C3','ESP32-H2','ESP32'):
if name in output:
return name
except FileNotFoundError:
print(" esptool.py not found (pip install esptool)")
except subprocess.TimeoutExpired:
print(f" esptool on {port} timed out (check EN/IO0 wiring)")
except Exception as e:
print(f" Error running esptool on {port}: {e}")
return 'Unknown'
def try_enter_bootloader(port):
"""
Toggle DTR/RTS to enter download mode.
Assumes RTS->EN (active-low) and DTR->IO0 (active-low on many adapters).
Safe no-op if control lines aren't available.
"""
try: try:
result = subprocess.run( with serial.Serial(port, 115200, timeout=0.1) as ser:
['esptool.py', '--port', port, 'chip_id'], ser.rts = True # EN low
capture_output=True, ser.dtr = True # IO0 low
text=True, time.sleep(0.05)
timeout=10 ser.rts = False # EN high
) time.sleep(0.05)
ser.dtr = False # IO0 high
output = result.stdout + result.stderr time.sleep(0.05)
if 'ESP32-S3' in output:
return 'ESP32-S3'
elif 'ESP32-S2' in output:
return 'ESP32-S2'
elif 'ESP32-C3' in output:
return 'ESP32-C3'
elif 'ESP32-C6' in output:
return 'ESP32-C6'
elif 'ESP32-H2' in output:
return 'ESP32-H2'
elif 'ESP32' in output:
return 'ESP32'
except Exception: except Exception:
pass pass
return 'Unknown'
def guess_chip_type_from_usb(vid, pid): def guess_chip_type_from_usb(vid, pid):
@ -53,7 +77,7 @@ def guess_chip_type_from_usb(vid, pid):
return 'ESP32-S3/C3' # Built-in USB, could be either return 'ESP32-S3/C3' # Built-in USB, could be either
elif pid == 0x1002: elif pid == 0x1002:
return 'ESP32-S3/C3' return 'ESP32-S3/C3'
# For CP210x, CH340, etc., we can't tell from USB alone # For CP210x, CH340, etc., we can't tell from USB alone
return None return None
@ -64,7 +88,7 @@ def detect_esp32_devices():
Returns a list of tuples containing (port, description, hwid) Returns a list of tuples containing (port, description, hwid)
""" """
esp32_devices = [] esp32_devices = []
# Common USB vendor IDs used by ESP32 boards # Common USB vendor IDs used by ESP32 boards
ESP32_VID_PIDS = [ ESP32_VID_PIDS = [
('10C4', 'EA60'), # Silicon Labs CP210x ('10C4', 'EA60'), # Silicon Labs CP210x
@ -75,7 +99,7 @@ def detect_esp32_devices():
('303A', '1001'), # Espressif USB JTAG/serial debug unit (ESP32-C3, ESP32-S3) ('303A', '1001'), # Espressif USB JTAG/serial debug unit (ESP32-C3, ESP32-S3)
('303A', '1002'), # Espressif USB JTAG/serial debug unit ('303A', '1002'), # Espressif USB JTAG/serial debug unit
] ]
# Keywords that might appear in ESP32 device descriptions # Keywords that might appear in ESP32 device descriptions
ESP32_KEYWORDS = [ ESP32_KEYWORDS = [
'CP210', 'CP210',
@ -87,56 +111,56 @@ def detect_esp32_devices():
'JTAG', 'JTAG',
'ESP32', 'ESP32',
] ]
# Get all available ports # Get all available ports
ports = serial.tools.list_ports.comports() ports = serial.tools.list_ports.comports()
for port in ports: for port in ports:
# Check by VID:PID # Check by VID:PID
if port.vid is not None and port.pid is not None: if port.vid is not None and port.pid is not None:
vid = f"{port.vid:04X}" vid = f"{port.vid:04X}"
pid = f"{port.pid:04X}" pid = f"{port.pid:04X}"
if any((vid == v and pid == p) for v, p in ESP32_VID_PIDS): if any((vid == v and pid == p) for v, p in ESP32_VID_PIDS):
esp32_devices.append(port) esp32_devices.append(port)
continue continue
# Check by description keywords # Check by description keywords
description_upper = port.description.upper() description_upper = port.description.upper()
if any(keyword in description_upper for keyword in ESP32_KEYWORDS): if any(keyword in description_upper for keyword in ESP32_KEYWORDS):
esp32_devices.append(port) esp32_devices.append(port)
return esp32_devices return esp32_devices
def main(): def main():
import argparse import argparse
parser = argparse.ArgumentParser(description='ESP32 USB Device Detection') parser = argparse.ArgumentParser(description='ESP32 USB Device Detection')
parser.add_argument('--no-probe', action='store_true', parser.add_argument('--no-probe', action='store_true',
help='Skip chip type probing (faster, less accurate)') help='Skip chip type probing (faster, less accurate)')
args = parser.parse_args() args = parser.parse_args()
print("=" * 60) print("=" * 60)
print("ESP32 USB Device Detection") print("ESP32 USB Device Detection")
print("=" * 60) print("=" * 60)
print() print()
# Detect ESP32 devices # Detect ESP32 devices
esp32_devices = detect_esp32_devices() esp32_devices = detect_esp32_devices()
if esp32_devices: if esp32_devices:
print(f"Found {len(esp32_devices)} ESP32 device(s):\n") print(f"Found {len(esp32_devices)} ESP32 device(s):\n")
for idx, device in enumerate(esp32_devices, 1): for idx, device in enumerate(esp32_devices, 1):
print(f"Device {idx}:") print(f"Device {idx}:")
print(f" Port: {device.device}") print(f" Port: {device.device}")
print(f" Description: {device.description}") print(f" Description: {device.description}")
print(f" Hardware ID: {device.hwid}") print(f" Hardware ID: {device.hwid}")
if device.vid is not None and device.pid is not None: if device.vid is not None and device.pid is not None:
print(f" VID:PID: {device.vid:04X}:{device.pid:04X}") print(f" VID:PID: {device.vid:04X}:{device.pid:04X}")
# Chip type detection (probe by default) # Chip type detection (probe by default)
chip_type = None chip_type = None
if not args.no_probe: if not args.no_probe:
@ -151,15 +175,15 @@ def main():
print(f" Chip Guess: {chip_type} (remove --no-probe for exact type)") print(f" Chip Guess: {chip_type} (remove --no-probe for exact type)")
else: else:
print(f" Chip Type: Unknown (remove --no-probe to detect)") print(f" Chip Type: Unknown (remove --no-probe to detect)")
if device.manufacturer: if device.manufacturer:
print(f" Manufacturer: {device.manufacturer}") print(f" Manufacturer: {device.manufacturer}")
if device.serial_number: if device.serial_number:
print(f" Serial: {device.serial_number}") print(f" Serial: {device.serial_number}")
print() print()
print("=" * 60) print("=" * 60)
print(f"Total ESP32 devices detected: {len(esp32_devices)}") print(f"Total ESP32 devices detected: {len(esp32_devices)}")
if args.no_probe: if args.no_probe:
@ -170,7 +194,7 @@ def main():
print() print()
print("Available USB serial devices:") print("Available USB serial devices:")
all_ports = serial.tools.list_ports.comports() all_ports = serial.tools.list_ports.comports()
if all_ports: if all_ports:
for port in all_ports: for port in all_ports:
print(f" - {port.device}: {port.description}") print(f" - {port.device}: {port.description}")