33
33
__version__ = "0.0.0-auto.0"
34
34
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_AVRprog.git"
35
35
36
- import busio
37
36
from digitalio import Direction , DigitalInOut
38
37
39
38
_SLOW_CLOCK = 100000
40
- _FAST_CLOCK = 2000000
39
+ _FAST_CLOCK = 1000000
41
40
42
41
class AVRprog :
43
42
"""
@@ -47,25 +46,14 @@ class AVRprog:
47
46
"""
48
47
_spi = None
49
48
_rst = None
50
- _mosi = None
51
- _miso = None
52
- _sck = None
53
49
54
- def init (self , sck_pin , mosi_pin , miso_pin , rst_pin ):
50
+ def init (self , spi_bus , rst_pin ):
55
51
"""
56
52
Initialize the programmer with SPI pins that will be used to
57
53
communicate with the chip. Currently only hardware-SPI pins are
58
54
supported!
59
55
"""
60
- self ._spi = busio .SPI (sck_pin , mosi_pin , miso_pin )
61
- #except:
62
- # pins = [DigitalInOut(p) for p in (sck_pin, mosi_pin, miso_pin)]
63
- # self._sck, self._mosi, self._miso = pins
64
- # self._sck.direction = Direction.OUTPUT
65
- # self._sck.value = False
66
- # self._mosi.direction = Direction.OUTPUT
67
- # self._miso.direction = Direction.INPUT
68
-
56
+ self ._spi = spi_bus
69
57
self ._rst = DigitalInOut (rst_pin )
70
58
self ._rst .direction = Direction .OUTPUT
71
59
self ._rst .value = True
@@ -99,28 +87,33 @@ def program_file(self, chip, file_name, verbose=False, verify=True):
99
87
self .erase_chip ()
100
88
101
89
self .begin ()
102
- hexfile = open (file_name , 'r' )
90
+
91
+ # create a file state dictionary
92
+ file_state = {'line' : 0 , 'ext_addr' : 0 , 'eof' : False }
93
+ file_state ['f' ] = open (file_name , 'r' )
103
94
104
95
page_size = chip ['page_size' ]
105
96
106
97
for page_addr in range (0 , chip ['flash_size' ], page_size ):
107
- #print("Programming page $%04X" % page_addr)
98
+ if verbose :
99
+ print ("Programming page $%04X..." % page_addr , end = "" )
108
100
page_buffer = bytearray (page_size )
109
101
for b in range (page_size ):
110
102
page_buffer [b ] = 0xFF # make an empty page
111
103
112
- read_hex_page (hexfile , page_addr , page_size , page_buffer )
104
+ read_hex_page (file_state , page_addr , page_size , page_buffer )
113
105
114
106
if all ([v == 0xFF for v in page_buffer ]):
115
- #print("Skipping empty page")
107
+ if verbose :
108
+ print ("skipping" )
116
109
continue
117
110
118
- if verbose :
119
- print ("Programming page @ $%04X" % (page_addr ))
120
111
#print("From HEX file: ", page_buffer)
121
112
self ._flash_page (bytearray (page_buffer ), page_addr , page_size )
122
113
123
114
if not verify :
115
+ if verbose :
116
+ print ("done!" )
124
117
continue
125
118
126
119
if verbose :
@@ -137,7 +130,10 @@ def program_file(self, chip, file_name, verbose=False, verify=True):
137
130
self .end ()
138
131
return False
139
132
140
- hexfile .close ()
133
+ if file_state ['eof' ]:
134
+ break # we're done, bail!
135
+
136
+ file_state ['f' ].close ()
141
137
self .end ()
142
138
return True
143
139
@@ -149,21 +145,25 @@ def verify_file(self, chip, file_name, verbose=False):
149
145
if not self .verify_sig (chip ):
150
146
raise RuntimeError ("Signature read failure" )
151
147
152
- hexfile = open (file_name , 'r' )
148
+ # create a file state dictionary
149
+ file_state = {'line' : 0 , 'ext_addr' : 0 , 'eof' : False }
150
+ file_state ['f' ] = open (file_name , 'r' )
151
+
153
152
page_size = chip ['page_size' ]
154
153
self .begin ()
155
- for page_addr in range (0 , chip ['flash_size' ], page_size ):
154
+ for page_addr in range (0x0 , chip ['flash_size' ], page_size ):
156
155
page_buffer = bytearray (page_size )
157
156
for b in range (page_size ):
158
157
page_buffer [b ] = 0xFF # make an empty page
159
158
160
- read_hex_page (hexfile , page_addr , page_size , page_buffer )
159
+ read_hex_page (file_state , page_addr , page_size , page_buffer )
161
160
162
161
if verbose :
163
162
print ("Verifying page @ $%04X" % page_addr )
164
163
read_buffer = bytearray (page_size )
165
164
self .read (page_addr , read_buffer )
166
165
#print("From memory: ", read_buffer)
166
+ #print("From file : ", page_buffer)
167
167
168
168
if page_buffer != read_buffer :
169
169
if verbose :
@@ -172,7 +172,11 @@ def verify_file(self, chip, file_name, verbose=False):
172
172
# pylint: enable=line-too-long
173
173
self .end ()
174
174
return False
175
- hexfile .close ()
175
+
176
+ if file_state ['eof' ]:
177
+ break # we're done, bail!
178
+
179
+ file_state ['f' ].close ()
176
180
self .end ()
177
181
return True
178
182
@@ -237,18 +241,16 @@ def begin(self, clock=_FAST_CLOCK):
237
241
send the initialization command to get the AVR's attention.
238
242
"""
239
243
self ._rst .value = False
240
- if self ._spi :
241
- while self ._spi and not self ._spi .try_lock ():
242
- pass
243
- self ._spi .configure (baudrate = clock )
244
+ while self ._spi and not self ._spi .try_lock ():
245
+ pass
246
+ self ._spi .configure (baudrate = clock )
244
247
self ._transaction ((0xAC , 0x53 , 0 , 0 ))
245
248
246
249
def end (self ):
247
250
"""
248
251
End programming mode: SPI is released, and reset pin set high.
249
252
"""
250
- if self ._spi :
251
- self ._spi .unlock ()
253
+ self ._spi .unlock ()
252
254
self ._rst .value = True
253
255
254
256
def read_signature (self ):
@@ -269,37 +271,48 @@ def read(self, addr, read_buffer):
269
271
directly into 'read_buffer'
270
272
Requires calling begin() beforehand to put in programming mode.
271
273
"""
274
+ last_addr = 0
272
275
for i in range (len (read_buffer )// 2 ):
273
276
read_addr = addr // 2 + i # read 'words' so address is half
277
+
278
+ if (last_addr >> 16 ) != (read_addr >> 16 ):
279
+ # load extended byte
280
+ #print("Loading extended address", read_addr >> 16)
281
+ self ._transaction ((0x4D , 0 , read_addr >> 16 , 0 ))
274
282
high = self ._transaction ((0x28 , read_addr >> 8 , read_addr , 0 ))[2 ]
275
283
low = self ._transaction ((0x20 , read_addr >> 8 , read_addr , 0 ))[2 ]
276
284
#print("%04X: %02X %02X" % (read_addr*2, low, high))
277
285
read_buffer [i * 2 ] = low
278
286
read_buffer [i * 2 + 1 ] = high
279
287
288
+ last_addr = read_addr
289
+
280
290
#################### Low level
281
291
def _flash_word (self , addr , low , high ):
282
292
self ._transaction ((0x40 , addr >> 8 , addr , low ))
283
293
self ._transaction ((0x48 , addr >> 8 , addr , high ))
284
294
285
295
def _flash_page (self , page_buffer , page_addr , page_size ):
286
- for i in range (page_size / 2 ):
296
+ page_addr //= 2 # address is by 'words' not bytes!
297
+ for i in range (page_size / 2 ): # page indexed by words, not bytes
287
298
lo_byte , hi_byte = page_buffer [2 * i :2 * i + 2 ]
288
299
self ._flash_word (i , lo_byte , hi_byte )
289
- page_addr //= 2
300
+
301
+ # load extended byte
302
+ self ._transaction ((0x4D , 0 , page_addr >> 16 , 0 ))
303
+
290
304
commit_reply = self ._transaction ((0x4C , page_addr >> 8 , page_addr , 0 ))
291
- if ((commit_reply [1 ] << 8 ) + commit_reply [2 ]) != page_addr :
305
+ if ((commit_reply [1 ] << 8 ) + commit_reply [2 ]) != ( page_addr & 0xFFFF ) :
292
306
raise RuntimeError ("Failed to commit page to flash" )
293
307
self ._busy_wait ()
294
308
295
309
def _transaction (self , command ):
296
310
reply = bytearray (4 )
297
311
command = bytearray ([i & 0xFF for i in command ])
298
312
299
- if self ._spi :
300
- self ._spi .write_readinto (command , reply )
313
+ self ._spi .write_readinto (command , reply )
301
314
#s = [hex(i) for i in command]
302
- #print("Sending %s reply %s" % (command, reply))
315
+ #print("Sending %s reply %s" % ([hex(i) for i in command], [hex(i) for i in reply] ))
303
316
if reply [2 ] != command [1 ]:
304
317
raise RuntimeError ("SPI transaction failed" )
305
318
return reply [1 :] # first byte is ignored
@@ -308,7 +321,7 @@ def _busy_wait(self):
308
321
while self ._transaction ((0xF0 , 0 , 0 , 0 ))[2 ] & 0x01 :
309
322
pass
310
323
311
- def read_hex_page (hexfile , page_addr , page_size , page_buffer ):
324
+ def read_hex_page (file_state , page_addr , page_size , page_buffer ):
312
325
"""
313
326
Helper function that does the Intel Hex parsing. Given an open file
314
327
'hexfile' and our desired buffer address start (page_addr), size
@@ -322,36 +335,51 @@ def read_hex_page(hexfile, page_addr, page_size, page_buffer):
322
335
line does not contain any more data we can use.
323
336
"""
324
337
while True : # read until our page_buff is full!
325
- orig_loc = hexfile .tell () # in case we have to 'back up'
326
- line = hexfile .readline () # read one line from the HEX file
338
+ orig_loc = file_state ['f' ].tell () # in case we have to 'back up'
339
+ line = file_state ['f' ].readline () # read one line from the HEX file
340
+ file_state ['line' ] += 1
341
+
327
342
if not line :
343
+ file_state ['eof' ] = True
328
344
return False
329
345
#print(line)
330
346
if line [0 ] != ':' : # lines must start with ':'
331
- raise RuntimeError ("HEX line doesn't start with :" )
347
+ raise RuntimeError ("HEX line %d doesn't start with :" % file_state [ 'line' ] )
332
348
333
349
# Try to parse the line length, address, and record type
334
350
try :
335
351
hex_len = int (line [1 :3 ], 16 )
336
352
line_addr = int (line [3 :7 ], 16 )
353
+ file_state ['line_addr' ] = line_addr
337
354
rec_type = int (line [7 :9 ], 16 )
338
355
except ValueError :
339
- raise RuntimeError ("Could not parse HEX line addr" )
356
+ raise RuntimeError ("Could not parse HEX line %d addr" % file_state [ 'line' ] )
340
357
358
+ if file_state ['ext_addr' ]:
359
+ line_addr += file_state ['ext_addr' ]
341
360
#print("Hex len: %d, addr %04X, record type %d " % (hex_len, line_addr, rec_type))
342
361
343
362
# We should only look for data type records (0x00)
344
- if rec_type == 0x01 :
345
- return False # reached end of file
346
- elif rec_type != 0x00 :
347
- raise RuntimeError ("Unsupported record type %d" % rec_type )
363
+ if rec_type == 1 :
364
+ file_state ['eof' ] = True
365
+ return False # reached end of file
366
+ if rec_type == 2 :
367
+ file_state ['ext_addr' ] = int (line [9 :13 ], 16 ) << 4
368
+ #print("Extended addr: %05X" % file_state['ext_addr'])
369
+ continue
370
+ if rec_type == 3 : # sometimes appears, we ignore this
371
+ continue
372
+ elif rec_type != 0 : # if not the above or a data record...
373
+ raise RuntimeError ("Unsupported record type %d on line %d" %
374
+ (rec_type , file_state ['line' ]))
348
375
349
376
# check if this file file is either after the current page
350
377
# (in which case, we've read all we can for this page and should
351
- # commence flashing ...)
378
+ # commence flasing ...)
352
379
if line_addr >= (page_addr + page_size ):
353
380
#print("Hex is past page address range")
354
- hexfile .seek (orig_loc ) # back up!
381
+ file_state ['f' ].seek (orig_loc ) # back up!
382
+ file_state ['line' ] -= 1
355
383
return True
356
384
# or, this line does not yet reach the current page address, in which
357
385
# case which should just keep reading in hopes we reach the address
0 commit comments