add batch read/write UART for speedo mode
This commit is contained in:
parent
9cc2357ea4
commit
f6f9096895
|
|
@ -33,5 +33,8 @@ if __name__ == "__main__":
|
||||||
from manta import Manta
|
from manta import Manta
|
||||||
m = Manta('manta.yaml')
|
m = Manta('manta.yaml')
|
||||||
|
|
||||||
for addr, pixel in enumerate(pixels):
|
# for addr, pixel in enumerate(pixels):
|
||||||
m.image_mem.write(addr, pixel)
|
# m.image_mem.write(addr, pixel)
|
||||||
|
|
||||||
|
addrs = list(range(len(pixels)))
|
||||||
|
m.image_mem.interface.write_registers(addrs, pixels)
|
||||||
|
|
@ -123,19 +123,25 @@ class UARTInterface:
|
||||||
assert config["baudrate"] > 0, "Baudrate must be positive."
|
assert config["baudrate"] > 0, "Baudrate must be positive."
|
||||||
self.baudrate = config["baudrate"]
|
self.baudrate = config["baudrate"]
|
||||||
|
|
||||||
# confirm core clock is sufficiently fast
|
# Confirm core clock is sufficiently fast
|
||||||
clocks_per_baud = self.clock_freq // self.baudrate
|
clocks_per_baud = self.clock_freq // self.baudrate
|
||||||
assert clocks_per_baud >= 2
|
assert clocks_per_baud >= 2
|
||||||
self.clocks_per_baud = clocks_per_baud
|
self.clocks_per_baud = clocks_per_baud
|
||||||
|
|
||||||
# confirm we can match baudrate suffeciently well
|
# Confirm we can match baudrate suffeciently well
|
||||||
actual_baudrate = self.clock_freq / clocks_per_baud
|
actual_baudrate = self.clock_freq / clocks_per_baud
|
||||||
baudrate_error = 100 * abs(actual_baudrate - self.baudrate) / self.baudrate
|
baudrate_error = 100 * abs(actual_baudrate - self.baudrate) / self.baudrate
|
||||||
assert (
|
assert (
|
||||||
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
|
# Set chunk_size, which is the max amount of bytes that get dumped
|
||||||
|
# to the OS driver at a time
|
||||||
|
self.chunk_size = 256
|
||||||
|
if "chunk size" in config:
|
||||||
|
self.chunk_size = config["chunk size"]
|
||||||
|
|
||||||
|
# Set verbosity
|
||||||
self.verbose = False
|
self.verbose = False
|
||||||
if "verbose" in config:
|
if "verbose" in config:
|
||||||
self.verbose = config["verbose"]
|
self.verbose = config["verbose"]
|
||||||
|
|
@ -167,31 +173,30 @@ class UARTInterface:
|
||||||
assert rd[0].serial_number == rd[1].serial_number, "Serial numbers should be the same on both FT2232 ports - probably somehow grabbed ports on two different devices."
|
assert rd[0].serial_number == rd[1].serial_number, "Serial numbers should be the same on both FT2232 ports - probably somehow grabbed ports on two different devices."
|
||||||
return rd[0].device if rd[0].location > rd[1].location else rd[1].device
|
return rd[0].device if rd[0].location > rd[1].location else rd[1].device
|
||||||
|
|
||||||
|
def decode_response(self, response):
|
||||||
|
"""Make sure reponse from FPGA has the correct format, and return data contained within if so."""
|
||||||
|
assert response is not None, "No reponse received."
|
||||||
|
|
||||||
|
response_str = response.decode('ascii')
|
||||||
|
assert response_str[0] == 'M', "Bad message recieved, incorrect preamble."
|
||||||
|
assert response_str[-1] == '\n', "Bad message received, incorrect EOL."
|
||||||
|
assert response_str[-2] == '\r', "Bad message received, incorrect EOL."
|
||||||
|
assert len(response_str) == 7, f"Wrong number of bytes received, expecting 7 but got {len(response)}."
|
||||||
|
|
||||||
|
return int(response_str[1:5], 16)
|
||||||
|
|
||||||
def read_register(self, addr):
|
def read_register(self, addr):
|
||||||
self.open_port_if_not_alredy_open()
|
self.open_port_if_not_alredy_open()
|
||||||
|
|
||||||
# request from the bus
|
# request from the bus
|
||||||
addr_str = '{:04X}'.format(addr)
|
request = f"M{addr:04X}\r\n".encode('ascii')
|
||||||
request = f"M{addr_str}\r\n".encode('ascii')
|
|
||||||
|
|
||||||
self.ser.write(request)
|
self.ser.write(request)
|
||||||
|
|
||||||
# read and parse the response
|
# read and parse the response
|
||||||
response = self.ser.read(7)
|
data = self.decode_response(self.ser.read(7))
|
||||||
|
|
||||||
assert response is not None, "No reponse received."
|
|
||||||
response = response.decode('ascii')
|
|
||||||
assert response[0] == 'M', "Bad message recieved, incorrect preamble."
|
|
||||||
assert response[-1] == '\n', "Bad message received, incorrect EOL."
|
|
||||||
assert response[-2] == '\r', "Bad message received, incorrect EOL."
|
|
||||||
assert len(response) == 7, f"Wrong number of bytes received, expecting 7 but got {len(response)}."
|
|
||||||
|
|
||||||
data = int(response[1:5], 16)
|
|
||||||
data_hex ='{:04X}'.format(data)
|
|
||||||
|
|
||||||
|
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
print(f"read {data_hex} from {addr_str}")
|
print(f"read {data:04X} from {addr:04X}")
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
@ -199,14 +204,57 @@ class UARTInterface:
|
||||||
self.open_port_if_not_alredy_open()
|
self.open_port_if_not_alredy_open()
|
||||||
|
|
||||||
# request from the bus
|
# request from the bus
|
||||||
addr_str = '{:04X}'.format(addr)
|
request = f"M{addr:04X}{data:04X}\r\n".encode('ascii')
|
||||||
data_str = '{:04X}'.format(data)
|
self.ser.write(request)
|
||||||
request = f"M{addr_str}{data_str}\r\n"
|
|
||||||
|
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
print(f"wrote {data_str} to {addr_str}")
|
print(f"wrote {data:04X} to {addr:04X}")
|
||||||
|
|
||||||
self.ser.write(request.encode('ascii'))
|
def read_registers(self, addrs):
|
||||||
|
assert isinstance(addrs, list), "Read addresses must be list of integers."
|
||||||
|
assert all(isinstance(addr, int) for addr in addrs), "Read addresses must be list of integers."
|
||||||
|
|
||||||
|
# send data in chunks because the reponses will fill up the OS's
|
||||||
|
# input buffer in no time flat
|
||||||
|
self.open_port_if_not_alredy_open()
|
||||||
|
|
||||||
|
inbound_bytes = b""
|
||||||
|
for i in range(0, len(addrs), self.chunk_size):
|
||||||
|
addr_chunk = addrs[i:i+self.chunk_size]
|
||||||
|
|
||||||
|
outbound_bytes = [f"M{addr:04X}\r\n".encode('ascii') for addr in addr_chunk]
|
||||||
|
outbound_bytes = b"".join(outbound_bytes)
|
||||||
|
|
||||||
|
self.ser.write(outbound_bytes)
|
||||||
|
|
||||||
|
inbound_bytes += self.ser.read(len(outbound_bytes))
|
||||||
|
|
||||||
|
data = []
|
||||||
|
for i in range(0, len(inbound_bytes), 7):
|
||||||
|
response = inbound_bytes[i:i+7]
|
||||||
|
data = self.decode_response(response)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def write_registers(self, addrs, datas):
|
||||||
|
assert isinstance(addrs, list), "Write addresses must be list of integers."
|
||||||
|
assert isinstance(datas, list), "Write data must be list of integers."
|
||||||
|
assert all(isinstance(addr, int) for addr in addrs), "Write addresses must be list of integers."
|
||||||
|
assert all(isinstance(data, int) for data in datas), "Write data must be list of integers."
|
||||||
|
assert len(addrs) == len(datas), "Write addresses and write data must be of same length."
|
||||||
|
|
||||||
|
# send data in chunks because the responses will fill up the OS's
|
||||||
|
# input buffer in no time flat
|
||||||
|
self.open_port_if_not_alredy_open()
|
||||||
|
|
||||||
|
for i in range(0, len(addrs), self.chunk_size):
|
||||||
|
addr_chunk = addrs[i:i+self.chunk_size]
|
||||||
|
|
||||||
|
outbound_bytes = [f"M{addrs[i]:04X}{datas[i]:04X}\r\n" for i in range(len(addr_chunk))]
|
||||||
|
outbound_bytes = [ob.encode('ascii') for ob in outbound_bytes]
|
||||||
|
outbound_bytes = b"".join(outbound_bytes)
|
||||||
|
|
||||||
|
self.ser.write(outbound_bytes)
|
||||||
|
|
||||||
def hdl_top_level_ports(self):
|
def hdl_top_level_ports(self):
|
||||||
# this should return the probes that we want to connect to top-level, but like as a string of verilog
|
# this should return the probes that we want to connect to top-level, but like as a string of verilog
|
||||||
|
|
@ -627,9 +675,8 @@ class LogicAnalyzerCore:
|
||||||
|
|
||||||
# Read out contents from memory
|
# Read out contents from memory
|
||||||
print(" -> Reading sample memory contents...")
|
print(" -> Reading sample memory contents...")
|
||||||
block_mem_contents = []
|
addrs = list(range(self.block_memory_base_addr, self.max_addr))
|
||||||
for i in range(self.block_memory_base_addr, self.max_addr):
|
block_mem_contents = self.interface.read_registers(addrs)
|
||||||
block_mem_contents.append(self.interface.read_register(i))
|
|
||||||
|
|
||||||
# Revolve BRAM contents around so the data pointed to by the read_pointer
|
# Revolve BRAM contents around so the data pointed to by the read_pointer
|
||||||
# is at the beginning
|
# is at the beginning
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue