354 lines
10 KiB
Python
354 lines
10 KiB
Python
|
from sys import argv
|
||
|
from time import sleep
|
||
|
from RPi.GPIO import IN, OUT
|
||
|
import RPi.GPIO as GPIO
|
||
|
from re import fullmatch
|
||
|
# EEPROM AT28C256 Pin names and RPi GPIO Pin Numbers
|
||
|
# b means bar = inverted
|
||
|
|
||
|
|
||
|
gpio_l = [2, 3, 4, 17, 27, 22, 10, 9, 11, 5, 6, 13, 19, 26]
|
||
|
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]
|
||
|
|
||
|
IO = gpio_r[4:12] # 8 io pins
|
||
|
IO.reverse()
|
||
|
|
||
|
OEb = 26 # Output Enable
|
||
|
WEb = 19 # Write Enable
|
||
|
CEb = 14 # Chip Enable is hooked up to A15 on the processor
|
||
|
|
||
|
controls = [CEb, WEb, OEb]
|
||
|
|
||
|
# TIMES
|
||
|
# Read:
|
||
|
t_ACC = 150 * 1e-9 # Address to Output Delay
|
||
|
|
||
|
# Write:
|
||
|
t_AS = 0 # Address Setup time
|
||
|
t_AH = 50 * 1e-9 # Address Hold Time
|
||
|
t_CS = 0 # Chip Select Hold Time
|
||
|
t_WP = 100 * 1e-9 # Write Pulse Width
|
||
|
t_DS = 50 * 1e-9 # Data Setup Time_CS = 0
|
||
|
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):
|
||
|
# OUT when writing and IN when reading
|
||
|
for pin in IO:
|
||
|
GPIO.setup(pin, IOdirection)
|
||
|
|
||
|
|
||
|
def print_pins():
|
||
|
for i in range(len(A)):
|
||
|
print(f"A{i} - {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}")
|
||
|
|
||
|
|
||
|
def set_address(address: int, bits=8):
|
||
|
"""
|
||
|
set the address pins to the given value
|
||
|
"""
|
||
|
ad_bin = format(address, f"0{bits}b") # get the x-bit verion if the address, eg 12 -> 00001100
|
||
|
for j in range(bits):
|
||
|
# print("Address:", address, ad_bin, j)
|
||
|
if ad_bin[bits-1-j] == "0":
|
||
|
GPIO.output(A[j], 0)
|
||
|
elif ad_bin[bits-1-j] == "1":
|
||
|
GPIO.output(A[j], 1)
|
||
|
return ad_bin
|
||
|
|
||
|
|
||
|
def get_bits(i: int):
|
||
|
"""
|
||
|
return how many bits are needed to express the number in binary
|
||
|
"""
|
||
|
return len(bin(i)) - 2 # -2 for the "0x"
|
||
|
|
||
|
|
||
|
def check_valid_list(l: list, bits=8):
|
||
|
"""
|
||
|
check if the list only has x-bit binary numbers
|
||
|
"""
|
||
|
for line in l:
|
||
|
if not fullmatch("[01]{8}", line):
|
||
|
return False
|
||
|
return True
|
||
|
|
||
|
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
|
||
|
WEb controlled
|
||
|
"""
|
||
|
data = [0xff for i in range(from_ad, to_ad)]
|
||
|
write(data, from_ad=from_ad, **keys)
|
||
|
print("Erased EEPROM - Done!")
|
||
|
return
|
||
|
|
||
|
|
||
|
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 Data
|
||
|
for j in range(8):
|
||
|
if byte[7-j] == "1":
|
||
|
bit = 1
|
||
|
else:
|
||
|
bit = 0
|
||
|
GPIO.output(IO[j], bit)
|
||
|
# wait "Address" Setup Time
|
||
|
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)
|
||
|
|
||
|
# check the toggle bit IO6, if it stops toggling the write is done
|
||
|
timeout = 0
|
||
|
while timeout < 1e3:
|
||
|
GPIO.output(OEb, 0)
|
||
|
sleep(1e-9)
|
||
|
bit1 = GPIO.input(IO[6])
|
||
|
GPIO.output(OEb, 1)
|
||
|
sleep(1e-9)
|
||
|
GPIO.output(OEb, 0)
|
||
|
sleep(1e-9)
|
||
|
bit2 = GPIO.input(IO[6])
|
||
|
GPIO.output(OEb, 1)
|
||
|
sleep(1e-9)
|
||
|
if bit1 == bit2:
|
||
|
timeout = 1e3
|
||
|
timeout += 1
|
||
|
GPIO.output(CEb, 1)
|
||
|
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)
|
||
|
# 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)
|
||
|
|
||
|
# wait the "Address to Output Delay" until the output is valid
|
||
|
sleep(t_ACC)
|
||
|
|
||
|
byte = ""
|
||
|
for j in range(8):
|
||
|
if GPIO.input(IO[7-j]) == 1:
|
||
|
byte += "1"
|
||
|
else:
|
||
|
byte += "0"
|
||
|
|
||
|
# high in OEb and CEb -> disable
|
||
|
GPIO.output(OEb, 1)
|
||
|
GPIO.output(CEb, 1)
|
||
|
return int(byte, 2)
|
||
|
|
||
|
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
|
||
|
to_ad: end address to read to
|
||
|
delay: delay between readings in s
|
||
|
verbose wether to print the reading
|
||
|
ignore list of values which are not printed
|
||
|
"""
|
||
|
content = []
|
||
|
unequal = []
|
||
|
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:
|
||
|
if not compare[i] == byte:
|
||
|
unequal.append(i)
|
||
|
print(f"Unequal at Address 0x{format(i, '04x')} ||| File: 0x{format(compare[i], '02x')} vs EEPROM: 0x{format(byte, '02x')}")
|
||
|
|
||
|
# wait artifical delay
|
||
|
sleep(delay)
|
||
|
if single_step:
|
||
|
input("Press Return to read the next byte")
|
||
|
if compare:
|
||
|
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.
|
||
|
WEb controlled
|
||
|
"""
|
||
|
or_content = content.copy()
|
||
|
content = get_8_bit(content)
|
||
|
failed = []
|
||
|
print(f"Writing to EEPROM: {len(content)} bytes from address {hex(from_ad)}.")
|
||
|
|
||
|
for i in range(len(content)):
|
||
|
write_byte(content[i], from_ad + i, verbose=verbose)
|
||
|
# wait artifical delay
|
||
|
sleep(delay)
|
||
|
if single_step:
|
||
|
input("Press Return to write the next byte")
|
||
|
print("Write to EEPROM - Done!")
|
||
|
if check_written:
|
||
|
print("Comparing EEPROM to file...")
|
||
|
failed = read(from_ad=from_ad, delay=delay, single_step=single_step, verbose=False, compare=or_content)
|
||
|
while len(failed) > 0:
|
||
|
for ad in failed:
|
||
|
write_byte(content[ad], ad, verbose=verbose)
|
||
|
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 = []
|
||
|
for byte in file.read():
|
||
|
bindata.append(byte)
|
||
|
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()
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|