Skip to content

Commit 9b71b91

Browse files
committed
improved reliability using sector erase,write,verify retry
1 parent 2058597 commit 9b71b91

File tree

1 file changed

+66
-17
lines changed

1 file changed

+66
-17
lines changed

programmer/tinyprog/__init__.py

Lines changed: 66 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ def _read_metadata(self):
167167
import math
168168
meta_roots = (
169169
[self._parse_json(self.prog.read_security_register_page(p).replace(b"\x00", b"").replace(b"\xff", b"")) for p in [1, 2, 3]] +
170-
[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]]
170+
[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]]
171171
)
172172
meta_roots = [root for root in meta_roots if root is not None]
173173
if len(meta_roots) > 0:
@@ -273,11 +273,14 @@ def read(self, addr, length, disable_progress=True):
273273
with tqdm(desc=" Reading", unit="B", unit_scale=True, total=length, disable=disable_progress) as pbar:
274274
while length > 0:
275275
read_length = min(255, length)
276-
data += self.cmd(0x0b, addr, b'\x00', read_len=read_length)
277-
self.progress(read_length)
278-
addr += read_length
279-
length -= read_length
280-
pbar.update(read_length)
276+
read_payload = self.cmd(0x0b, addr, b'\x00', read_len=read_length)
277+
payload_length = len(read_payload)
278+
if payload_length > 0:
279+
data += read_payload
280+
self.progress(payload_length)
281+
addr += payload_length
282+
length -= payload_length
283+
pbar.update(payload_length)
281284
return data
282285

283286
def write_enable(self):
@@ -301,12 +304,32 @@ def _erase(self, addr, length):
301304
self.wait_while_busy()
302305

303306
def erase(self, addr, length, disable_progress=True):
307+
return self.program_sectors(addr, length, disable_progress)
308+
309+
# for each sector: erase,program,verify
310+
# this programming is much more reliable than previous program()
311+
# because each written sector will be verified and in case of
312+
# error, retried several times
313+
# if integer value is passed to data, this will erase that much bytes
314+
def program_sectors(self, addr, data, disable_progress=True, verify_only=False, retry=10):
304315
possible_lengths = (1, 4 * 1024, 32 * 1024, 64 * 1024)
305-
306-
with tqdm(desc=" Erasing", unit="B", unit_scale=True, total=length, disable=disable_progress) as pbar:
307-
while length > 0:
316+
retries_remaining = retry
317+
data_enable = False
318+
description = " Erasing"
319+
try:
320+
if len(data) > 0:
321+
length = len(data)
322+
description = " Writing"
323+
data_enable = True
324+
except:
325+
length = data # probably integer = number of bytes to erase
326+
offset = 0
327+
write_addr = addr + offset
328+
if verify_only == False:
329+
with tqdm(desc=description, unit="B", unit_scale=True, total=length, disable=disable_progress) as pbar:
330+
while length > 0 and retries_remaining > 0:
308331
erase_length = max(p for p in possible_lengths
309-
if p <= length and addr % p == 0)
332+
if p <= length and write_addr % p == 0)
310333

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

323-
start_addr = addr & 0xfff000
324-
start_length = addr & 0xfff
346+
start_addr = write_addr & 0xfff000
347+
start_length = write_addr & 0xfff
325348
erase_length = min(0x1000 - start_length, length)
326349
end_addr = start_addr + start_length + erase_length
327350
end_length = start_addr + 0x1000 - end_addr
@@ -344,12 +367,38 @@ def erase(self, addr, length, disable_progress=True):
344367
else:
345368
# there is an opcode to erase that much data
346369
self.progress(erase_length)
347-
self._erase(addr, erase_length)
370+
self._erase(write_addr, erase_length)
371+
372+
if data_enable:
373+
# write part of the data into erased place
374+
write_data = data[offset : offset + erase_length]
375+
self.write(write_addr, write_data)
376+
read_back = self.read(write_addr, erase_length)
377+
else:
378+
# forces retry compare to succeed
379+
# todo: compare erased sector against 0xFF
380+
write_data = None
381+
read_back = None
348382

349383
# update
350-
length -= erase_length
351-
addr += erase_length
352-
pbar.update(erase_length)
384+
if read_back == write_data:
385+
length -= erase_length
386+
write_addr += erase_length
387+
offset += erase_length
388+
retries_remaining = retry
389+
pbar.update(erase_length)
390+
else:
391+
retries_remaining -= 1
392+
393+
if data_enable:
394+
read_back = self.read(addr, len(data), disable_progress=disable_progress)
395+
396+
if read_back == data:
397+
self.progress("Success!")
398+
return True
399+
else:
400+
self.progress("Failure!")
401+
return False
353402

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

0 commit comments

Comments
 (0)