Skip to content

Commit

Permalink
improved reliability using sector erase,write,verify retry
Browse files Browse the repository at this point in the history
  • Loading branch information
emard committed Jul 28, 2018
1 parent 2058597 commit 9b71b91
Showing 1 changed file with 66 additions and 17 deletions.
83 changes: 66 additions & 17 deletions programmer/tinyprog/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def _read_metadata(self):
import math
meta_roots = (
[self._parse_json(self.prog.read_security_register_page(p).replace(b"\x00", b"").replace(b"\xff", b"")) for p in [1, 2, 3]] +
[self._parse_json(self.prog.read(int(math.pow(2, p) - (4 * 1024)), (4 * 1024)).replace(b"\x00", b"").replace(b"\xff", b"")) for p in [17, 18, 19, 20, 21, 22, 23, 24]]
[self._parse_json(self.prog.read(int(math.pow(2, p) - (4 * 1024)), (4 * 1024) - 256).replace(b"\x00", b"").replace(b"\xff", b"")) for p in [17, 18, 19, 20, 21, 22, 23, 24]]
)
meta_roots = [root for root in meta_roots if root is not None]
if len(meta_roots) > 0:
Expand Down Expand Up @@ -273,11 +273,14 @@ def read(self, addr, length, disable_progress=True):
with tqdm(desc=" Reading", unit="B", unit_scale=True, total=length, disable=disable_progress) as pbar:
while length > 0:
read_length = min(255, length)
data += self.cmd(0x0b, addr, b'\x00', read_len=read_length)
self.progress(read_length)
addr += read_length
length -= read_length
pbar.update(read_length)
read_payload = self.cmd(0x0b, addr, b'\x00', read_len=read_length)
payload_length = len(read_payload)
if payload_length > 0:
data += read_payload
self.progress(payload_length)
addr += payload_length
length -= payload_length
pbar.update(payload_length)
return data

def write_enable(self):
Expand All @@ -301,12 +304,32 @@ def _erase(self, addr, length):
self.wait_while_busy()

def erase(self, addr, length, disable_progress=True):
return self.program_sectors(addr, length, disable_progress)

# for each sector: erase,program,verify
# this programming is much more reliable than previous program()
# because each written sector will be verified and in case of
# error, retried several times
# if integer value is passed to data, this will erase that much bytes
def program_sectors(self, addr, data, disable_progress=True, verify_only=False, retry=10):
possible_lengths = (1, 4 * 1024, 32 * 1024, 64 * 1024)

with tqdm(desc=" Erasing", unit="B", unit_scale=True, total=length, disable=disable_progress) as pbar:
while length > 0:
retries_remaining = retry
data_enable = False
description = " Erasing"
try:
if len(data) > 0:
length = len(data)
description = " Writing"
data_enable = True
except:
length = data # probably integer = number of bytes to erase
offset = 0
write_addr = addr + offset
if verify_only == False:
with tqdm(desc=description, unit="B", unit_scale=True, total=length, disable=disable_progress) as pbar:
while length > 0 and retries_remaining > 0:
erase_length = max(p for p in possible_lengths
if p <= length and addr % p == 0)
if p <= length and write_addr % p == 0)

if erase_length == 1:
# there are no opcode to erase that much
Expand All @@ -320,8 +343,8 @@ def erase(self, addr, length, disable_progress=True):
# +------------------+------------------+----------------+
# <- start_length -> <- erase_length -> <- end_length ->

start_addr = addr & 0xfff000
start_length = addr & 0xfff
start_addr = write_addr & 0xfff000
start_length = write_addr & 0xfff
erase_length = min(0x1000 - start_length, length)
end_addr = start_addr + start_length + erase_length
end_length = start_addr + 0x1000 - end_addr
Expand All @@ -344,12 +367,38 @@ def erase(self, addr, length, disable_progress=True):
else:
# there is an opcode to erase that much data
self.progress(erase_length)
self._erase(addr, erase_length)
self._erase(write_addr, erase_length)

if data_enable:
# write part of the data into erased place
write_data = data[offset : offset + erase_length]
self.write(write_addr, write_data)
read_back = self.read(write_addr, erase_length)
else:
# forces retry compare to succeed
# todo: compare erased sector against 0xFF
write_data = None
read_back = None

# update
length -= erase_length
addr += erase_length
pbar.update(erase_length)
if read_back == write_data:
length -= erase_length
write_addr += erase_length
offset += erase_length
retries_remaining = retry
pbar.update(erase_length)
else:
retries_remaining -= 1

if data_enable:
read_back = self.read(addr, len(data), disable_progress=disable_progress)

if read_back == data:
self.progress("Success!")
return True
else:
self.progress("Failure!")
return False

# don't use this directly, use the public "write" function instead
def _write(self, addr, data):
Expand Down Expand Up @@ -416,4 +465,4 @@ def program_bitstream(self, addr, bitstream):
self.progress("Waking up SPI flash")
self.wake()
self.progress(str(len(bitstream)) + " bytes to program")
return self.program(addr, bitstream)
return self.program_sectors(addr, bitstream, disable_progress=False)

0 comments on commit 9b71b91

Please sign in to comment.