import time import board import digitalio import struct def make_dios(*args): return [digitalio.DigitalInOut(a) for a in args] address_pins = make_dios( board.GP19, board.GP20, board.GP21, board.GP22, board.GP26, board.GP27, board.GP28, board.GP4, board.GP5, board.GP6, board.GP9, ) for a in address_pins: a.switch_to_output() data_pins = make_dios( board.GP18, board.GP17, board.GP16, board.GP15, board.GP14, board.GP13, board.GP12, board.GP11, ) not_write_enable = digitalio.DigitalInOut(board.GP7) not_write_enable.switch_to_output(True) not_output_enable = digitalio.DigitalInOut(board.GP8) not_output_enable.switch_to_output(True) not_chip_enable = digitalio.DigitalInOut(board.GP10) not_chip_enable.switch_to_output(True) def a2b_hex(data): if len(data) % 2 != 0: raise ValueError("Odd-length string") return bytes(int(data[i:i+2], 16) for i in range(0, len(data), 2)) def print_ihex(address, rectype, data): data = list(data) data_str = "".join(f"{b:02x}" for b in data) data_len = len(data) assert data_len < 256 assert 0 <= rectype < 256 assert 0 <= address < 65536 checksum = (-(data_len + sum(data) + rectype + address + address // 256)) & 0xff print(f":{data_len:02x}{address:04x}{rectype:02x}{data_str}{checksum:02x}") def ihex(f): lineno = 0 while True: lineno += 1 line = f.readline() if not line: break line = line.strip() if not line.startswith(':'): continue line_bin = a2b_hex(line[1:]) if sum(line_bin) % 256 != 0: raise ValueError(f"Bad checksum on line {lineno}") data_len = struct.unpack('>BHB', line_bin[:4])[0] data_len, address, rectype, data, checksum = struct.unpack(f'>BHB{data_len}sB', line_bin) yield (address, rectype, data) def set_pins(value, pins): for p in pins: p.switch_to_output(value & 1) value >>= 1 def get_pins(pins): value = 0 for i, p in enumerate(pins): value |= p.value << i return value def strobe(pin): pin.value = False pin.value = True def read_out(*args): for p in data_pins: p.switch_to_input(digitalio.Pull.UP) not_output_enable.value = False not_chip_enable.value = False if not args: args = (0x800,) for addr in range(*args): set_pins(addr, address_pins) # There's no way the 150ns setup is violated at CP speeds! yield get_pins(data_pins) def _write(data, start_addr=0): for p in data_pins: p.switch_to_output(False) not_output_enable.value = True not_chip_enable.value = False print(end=f"{start_addr:04x}") for offset, byte in enumerate(data): addr = start_addr + offset set_pins(addr, address_pins) set_pins(byte, data_pins) assert get_pins(data_pins) == byte not_write_enable.value = False not_write_enable.value = True print(end='.') def write(data, start_addr=0): _write(data, start_addr) print() def verify(data, start_addr = 0): for p in data_pins: p.switch_to_input(digitalio.Pull.UP) not_output_enable.value = False not_chip_enable.value = False result = True for offset, byte in enumerate(data): addr = start_addr + offset set_pins(addr, address_pins) readback = get_pins(data_pins) if readback != byte: print(f"0x{addr:04x} {byte:02x} {readback:02x}") result = False if not result: raise ValueError("Verify failed") print("Verified") def write_verify(data, start_addr = 0): _write(data, start_addr) verify(data, start_addr) ## Uncomment if you want to pre-erase the eeprom (not needed) #write_verify(b"\xff" * 2048) command = input("[P]rogram, [V]erify or [R]eadout? ").lower() if command == "p": with open("xrxpl.hex") as f: for address, rectype, data in ihex(f): if rectype == 0: write_verify(data, address) elif rectype == 1: break else: print(address, rectype, data) if command in ("p", "v"): with open("xrxpl.hex") as f: for address, rectype, data in ihex(f): if rectype == 0: verify(data, address) elif rectype == 1: break else: print(address, rectype, data) else: stride = 32 end = 2048 if end % stride != 0: raise ValueError("{stride=} incompatible with {end=}") for start_address in range(0, 2048, stride): print_ihex(start_address, 0, read_out(start_address, start_address + stride)) print_ihex(0, 1, [])