@@ -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