add ability to autodetect serial port

This commit is contained in:
Fischer Moseley 2023-03-23 20:46:49 -04:00
parent f7077f96d8
commit a562c8136c
4 changed files with 48 additions and 19 deletions

View File

@ -21,6 +21,6 @@ cores:
led17_r: 1 led17_r: 1
uart: uart:
port: "/dev/tty.usbserial-2102926963071" port: "auto"
baudrate: 115200 baudrate: 115200
clock_freq: 100000000 clock_freq: 100000000

View File

@ -14,6 +14,6 @@ cores:
- larry && curly && ~moe - larry && curly && ~moe
uart: uart:
port: "/dev/tty.usbserial-2102926963071" port: "auto"
baudrate: 115200 baudrate: 115200
clock_freq: 100000000 clock_freq: 100000000

View File

@ -5,6 +5,6 @@ cores:
size: 64 size: 64
uart: uart:
port: "/dev/ttyUSB1" port: "auto"
baudrate: 115200 baudrate: 115200
clock_freq: 100000000 clock_freq: 100000000

View File

@ -7,9 +7,12 @@ version = "0.0.0"
class UARTInterface: class UARTInterface:
def __init__(self, config): def __init__(self, config):
# Obtain port. No way to check if it's valid yet. # Obtain port. Try to automatically detect port if "auto" is specified
assert "port" in config, "No serial port provided to UART core." assert "port" in config, "No serial port provided to UART core."
self.port = config["port"] self.port = config["port"]
if config["port"] == "auto":
self.port = self.autodetect_port()
# Check that clock frequency is provided and positive # Check that clock frequency is provided and positive
assert "clock_freq" in config, "Clock frequency not provided to UART core." assert "clock_freq" in config, "Clock frequency not provided to UART core."
@ -33,21 +36,50 @@ class UARTInterface:
baudrate_error <= 5 baudrate_error <= 5
), "Unable to match target baudrate - they differ by {baudrate_error}%" ), "Unable to match target baudrate - they differ by {baudrate_error}%"
# set verbosity
self.verbose = False
if "verbose" in config: if "verbose" in config:
self.verbose = config["verbose"] self.verbose = config["verbose"]
else:
self.verbose = False
def open(self): # open port
import serial import serial
self.ser = serial.Serial(self.port, self.baudrate) self.ser = serial.Serial(self.port, self.baudrate)
def read_register(self, addr): def autodetect_port(self):
# open the port if it's not already open # TODO: clean all of this up - it's a little gross and inflexible
if not hasattr(self, "ser"):
self.open()
# as far as I know the FT2232 is the only chip used on the icestick/digilent boards, so just look for that
known_devices = [{
"name": "FT2232",
"vid": 0x403,
"pid": 0x6010
}]
import serial.tools.list_ports
recognized_devices = []
for port in serial.tools.list_ports.comports():
for device in known_devices:
if (port.vid == device["vid"]) and (port.pid == device["pid"]):
recognized_devices.append(port)
assert len(recognized_devices) == 2, f"Expected to recognize two ports (one for bitstream upload over JTAG, another for UART). Instead recognized {len(recognized_devices)} ports. Which device to select is unknown."
largest_location_device = None
largest_location = 0
for device in recognized_devices:
location = device.hwid.split("LOCATION=")[-1]
location = location.replace("-","")
location = location.replace(":","")
location = location.replace(".","")
location = int(location)
if location > largest_location:
largest_location = location
largest_location_device = device
return largest_location_device.device
def read_register(self, addr):
# request from the bus # request from the bus
addr_str = '{:04X}'.format(addr) addr_str = '{:04X}'.format(addr)
request = f"M{addr_str}\r\n".encode('ascii') request = f"M{addr_str}\r\n".encode('ascii')
@ -65,7 +97,7 @@ class UARTInterface:
assert len(response) == 7, f"Wrong number of bytes received, expecting 7 but got {len(response)}." assert len(response) == 7, f"Wrong number of bytes received, expecting 7 but got {len(response)}."
data = int(response[1:5], 16) data = int(response[1:5], 16)
data_hex ='{:04X}'.format(data) data_hex ='{:04X}'.format(data)
if self.verbose: if self.verbose:
@ -74,11 +106,8 @@ class UARTInterface:
return data return data
def write_register(self, addr, data): def write_register(self, addr, data):
# open the port if it's not already open # request from the bus
if not hasattr(self, "ser"): addr_str = '{:04X}'.format(addr)
self.open()
addr_str = '{:04X}'.format(addr)
data_str = '{:04X}'.format(data) data_str = '{:04X}'.format(data)
request = f"M{addr_str}{data_str}\r\n" request = f"M{addr_str}{data_str}\r\n"
@ -385,7 +414,7 @@ class LUTRAMCore:
def read(self, addr): def read(self, addr):
return self.interface.read_register(addr + self.base_addr) return self.interface.read_register(addr + self.base_addr)
def write(self, addr, data): def write(self, addr, data):
return self.interface.write_register(addr + self.base_addr, data) return self.interface.write_register(addr + self.base_addr, data)