From 824ecec13d8e6f29486e830f04e35cff41f83276 Mon Sep 17 00:00:00 2001 From: "matthias@rpi" Date: Thu, 26 Oct 2023 22:02:19 +0200 Subject: [PATCH] use argparse --- eeprom.py | 220 ++++++++++++++++++++++-------------------------------- 1 file changed, 91 insertions(+), 129 deletions(-) mode change 100644 => 100755 eeprom.py diff --git a/eeprom.py b/eeprom.py old mode 100644 new mode 100755 index f3c6d17..452718a --- a/eeprom.py +++ b/eeprom.py @@ -1,8 +1,11 @@ -from sys import argv +#!/bin/env python3 +from sys import exit from time import sleep from RPi.GPIO import IN, OUT import RPi.GPIO as GPIO from re import fullmatch +import argparse +import atexit # EEPROM AT28C256 Pin names and RPi GPIO Pin Numbers # b means bar = inverted @@ -13,12 +16,16 @@ gpio_r = [14, 15, 18, 23, 24, 25, 8, 7, 12, 16, 20, 21] # Defining which 6502 pin goes to which GPIO pin # -A = [27, 22, 10, 9, 11, 5, 6, 13, - 17, 4, 3, 2, - 23, 18, 15] +A = [ + # 27, 22, 10, 9, 11, 5, 6, 13, + 13, 6, 5, 11, 9, 10, 22, 27, # A0 - A7 + 2, 3, 4, 17, # A8 - A11 + 23, 18, 15 # A12 - A14 +] -IO = gpio_r[4:12] # 8 io pins -IO.reverse() +# IO = gpio_r[4:12] # 8 io pins +# IO.reverse() +IO = [ 24, 25, 8, 7, 12, 16, 20, 21 ] OEb = 26 # Output Enable WEb = 19 # Write Enable @@ -40,28 +47,33 @@ t_DH = 0 # Data Hold Time t_WPH = 50 * 1e-9 # Write Puls High # t_WPH = 50 * 1e-4 # Write Pulse High !!!2*e5 longer than in Datasheet, since shorter high caused Problems with my Chip!!! -# setup the pins -GPIO.setmode(GPIO.BCM) -for pin in controls: - GPIO.setup(pin, OUT, initial=1) # inverted, is 1 means disable -for pin in A: - GPIO.setup(pin, OUT, initial=0) -def setup_pins(IOdirection=OUT): +def setup_address_control_pins(): + # setup the pins + GPIO.setmode(GPIO.BCM) + for pin in controls: + GPIO.setup(pin, OUT, initial=1) # inverted, is 1 means disable + for pin in A: + GPIO.setup(pin, OUT, initial=0) + +def setup_io_pins(IOdirection=OUT): # OUT when writing and IN when reading for pin in IO: GPIO.setup(pin, IOdirection) +def cleanup(): + GPIO.cleanup() + def print_pins(): for i in range(len(A)): - print(f"A{i} - {A[i]}") + print(f" A{i:02} - {A[i]}") for i in range(len(IO)): - print(f"IO{i} - {IO[i]}") - print(f"CEb - {CEb}") - print(f"WEb - {WEb}") - print(f"OEb - {OEb}") + print(f"IO{i:02} - {IO[i]}") + print(f" CEb - {CEb}") + print(f" WEb - {WEb}") + print(f" OEb - {OEb}") def set_address(address: int, bits=8): @@ -85,20 +97,23 @@ def get_bits(i: int): return len(bin(i)) - 2 # -2 for the "0x" -def check_valid_list(l: list, bits=8): +def convert_to_int(v): """ - check if the list only has x-bit binary numbers + convert 0xABC and 0b0101 to int """ - for line in l: - if not fullmatch("[01]{8}", line): - return False - return True + if type(v) == str and fullmatch(f"0x[0-9,a-f,A-F]+", v): + return int(v.replace("0x", ""), 16) + elif type(v) == str and fullmatch(f"0b[0]+", v): + return int(v.replace("0b", ""), 2) + return int(v) + def get_8_bit(l: list): for i in range(len(l)): l[i] = format(l[i], f"08b") # get the 8-bit bin value return l + def erase(from_ad=0, to_ad=32767, **keys): """ Write all 1 to the EEPROM @@ -114,7 +129,7 @@ def write_byte(byte, address, verbose=True): GPIO.output(OEb, 1) # setup the address ad_bin = set_address(address, bits=15) - setup_pins(OUT) + setup_io_pins(OUT) # Setup Data for j in range(8): if byte[7-j] == "1": @@ -126,24 +141,24 @@ def write_byte(byte, address, verbose=True): sleep(t_AS) # wait "Data Setup Time" sleep(t_DS) - + GPIO.output(CEb, 0) # Start the write pulse -> enable WEb GPIO.output(WEb, 0) - + # wait until minimum write pulse width is reached. in theory, should be t_WP-t_DS but this caused problems sleep(t_WP) # End Write Pulse -> disable WEb GPIO.output(WEb, 1) GPIO.output(CEb, 1) - + # wait "Data Hold" sleep(t_DH) GPIO.output(CEb, 0) GPIO.cleanup(IO) - setup_pins(IN) + setup_io_pins(IN) # check the toggle bit IO6, if it stops toggling the write is done timeout = 0 @@ -165,12 +180,13 @@ def write_byte(byte, address, verbose=True): if verbose: print(f"Writing:\t0b{format(address, '015b')} - 0b{byte} ||| 0x{format(address, '04x')} - {hex(int(byte, 2))}") + def read_byte(address): GPIO.output(WEb, 1) - setup_pins(IN) + setup_io_pins(IN) # set the address valid ad_bin = set_address(address, bits=15) - + # low in chip/output enable -> enable GPIO.output(CEb, 0) GPIO.output(OEb, 0) @@ -184,11 +200,12 @@ def read_byte(address): byte += "1" else: byte += "0" - + # high in OEb and CEb -> disable GPIO.output(OEb, 1) GPIO.output(CEb, 1) - return int(byte, 2) + return int(byte, 2) + def read(from_ad=0, to_ad=255, delay=1e-3, ignore=[0xff], verbose=True, single_step=False, compare=None): """ @@ -203,7 +220,7 @@ def read(from_ad=0, to_ad=255, delay=1e-3, ignore=[0xff], verbose=True, single_s for i in range(from_ad, to_ad + 1): byte = read_byte(i) content.append(byte) - + if not compare and verbose and not byte in ignore: print(f"Reading:\t0b{format(i, '015b')} - 0b{format(byte, '08b')} ||| 0x{format(i, '04x')} - 0x{format(byte, '02x')}") elif compare: @@ -219,9 +236,10 @@ def read(from_ad=0, to_ad=255, delay=1e-3, ignore=[0xff], verbose=True, single_s return unequal return content + def write(content: list, from_ad=0, delay=0, single_step=False, verbose=True, check_written=True): """ - Write a list if bytes to the eeprom. + Write a list if bytes to the eeprom. WEb controlled """ or_content = content.copy() @@ -245,7 +263,7 @@ def write(content: list, from_ad=0, delay=0, single_step=False, verbose=True, ch failed = read(from_ad=from_ad, delay=delay, single_step=single_step, verbose=False, compare=or_content) print("Comparing complete") return - + def get_bytes(filepath, from_ad=0): with open(filepath, "rb") as file: bindata = [] @@ -254,100 +272,44 @@ def get_bytes(filepath, from_ad=0): return bindata[from_ad:] -action = None -file = None -from_ad = 0 -to_ad = 32767 #2^15 -1 -delay = 0 -single_step = False -verbose = False -ignore = [0xff] -content = [] - -if len(argv) > 1: - for i in range(1, len(argv)): - arg = argv[i] - if argv[i-1] == "-w": - action = "write_file" - file = arg - elif argv[i-1] == "-wh": - action = "write_hex" - content = arg.split(",") - for i in range(len(content)): - content[i] = int(content[i].replace("0x", ""), 16) - elif arg == "-r": - action = "read" - verbose = True - elif argv[i-1] == "-c": - action = "compare" - file = arg - verbose = True - elif arg == "-e": - action = "erase" - elif arg == "-h": - action = "help" - - # Addresses - elif argv[i-1] == "--from": - if "0x" in arg: - from_ad = int(arg.replace("0x", ""), 16) - else: - from_ad = int(arg) - elif argv[i-1] == "--to": - if "0x" in arg: - to_ad = int(arg.replace("0x", ""), 16) - else: - to_ad = int(arg) - # options - elif argv[i-1] == "--delay": - delay = float(arg) - elif arg == "--single_step": - single_step = True - elif arg == "--verbose": - verbose = True - elif argv[i-1] == "--ignore": - ignore = arg.split(",") - for i in range(len(ignore)): - ignore[i] = int(ignore[i].replace("0x", ""), 16) - -# print(action, file, from_ad, to_ad) -if action == "write_file": - write(get_bytes(file, from_ad=from_ad), from_ad=from_ad, delay=delay, single_step=single_step, verbose=verbose) -elif action == "write_hex": - write(content, from_ad=from_ad, delay=delay, single_step=single_step, verbose=verbose) -elif action == "read": - read(from_ad=from_ad, to_ad=to_ad, delay=delay, single_step=single_step, verbose=verbose, ignore=ignore) -elif action == "compare": - read(from_ad=from_ad, to_ad=to_ad, delay=delay, single_step=single_step, verbose=verbose, ignore=ignore, compare=get_bytes(file)) -elif action == "erase": - erase(from_ad=from_ad, to_ad=to_ad, delay=delay, single_step=single_step, verbose=verbose) -elif action == "help": - print(""" -program options: - -w file write file - -e erase EEPROM - -c compare EEPROM content to binary file - -r read EEPROM - -h print this - --from x start at address x (can be int or hex with '0x' prefix)) - --to y end at address y - --single_step single step the program - --delay t extra delay t between cycles - --verbose print extra information - --ignore a,b,.. ignore the numbers a,b,... (in hex) when printing. Default is 0xff -if no option is given the GPIO-Pin-settings are printed - """) -else: - print("No valid action given. Printing Pin-Settings") - print_pins() -# if performing action from this script, put the code HERE: - - -GPIO.cleanup() - - - +def main(): + parser = argparse.ArgumentParser( + prog="AT28C256-EEPROM Writer", + description="Read and write from/to an AT28C256 EEPROM via the Raspberry Pi 4's GPIO pins\n2023 Matthias Quintern", + epilog="Numbers can be passed as int, hex prefixed with '0x' and binary prefixed with '0b'", + ) + parser.add_argument("--write", "-w", dest="write", action="store_true", default=False, help="write binary file onto the EEPROM") + parser.add_argument("--compare", "-c", dest="compare", action="store_true", default=False, help="compare EEPROM content to binary file") + parser.add_argument("--read", "-r", dest="read", action="store_true", default=False, help="read the contents of the EEPROM") + parser.add_argument("--erase", "-e", dest="erase", action="store_true", default=False, help="erase the contents of the EEPROM") + parser.add_argument("--file", "-f", metavar="file", dest="file", action="store", default="", help="file for --write and --compare") + parser.add_argument("--from", metavar="start-address", dest="from_ad", action="store", default=0, type=convert_to_int, help="start at address x") + parser.add_argument("--to", metavar="end-address", dest="to_ad", action="store", default=32767, type=convert_to_int, help="end at address y (inclusive)") + parser.add_argument("--single-step", dest="single_step", action="store_true", default=False, help="single step the program") + parser.add_argument("--delay", dest="delay", metavar="delay", action="store", default=0, help="extra delay between cycles") + parser.add_argument("--ignore", dest="ignore", metavar="numbers", action="store", nargs="*", type=convert_to_int, default=[0x100], help="ignore the numbers a b ... Default=[0xff]") + parser.add_argument("--verbose", dest="verbose", action="store_true", default=False, help="increase verbosity") + parser.add_argument("--print-pins", dest="print_pins", action="store_true", default=False, help="print the pin layout and exit") + args = parser.parse_args() + if (args.write or args.compare) and not args.file: + parser.error('--file is required with --write and --compare') + + if args.print_pins: + print_pins() + exit(0) + if args.erase: + erase(from_ad=args.from_ad, to_ad=args.to_ad, delay=args.delay, single_step=args.single_step, verbose=args.verbose) + if args.write: + write(get_bytes(args.file, from_ad=args.from_ad), from_ad=args.from_ad, delay=args.delay, single_step=args.single_step, verbose=args.verbose) + if args.read: + read(from_ad=args.from_ad, to_ad=args.to_ad, delay=args.delay, single_step=args.single_step, verbose=args.verbose, ignore=args.ignore) + if args.compare: + compare(from_ad=args.from_ad, to_ad=args.to_ad, delay=args.delay, single_step=args.single_step, verbose=args.verbose, ignore=args.ignore, compare=get_bytes(args.file)) +if __name__ == '__main__': + atexit.register(cleanup) + setup_address_control_pins() + main()