use argparse

This commit is contained in:
matthias@rpi 2023-10-26 22:02:19 +02:00
parent df08c72d1f
commit 824ecec13d

220
eeprom.py Normal file → Executable file
View File

@ -1,8 +1,11 @@
from sys import argv #!/bin/env python3
from sys import exit
from time import sleep from time import sleep
from RPi.GPIO import IN, OUT from RPi.GPIO import IN, OUT
import RPi.GPIO as GPIO import RPi.GPIO as GPIO
from re import fullmatch from re import fullmatch
import argparse
import atexit
# EEPROM AT28C256 Pin names and RPi GPIO Pin Numbers # EEPROM AT28C256 Pin names and RPi GPIO Pin Numbers
# b means bar = inverted # 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 # Defining which 6502 pin goes to which GPIO pin
# #
A = [27, 22, 10, 9, 11, 5, 6, 13, A = [
17, 4, 3, 2, # 27, 22, 10, 9, 11, 5, 6, 13,
23, 18, 15] 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 = gpio_r[4:12] # 8 io pins
IO.reverse() # IO.reverse()
IO = [ 24, 25, 8, 7, 12, 16, 20, 21 ]
OEb = 26 # Output Enable OEb = 26 # Output Enable
WEb = 19 # Write 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-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!!! # 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 # OUT when writing and IN when reading
for pin in IO: for pin in IO:
GPIO.setup(pin, IOdirection) GPIO.setup(pin, IOdirection)
def cleanup():
GPIO.cleanup()
def print_pins(): def print_pins():
for i in range(len(A)): 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)): for i in range(len(IO)):
print(f"IO{i} - {IO[i]}") print(f"IO{i:02} - {IO[i]}")
print(f"CEb - {CEb}") print(f" CEb - {CEb}")
print(f"WEb - {WEb}") print(f" WEb - {WEb}")
print(f"OEb - {OEb}") print(f" OEb - {OEb}")
def set_address(address: int, bits=8): 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" 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 type(v) == str and fullmatch(f"0x[0-9,a-f,A-F]+", v):
if not fullmatch("[01]{8}", line): return int(v.replace("0x", ""), 16)
return False elif type(v) == str and fullmatch(f"0b[0]+", v):
return True return int(v.replace("0b", ""), 2)
return int(v)
def get_8_bit(l: list): def get_8_bit(l: list):
for i in range(len(l)): for i in range(len(l)):
l[i] = format(l[i], f"08b") # get the 8-bit bin value l[i] = format(l[i], f"08b") # get the 8-bit bin value
return l return l
def erase(from_ad=0, to_ad=32767, **keys): def erase(from_ad=0, to_ad=32767, **keys):
""" """
Write all 1 to the EEPROM Write all 1 to the EEPROM
@ -114,7 +129,7 @@ def write_byte(byte, address, verbose=True):
GPIO.output(OEb, 1) GPIO.output(OEb, 1)
# setup the address # setup the address
ad_bin = set_address(address, bits=15) ad_bin = set_address(address, bits=15)
setup_pins(OUT) setup_io_pins(OUT)
# Setup Data # Setup Data
for j in range(8): for j in range(8):
if byte[7-j] == "1": if byte[7-j] == "1":
@ -126,24 +141,24 @@ def write_byte(byte, address, verbose=True):
sleep(t_AS) sleep(t_AS)
# wait "Data Setup Time" # wait "Data Setup Time"
sleep(t_DS) sleep(t_DS)
GPIO.output(CEb, 0) GPIO.output(CEb, 0)
# Start the write pulse -> enable WEb # Start the write pulse -> enable WEb
GPIO.output(WEb, 0) GPIO.output(WEb, 0)
# wait until minimum write pulse width is reached. in theory, should be t_WP-t_DS but this caused problems # wait until minimum write pulse width is reached. in theory, should be t_WP-t_DS but this caused problems
sleep(t_WP) sleep(t_WP)
# End Write Pulse -> disable WEb # End Write Pulse -> disable WEb
GPIO.output(WEb, 1) GPIO.output(WEb, 1)
GPIO.output(CEb, 1) GPIO.output(CEb, 1)
# wait "Data Hold" # wait "Data Hold"
sleep(t_DH) sleep(t_DH)
GPIO.output(CEb, 0) GPIO.output(CEb, 0)
GPIO.cleanup(IO) GPIO.cleanup(IO)
setup_pins(IN) setup_io_pins(IN)
# check the toggle bit IO6, if it stops toggling the write is done # check the toggle bit IO6, if it stops toggling the write is done
timeout = 0 timeout = 0
@ -165,12 +180,13 @@ def write_byte(byte, address, verbose=True):
if verbose: if verbose:
print(f"Writing:\t0b{format(address, '015b')} - 0b{byte} ||| 0x{format(address, '04x')} - {hex(int(byte, 2))}") print(f"Writing:\t0b{format(address, '015b')} - 0b{byte} ||| 0x{format(address, '04x')} - {hex(int(byte, 2))}")
def read_byte(address): def read_byte(address):
GPIO.output(WEb, 1) GPIO.output(WEb, 1)
setup_pins(IN) setup_io_pins(IN)
# set the address valid # set the address valid
ad_bin = set_address(address, bits=15) ad_bin = set_address(address, bits=15)
# low in chip/output enable -> enable # low in chip/output enable -> enable
GPIO.output(CEb, 0) GPIO.output(CEb, 0)
GPIO.output(OEb, 0) GPIO.output(OEb, 0)
@ -184,11 +200,12 @@ def read_byte(address):
byte += "1" byte += "1"
else: else:
byte += "0" byte += "0"
# high in OEb and CEb -> disable # high in OEb and CEb -> disable
GPIO.output(OEb, 1) GPIO.output(OEb, 1)
GPIO.output(CEb, 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): 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): for i in range(from_ad, to_ad + 1):
byte = read_byte(i) byte = read_byte(i)
content.append(byte) content.append(byte)
if not compare and verbose and not byte in ignore: 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')}") print(f"Reading:\t0b{format(i, '015b')} - 0b{format(byte, '08b')} ||| 0x{format(i, '04x')} - 0x{format(byte, '02x')}")
elif compare: 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 unequal
return content return content
def write(content: list, from_ad=0, delay=0, single_step=False, verbose=True, check_written=True): 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 WEb controlled
""" """
or_content = content.copy() 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) failed = read(from_ad=from_ad, delay=delay, single_step=single_step, verbose=False, compare=or_content)
print("Comparing complete") print("Comparing complete")
return return
def get_bytes(filepath, from_ad=0): def get_bytes(filepath, from_ad=0):
with open(filepath, "rb") as file: with open(filepath, "rb") as file:
bindata = [] bindata = []
@ -254,100 +272,44 @@ def get_bytes(filepath, from_ad=0):
return bindata[from_ad:] return bindata[from_ad:]
action = None def main():
file = None parser = argparse.ArgumentParser(
from_ad = 0 prog="AT28C256-EEPROM Writer",
to_ad = 32767 #2^15 -1 description="Read and write from/to an AT28C256 EEPROM via the Raspberry Pi 4's GPIO pins\n2023 Matthias Quintern",
delay = 0 epilog="Numbers can be passed as int, hex prefixed with '0x' and binary prefixed with '0b'",
single_step = False )
verbose = False parser.add_argument("--write", "-w", dest="write", action="store_true", default=False, help="write binary file onto the EEPROM")
ignore = [0xff] parser.add_argument("--compare", "-c", dest="compare", action="store_true", default=False, help="compare EEPROM content to binary file")
content = [] 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")
if len(argv) > 1: parser.add_argument("--file", "-f", metavar="file", dest="file", action="store", default="", help="file for --write and --compare")
for i in range(1, len(argv)): parser.add_argument("--from", metavar="start-address", dest="from_ad", action="store", default=0, type=convert_to_int, help="start at address x")
arg = argv[i] parser.add_argument("--to", metavar="end-address", dest="to_ad", action="store", default=32767, type=convert_to_int, help="end at address y (inclusive)")
if argv[i-1] == "-w": parser.add_argument("--single-step", dest="single_step", action="store_true", default=False, help="single step the program")
action = "write_file" parser.add_argument("--delay", dest="delay", metavar="delay", action="store", default=0, help="extra delay between cycles")
file = arg 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]")
elif argv[i-1] == "-wh": parser.add_argument("--verbose", dest="verbose", action="store_true", default=False, help="increase verbosity")
action = "write_hex" parser.add_argument("--print-pins", dest="print_pins", action="store_true", default=False, help="print the pin layout and exit")
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()
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()