From c7fbd177d4bcf0d04dfca9edb168230cb7ba8633 Mon Sep 17 00:00:00 2001 From: Robbe Derks Date: Tue, 20 Jan 2026 16:52:25 +0100 Subject: [PATCH] USBGPU: debug script for comma chestnut (#14252) * initial debug script * improvements --- extra/usbgpu/debug.py | 102 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100755 extra/usbgpu/debug.py diff --git a/extra/usbgpu/debug.py b/extra/usbgpu/debug.py new file mode 100755 index 0000000000..0741c47d93 --- /dev/null +++ b/extra/usbgpu/debug.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 + +import sys +import time +from argparse import ArgumentParser + +from pyftdi.ftdi import Ftdi +from pyftdi.eeprom import FtdiEeprom +from pyftdi.misc import hexdump + +class USBGPUDebug: + CBUS_RESET = (1 << 2) + CBUS_BOOTLOADER = (1 << 1) + + def __init__(self, device_url: str = 'ftdi://ftdi:230x/1'): + self.device_url = device_url + self.ftdi = None + self.eeprom = None + self.provisioned = False + + def __enter__(self): + self.open() + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.close() + + def open(self): + self.ftdi = Ftdi() + self.ftdi.open_from_url(self.device_url) + self.ftdi.set_baudrate(921600) + self.ftdi.set_line_property(8, 1, 'N') + + self.eeprom = FtdiEeprom() + self.eeprom.connect(self.ftdi) + + self.provisioned = (self.eeprom.cbus_func_1 == "GPIO" and self.eeprom.cbus_func_2 == "GPIO") + + if not self.provisioned: + print("Warning: Device not provisioned for usbgpu debugging. Use --provision to provision it.") + return + + # setup gpio for reset control + self.ftdi.set_cbus_direction(self.CBUS_RESET | self.CBUS_BOOTLOADER, self.CBUS_RESET | self.CBUS_BOOTLOADER) + self.ftdi.set_cbus_gpio(0x00) + + def close(self): + self.ftdi.close() + + def provision(self): + print("Provisioning FTDI device for usbgpu debugging...") + self.eeprom.set_property('cbus_func_1', 'GPIO') + self.eeprom.set_property('cbus_func_2', 'GPIO') + if self.eeprom.commit(dry_run=False): + self.eeprom.reset_device() + self.ftdi.reset() + self.provisioned = True + print("Provisioning complete.") + + def reset(self, bootloader=False): + if not self.provisioned: + raise RuntimeError("Device not provisioned for usbgpu debugging. Use --provision to provision it.") + + self.ftdi.set_cbus_gpio(self.CBUS_RESET | (self.CBUS_BOOTLOADER if bootloader else 0)) + time.sleep(0.5) + self.ftdi.set_cbus_gpio(self.CBUS_BOOTLOADER if bootloader else 0) + if bootloader: + time.sleep(1) + self.ftdi.set_cbus_gpio(0) + print("Device reset complete.") + + def read(self) -> bytes: + return self.ftdi.read_data(256).decode('utf-8', errors='replace') + + +if __name__ == "__main__": + args = ArgumentParser() + args.add_argument('--device', '-d', type=str, default='ftdi://ftdi:230x/1', help="FTDI device URL") + args.add_argument('--provision', '-p', action='store_true', default=False, help="Provision the connected FTDI for usbgpu debugging") + args.add_argument('--reset', '-r', action='store_true', default=False, help="Reset the device") + args.add_argument('--bootloader', '-b', action='store_true', default=False, help="Reset to bootloader") + args.add_argument('--no-read', '-n', action='store_true', default=False, help="Do not read debug output") + + args = args.parse_args() + + with USBGPUDebug(args.device) as dbg: + if args.provision: + dbg.provision() + + if args.reset: + dbg.reset(bootloader=False) + + if args.bootloader: + dbg.reset(bootloader=True) + + if not args.no_read: + print("Starting debug output. Press Ctrl-C to exit.\n------") + while True: + sys.stdout.write(dbg.read()) + sys.stdout.flush() + time.sleep(0.001) +