use argparse

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

200
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":
@ -143,7 +158,7 @@ def write_byte(byte, address, verbose=True):
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,9 +180,10 @@ 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)
@ -190,6 +206,7 @@ def read_byte(address):
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):
""" """
from_ad: start address from where to read from_ad: start address from where to read
@ -219,6 +236,7 @@ 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.
@ -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()