Improve lilygo_t_display_s3 board detection

This commit is contained in:
Thomas Farstrike
2026-03-22 22:19:02 +01:00
parent 63d268950f
commit 1ca30efac8
2 changed files with 177 additions and 23 deletions
@@ -0,0 +1,139 @@
import sys
import time
import machine
def _adc_read(adc):
if hasattr(adc, "read_u16"):
return adc.read_u16()
return adc.read()
def _pin_snapshot(pin_id):
pin = machine.Pin(pin_id)
snapshot = {"pin": pin, "mode": None, "pull": None, "value": None}
for attr in ("mode", "pull"):
getter = getattr(pin, attr, None)
if callable(getter):
try:
snapshot[attr] = getter()
except Exception:
pass
try:
snapshot["value"] = pin.value()
except Exception:
pass
return snapshot
def _try_pin_snapshot(pin_id):
try:
return _pin_snapshot(pin_id), None
except Exception as exc:
return None, exc
def _restore_pin(snapshot):
pin = snapshot["pin"]
mode = snapshot.get("mode")
pull = snapshot.get("pull")
value = snapshot.get("value")
try:
if hasattr(pin, "init"):
kwargs = {}
if mode is not None:
kwargs["mode"] = mode
if pull is not None:
kwargs["pull"] = pull
if value is not None and mode in (machine.Pin.OUT, getattr(machine.Pin, "OPEN_DRAIN", None)):
kwargs["value"] = value
if kwargs:
pin.init(**kwargs)
return
if value is not None and mode in (machine.Pin.OUT, getattr(machine.Pin, "OPEN_DRAIN", None)):
pin.value(value)
except Exception as exc:
print("pinstates: WARNING: failed to restore GPIO%02d: %r" % (pin.id(), exc))
def _detect_board():
impl = [repr(sys.implementation)]
impl.append(getattr(sys.implementation, "_machine", ""))
impl.append(getattr(sys.implementation, "machine", ""))
haystack = " ".join(impl).upper()
if "ESP32S3" in haystack:
return "esp32s3"
return "esp32"
def _candidate_pins(board, skiplist=None):
extra_skip = set(skiplist or [])
if board in ("esp32", "esp32-wroom", "esp32-wrover"):
skip = {6, 7, 8, 9, 10, 11, 20, 24, 28, 29, 30, 31}
return [p for p in range(0, 40) if p not in skip and p not in extra_skip]
if board in ("esp32s3", "esp32-s3"):
skip = {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 45, 46}
return [p for p in range(0, 49) if p not in skip and p not in extra_skip]
raise ValueError("Unsupported board type: %r" % board)
def read_all_pins(skiplist=None):
board = _detect_board()
pins = _candidate_pins(board, skiplist=skiplist)
results = {"digital": {}, "analog": {}, "errors": {"digital": {}, "analog": {}}}
for p in pins:
pin_snapshot, snapshot_error = _try_pin_snapshot(p)
if snapshot_error is not None:
results["errors"]["digital"][p] = repr(snapshot_error)
continue
try:
print("Reading digital GPIO%02d..." % p)
pin = machine.Pin(p, machine.Pin.IN)
results["digital"][p] = pin.value()
#time.sleep(1)
except Exception as exc:
results["errors"]["digital"][p] = repr(exc)
finally:
try:
_restore_pin(pin_snapshot)
except Exception as exc:
results["errors"]["digital"][p] = repr(exc)
for p in pins:
pin_snapshot, snapshot_error = _try_pin_snapshot(p)
if snapshot_error is not None:
results["errors"]["analog"][p] = repr(snapshot_error)
continue
try:
print("Reading analog GPIO%02d..." % p)
adc = machine.ADC(machine.Pin(p))
results["analog"][p] = _adc_read(adc)
#time.sleep(1)
except Exception as exc:
results["errors"]["analog"][p] = repr(exc)
finally:
try:
_restore_pin(pin_snapshot)
except Exception as exc:
results["errors"]["analog"][p] = repr(exc)
print("=== Pin State Readout ===")
print("Board:", board)
print("=== Digital Reads ===")
for p in pins:
if p in results["digital"]:
print("GPIO%02d:" % p, results["digital"][p])
else:
print("GPIO%02d:" % p, "ERR", results["errors"]["digital"].get(p))
print("=== Analog Reads ===")
for p in pins:
if p in results["analog"]:
print("GPIO%02d:" % p, results["analog"][p])
else:
print("GPIO%02d:" % p, "ERR", results["errors"]["analog"].get(p))
return results
+38 -23
View File
@@ -1,6 +1,8 @@
import _thread
import lvgl as lv
from machine import Pin
import mpos.ui
import mpos.ui.topmenu
@@ -55,32 +57,21 @@ def single_address_i2c_scan(i2c_bus, address):
def fail_save_i2c(sda, scl):
from machine import I2C, Pin
from machine import I2C
print(f"Try to I2C initialized on {sda=} {scl=}")
try:
i2c0 = I2C(0, sda=Pin(sda), scl=Pin(scl))
except Exception as e:
print(f"Failed: {e}")
print(f"fail_save_i2c failed: {e}")
return None
else:
print("OK")
print("fail_save_i2c ok")
return i2c0
def check_pins(*pins):
from machine import Pin
print(f"Test {pins=}...")
for pin in pins:
try:
Pin(pin)
except Exception as e:
print(f"Failed to initialize {pin=}: {e}")
return True
print("All pins initialized successfully")
return True
def restore_i2c(sda, scl):
Pin(sda, Pin.IN, pull=None)
Pin(scl, Pin.IN, pull=None)
def detect_board():
import sys
@@ -88,6 +79,18 @@ def detect_board():
return "linux"
elif sys.platform == "esp32":
'''
# Reading and storing all pinstates can be useful for board detection
# But reading some pins can break peripherals
# So it's disabled by default - it's more for development
try:
import mpos
from mpos.board import pinstates
mpos.pinstates = pinstates.read_all_pins(skiplist = [7,8])
except Exception as e:
print("pinstates: WARNING: failed to read pins:", e)
'''
# First do unique_id-based board detections because they're fast and don't mess with actual hardware configurations
import machine
unique_id_prefixes = machine.unique_id()[0:3]
@@ -96,10 +99,6 @@ def detect_board():
if unique_id_prefixes == b'\x30\x30\xf9':
return "unphone"
print("(emulated) lilygo_t_display_s3 ?")
if unique_id_prefixes == b'\x10\x01\x00' or unique_id_prefixes == b'\xc0\x4e\x30':
return "lilygo_t_display_s3" # display gets confused by the i2c stuff below
print("odroid_go ?")
if unique_id_prefixes == b'\x30\xae\xa4':
return "odroid_go"
@@ -109,37 +108,53 @@ def detect_board():
# or: if single_address_i2c_scan(i2c0, 0x6A): # IMU currently not installed on prototype board
return "fri3d_2026"
# Do I2C-based board detection
print("lilygo_t_watch_s3_plus ?")
if i2c0 := fail_save_i2c(sda=10, scl=11):
if single_address_i2c_scan(i2c0, 0x19): # IMU on 0x19, vibrator on 0x5A and scan also shows: [52, 81]
return "lilygo_t_watch_s3_plus" # example MAC address: D0:CF:13:33:36:306
restore_i2c(sda=10, scl=11)
# Then do I2C-based board detection
print("matouch_esp32_s3_spi_ips_2_8_with_camera_ov3660 ?")
if i2c0 := fail_save_i2c(sda=39, scl=38):
if single_address_i2c_scan(i2c0, 0x14) or single_address_i2c_scan(i2c0, 0x5D): # "ghost" or real GT911 touch screen
return "matouch_esp32_s3_spi_ips_2_8_with_camera_ov3660"
restore_i2c(sda=39, scl=38) # fix pin 39 (data0) breaking lilygo_t_display_s3's display
print("waveshare_esp32_s3_touch_lcd_2 ?")
if i2c0 := fail_save_i2c(sda=48, scl=47):
# IO48 is floating on matouch_esp32_s3_spi_ips_2_8_with_camera_ov3660 and therefore, using that for I2C will find many devices, so do this after matouch_esp32_s3_spi_ips_2_8_with_camera_ov3660
if single_address_i2c_scan(i2c0, 0x15) and single_address_i2c_scan(i2c0, 0x6B): # CST816S touch screen and IMU
return "waveshare_esp32_s3_touch_lcd_2"
restore_i2c(sda=48, scl=47) # fix pin 47 (data6) and 48 (data7) breaking lilygo_t_display_s3's display
print("m5stack_fire ?")
if i2c0 := fail_save_i2c(sda=21, scl=22):
if single_address_i2c_scan(i2c0, 0x68): # IMU (MPU6886)
return "m5stack_fire"
restore_i2c(sda=21, scl=22)
print("fri3d_2024 ?")
if i2c0 := fail_save_i2c(sda=9, scl=18):
if single_address_i2c_scan(i2c0, 0x6B): # IMU (plus possibly the Communicator's LANA TNY at 0x38)
return "fri3d_2024"
restore_i2c(sda=9, scl=18)
# On devices without I2C, we use known GPIO states
print("(emulated) lilygo_t_display_s3 ?")
try:
# 2 buttons have PCB pull-ups so they'll be high unless pressed
pin0 = Pin(0, Pin.IN)
pin14 = Pin(14, Pin.IN)
if pin0.value() == 1 and pin14.value() == 1:
return "lilygo_t_display_s3" # display gets confused by the i2c stuff below
except Exception as e:
print(f"lilygo_t_display_s3 detection got exception: {e}")
print("Unknown board: couldn't detect known I2C devices or unique_id prefix")
# EXECUTION STARTS HERE
print(f"MicroPythonOS {BuildInfo.version.release} running lib/mpos/main.py")