58
58
__version__ = "0.0.0-auto.0"
59
59
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_miniesptool.git"
60
60
61
- SYNC_PACKET = b' \x07 \x07 \x12 UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU'
61
+ SYNC_PACKET = b" \x07 \x07 \x12 UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"
62
62
ESP32_DATAREGVALUE = 0x15122500
63
63
ESP8266_DATAREGVALUE = 0x00062000
64
64
65
65
# Commands supported by ESP8266 ROM bootloader
66
66
# pylint: disable=bad-whitespace
67
- ESP_FLASH_BEGIN = 0x02
68
- ESP_FLASH_DATA = 0x03
69
- ESP_FLASH_END = 0x04
70
- ESP_MEM_BEGIN = 0x05
71
- ESP_MEM_END = 0x06
72
- ESP_MEM_DATA = 0x07
73
- ESP_SYNC = 0x08
74
- ESP_WRITE_REG = 0x09
75
- ESP_READ_REG = 0x0a
76
- ESP_SPI_SET_PARAMS = 0x0b
77
- ESP_SPI_ATTACH = 0x0d
78
- ESP_CHANGE_BAUDRATE = 0x0f
79
- ESP_SPI_FLASH_MD5 = 0x13
80
- ESP_CHECKSUM_MAGIC = 0xef
81
-
82
- ESP8266 = 0x8266
83
- ESP32 = 0x32
67
+ ESP_FLASH_BEGIN = 0x02
68
+ ESP_FLASH_DATA = 0x03
69
+ ESP_FLASH_END = 0x04
70
+ ESP_MEM_BEGIN = 0x05
71
+ ESP_MEM_END = 0x06
72
+ ESP_MEM_DATA = 0x07
73
+ ESP_SYNC = 0x08
74
+ ESP_WRITE_REG = 0x09
75
+ ESP_READ_REG = 0x0A
76
+ ESP_SPI_SET_PARAMS = 0x0B
77
+ ESP_SPI_ATTACH = 0x0D
78
+ ESP_CHANGE_BAUDRATE = 0x0F
79
+ ESP_SPI_FLASH_MD5 = 0x13
80
+ ESP_CHECKSUM_MAGIC = 0xEF
81
+
82
+ ESP8266 = 0x8266
83
+ ESP32 = 0x32
84
84
# pylint: enable=bad-whitespace
85
85
86
86
FLASH_SIZES = {
87
- ' 512KB' : 0x00 ,
88
- ' 256KB' : 0x10 ,
89
- ' 1MB' : 0x20 ,
90
- ' 2MB' : 0x30 ,
91
- ' 4MB' : 0x40 ,
92
- ' 2MB-c1' : 0x50 ,
93
- ' 4MB-c1' : 0x60 ,
94
- ' 8MB' : 0x80 ,
95
- ' 16MB' : 0x90 ,
87
+ " 512KB" : 0x00 ,
88
+ " 256KB" : 0x10 ,
89
+ " 1MB" : 0x20 ,
90
+ " 2MB" : 0x30 ,
91
+ " 4MB" : 0x40 ,
92
+ " 2MB-c1" : 0x50 ,
93
+ " 4MB-c1" : 0x60 ,
94
+ " 8MB" : 0x80 ,
95
+ " 16MB" : 0x90 ,
96
96
}
97
97
98
- class miniesptool : # pylint: disable=invalid-name
98
+
99
+ class miniesptool : # pylint: disable=invalid-name
99
100
"""A miniature version of esptool, a programming command line tool for
100
101
ESP8266 and ESP32 chips. This version is minimized to work on CircuitPython
101
102
boards, so you can burn ESP firmware direct from the CPy disk drive. Handy
102
103
when you have an ESP module wired to a board and need to upload new AT
103
104
firmware. Its slow! Expect a few minutes when programming 1 MB flash."""
105
+
104
106
FLASH_WRITE_SIZE = 0x200
105
- FLASH_SECTOR_SIZE = 0x1000 # Flash sector size, minimum unit of erase.
107
+ FLASH_SECTOR_SIZE = 0x1000 # Flash sector size, minimum unit of erase.
106
108
ESP_ROM_BAUD = 115200
107
109
108
- def __init__ (self , uart , gpio0_pin , # pylint: disable=too-many-arguments
109
- reset_pin , * , flashsize , baudrate = ESP_ROM_BAUD ):
110
+ def __init__ (
111
+ self ,
112
+ uart ,
113
+ gpio0_pin , # pylint: disable=too-many-arguments
114
+ reset_pin ,
115
+ * ,
116
+ flashsize ,
117
+ baudrate = ESP_ROM_BAUD
118
+ ):
110
119
gpio0_pin .direction = Direction .OUTPUT
111
120
reset_pin .direction = Direction .OUTPUT
112
121
self ._gpio0pin = gpio0_pin
@@ -118,8 +127,8 @@ def __init__(self, uart, gpio0_pin, # pylint: disable=too-many-arguments
118
127
self ._chipfamily = None
119
128
self ._chipname = None
120
129
self ._flashsize = flashsize
121
- #self._debug_led = DigitalInOut(board.D13)
122
- #self._debug_led.direction = Direction.OUTPUT
130
+ # self._debug_led = DigitalInOut(board.D13)
131
+ # self._debug_led.direction = Direction.OUTPUT
123
132
124
133
@property
125
134
def debug (self ):
@@ -141,7 +150,7 @@ def baudrate(self):
141
150
def baudrate (self , baud ):
142
151
if self ._chipfamily == ESP8266 :
143
152
raise NotImplementedError ("Baud rate can only change on ESP32" )
144
- buffer = struct .pack (' <II' , baud , 0 )
153
+ buffer = struct .pack (" <II" , baud , 0 )
145
154
self .check_command (ESP_CHANGE_BAUDRATE , buffer )
146
155
self ._uart .baudrate = baud
147
156
time .sleep (0.05 )
@@ -155,9 +164,9 @@ def md5(self, offset, size):
155
164
if self ._chipfamily == ESP8266 :
156
165
raise NotImplementedError ("MD5 only supported on ESP32" )
157
166
self .check_command (ESP_SPI_ATTACH , bytes ([0 ] * 8 ))
158
- buffer = struct .pack (' <IIII' , offset , size , 0 , 0 )
167
+ buffer = struct .pack (" <IIII" , offset , size , 0 , 0 )
159
168
md5 = self .check_command (ESP_SPI_FLASH_MD5 , buffer , timeout = 2 )[1 ]
160
- return '' .join ([chr (i ) for i in md5 ])
169
+ return "" .join ([chr (i ) for i in md5 ])
161
170
162
171
@property
163
172
def mac_addr (self ):
@@ -166,20 +175,20 @@ def mac_addr(self):
166
175
mac0 , mac1 , mac2 , mac3 = self ._efuses
167
176
if self ._chipfamily == ESP8266 :
168
177
if mac3 != 0 :
169
- oui = ((mac3 >> 16 ) & 0xff , (mac3 >> 8 ) & 0xff , mac3 & 0xff )
170
- elif ((mac1 >> 16 ) & 0xff ) == 0 :
171
- oui = (0x18 , 0xfe , 0x34 )
172
- elif ((mac1 >> 16 ) & 0xff ) == 1 :
173
- oui = (0xac , 0xd0 , 0x74 )
178
+ oui = ((mac3 >> 16 ) & 0xFF , (mac3 >> 8 ) & 0xFF , mac3 & 0xFF )
179
+ elif ((mac1 >> 16 ) & 0xFF ) == 0 :
180
+ oui = (0x18 , 0xFE , 0x34 )
181
+ elif ((mac1 >> 16 ) & 0xFF ) == 1 :
182
+ oui = (0xAC , 0xD0 , 0x74 )
174
183
else :
175
184
raise RuntimeError ("Couldnt determine OUI" )
176
185
177
186
mac_addr [0 ] = oui [0 ]
178
187
mac_addr [1 ] = oui [1 ]
179
188
mac_addr [2 ] = oui [2 ]
180
- mac_addr [3 ] = (mac1 >> 8 ) & 0xff
181
- mac_addr [4 ] = mac1 & 0xff
182
- mac_addr [5 ] = (mac0 >> 24 ) & 0xff
189
+ mac_addr [3 ] = (mac1 >> 8 ) & 0xFF
190
+ mac_addr [4 ] = mac1 & 0xFF
191
+ mac_addr [5 ] = (mac0 >> 24 ) & 0xFF
183
192
if self ._chipfamily == ESP32 :
184
193
mac_addr [0 ] = mac2 >> 8 & 0xFF
185
194
mac_addr [1 ] = mac2 & 0xFF
@@ -206,7 +215,7 @@ def chip_type(self):
206
215
def chip_name (self ):
207
216
"""The specific name of the chip, e.g. ESP8266EX, to the best
208
217
of our ability to determine without a stub bootloader."""
209
- self .chip_type # pylint: disable=pointless-statement
218
+ self .chip_type # pylint: disable=pointless-statement
210
219
self ._read_efuses ()
211
220
212
221
if self .chip_type == ESP32 :
@@ -222,11 +231,11 @@ def _read_efuses(self):
222
231
if self ._chipfamily == ESP8266 :
223
232
base_addr = 0x3FF00050
224
233
elif self ._chipfamily == ESP32 :
225
- base_addr = 0x6001a000
234
+ base_addr = 0x6001A000
226
235
else :
227
236
raise RuntimeError ("Don't know what chip this is" )
228
237
for i in range (4 ):
229
- self ._efuses [i ] = self .read_register (base_addr + 4 * i )
238
+ self ._efuses [i ] = self .read_register (base_addr + 4 * i )
230
239
231
240
def get_erase_size (self , offset , size ):
232
241
"""Calculate an erase size given a specific size in bytes.
@@ -251,8 +260,9 @@ def flash_begin(self, *, size=0, offset=0):
251
260
if self ._chipfamily == ESP32 :
252
261
self .check_command (ESP_SPI_ATTACH , bytes ([0 ] * 8 ))
253
262
# We are harcoded for 4MB flash on ESP32
254
- buffer = struct .pack ('<IIIIII' , 0 , self ._flashsize ,
255
- 0x10000 , 4096 , 256 , 0xFFFF )
263
+ buffer = struct .pack (
264
+ "<IIIIII" , 0 , self ._flashsize , 0x10000 , 4096 , 256 , 0xFFFF
265
+ )
256
266
self .check_command (ESP_SPI_SET_PARAMS , buffer )
257
267
258
268
num_blocks = (size + self .FLASH_WRITE_SIZE - 1 ) // self .FLASH_WRITE_SIZE
@@ -262,18 +272,25 @@ def flash_begin(self, *, size=0, offset=0):
262
272
erase_size = size
263
273
timeout = 5
264
274
stamp = time .monotonic ()
265
- buffer = struct .pack ('<IIII' , erase_size , num_blocks ,
266
- self .FLASH_WRITE_SIZE , offset )
267
- print ("Erase size %d, num_blocks %d, size %d, offset 0x%04x" %
268
- (erase_size , num_blocks , self .FLASH_WRITE_SIZE , offset ))
275
+ buffer = struct .pack (
276
+ "<IIII" , erase_size , num_blocks , self .FLASH_WRITE_SIZE , offset
277
+ )
278
+ print (
279
+ "Erase size %d, num_blocks %d, size %d, offset 0x%04x"
280
+ % (erase_size , num_blocks , self .FLASH_WRITE_SIZE , offset )
281
+ )
269
282
270
283
self .check_command (ESP_FLASH_BEGIN , buffer , timeout = timeout )
271
284
if size != 0 :
272
- print ("Took %.2fs to erase %d flash blocks" %
273
- (time .monotonic ()- stamp , num_blocks ))
285
+ print (
286
+ "Took %.2fs to erase %d flash blocks"
287
+ % (time .monotonic () - stamp , num_blocks )
288
+ )
274
289
return num_blocks
275
290
276
- def check_command (self , opcode , buffer , checksum = 0 , timeout = 0.1 ): # pylint: disable=unused-argument
291
+ def check_command (
292
+ self , opcode , buffer , checksum = 0 , timeout = 0.1
293
+ ): # pylint: disable=unused-argument
277
294
"""Send a command packet, check that the command succeeded and
278
295
return a tuple with the value and data.
279
296
See the ESP Serial Protocol for more details on what value/data are"""
@@ -290,9 +307,9 @@ def check_command(self, opcode, buffer, checksum=0, timeout=0.1): # pylint: disa
290
307
raise RuntimeError ("Didn't get enough status bytes" )
291
308
status = data [- status_len :]
292
309
data = data [:- status_len ]
293
- #print("status", status)
294
- #print("value", value)
295
- #print("data", data)
310
+ # print("status", status)
311
+ # print("value", value)
312
+ # print("data", data)
296
313
if status [0 ] != 0 :
297
314
raise RuntimeError ("Command failure error code 0x%02x" % status [1 ])
298
315
return (value , data )
@@ -302,24 +319,24 @@ def send_command(self, opcode, buffer):
302
319
does not check response"""
303
320
self ._uart .reset_input_buffer ()
304
321
305
- #self._debug_led.value = True
322
+ # self._debug_led.value = True
306
323
checksum = 0
307
324
if opcode == 0x03 :
308
325
checksum = self .checksum (buffer [16 :])
309
- #self._debug_led.value = False
326
+ # self._debug_led.value = False
310
327
311
- packet = [0xC0 , 0x00 ] # direction
328
+ packet = [0xC0 , 0x00 ] # direction
312
329
packet .append (opcode )
313
- packet += [x for x in struct .pack ('H' , len (buffer ))]
314
- packet += [x for x in self .slip_encode (struct .pack ('I' , checksum ))]
330
+ packet += [x for x in struct .pack ("H" , len (buffer ))]
331
+ packet += [x for x in self .slip_encode (struct .pack ("I" , checksum ))]
315
332
packet += [x for x in self .slip_encode (buffer )]
316
333
packet += [0xC0 ]
317
334
if self ._debug :
318
335
print ([hex (x ) for x in packet ])
319
336
print ("Writing:" , bytearray (packet ))
320
337
self ._uart .write (bytearray (packet ))
321
338
322
- def get_response (self , opcode , timeout = 0.1 ): # pylint: disable=too-many-branches
339
+ def get_response (self , opcode , timeout = 0.1 ): # pylint: disable=too-many-branches
323
340
"""Read response data and decodes the slip packet, then parses
324
341
out the value/data and returns as a tuple of (value, data) where
325
342
each is a list of bytes"""
@@ -330,20 +347,20 @@ def get_response(self, opcode, timeout=0.1): # pylint: disable=too-many-branches
330
347
escaped_byte = False
331
348
while (time .monotonic () - stamp ) < timeout :
332
349
if self ._uart .in_waiting > 0 :
333
- c = self ._uart .read (1 ) # pylint: disable=invalid-name
334
- if c == b' \xDB ' :
350
+ c = self ._uart .read (1 ) # pylint: disable=invalid-name
351
+ if c == b" \xDB " :
335
352
escaped_byte = True
336
353
elif escaped_byte :
337
- if c == b' \xDD ' :
338
- reply += b' \xDC '
339
- elif c == b' \xDC ' :
340
- reply += b' \xC0 '
354
+ if c == b" \xDD " :
355
+ reply += b" \xDC "
356
+ elif c == b" \xDC " :
357
+ reply += b" \xC0 "
341
358
else :
342
359
reply += [0xDB , c ]
343
360
escaped_byte = False
344
361
else :
345
362
reply += c
346
- if reply and reply [0 ] != 0xc0 :
363
+ if reply and reply [0 ] != 0xC0 :
347
364
# packets must start with 0xC0
348
365
del reply [0 ]
349
366
if len (reply ) > 1 and reply [1 ] != 0x01 :
@@ -363,17 +380,16 @@ def get_response(self, opcode, timeout=0.1): # pylint: disable=too-many-branches
363
380
value = reply [5 :9 ]
364
381
data = reply [9 :- 1 ]
365
382
if self ._debug :
366
- print ("value:" , [hex (i ) for i in value ],
367
- "data:" , [hex (i ) for i in data ])
383
+ print ("value:" , [hex (i ) for i in value ], "data:" , [hex (i ) for i in data ])
368
384
return (value , data )
369
385
370
386
def read_register (self , reg ):
371
387
"""Read a register within the ESP chip RAM, returns a 4-element list"""
372
388
if self ._debug :
373
389
print ("Reading register 0x%08x" % reg )
374
- packet = struct .pack ('I' , reg )
390
+ packet = struct .pack ("I" , reg )
375
391
register = self .check_command (ESP_READ_REG , packet )[0 ]
376
- return struct .unpack ('I' , bytearray (register ))[0 ]
392
+ return struct .unpack ("I" , bytearray (register ))[0 ]
377
393
378
394
def reset (self , program_mode = False ):
379
395
"""Perform a hard-reset into ROM bootloader using gpio0 and reset"""
@@ -386,10 +402,12 @@ def reset(self, program_mode=False):
386
402
387
403
def flash_block (self , data , seq , timeout = 0.1 ):
388
404
"""Send one block of data to program into SPI Flash memory"""
389
- self .check_command (ESP_FLASH_DATA ,
390
- struct .pack ('<IIII' , len (data ), seq , 0 , 0 ) + data ,
391
- self .checksum (data ),
392
- timeout = timeout )
405
+ self .check_command (
406
+ ESP_FLASH_DATA ,
407
+ struct .pack ("<IIII" , len (data ), seq , 0 , 0 ) + data ,
408
+ self .checksum (data ),
409
+ timeout = timeout ,
410
+ )
393
411
394
412
def flash_file (self , filename , offset = 0 , md5 = None ):
395
413
"""Program a full, uncompressed binary file into SPI Flash at
@@ -405,17 +423,22 @@ def flash_file(self, filename, offset=0, md5=None):
405
423
address = offset
406
424
stamp = time .monotonic ()
407
425
while filesize - file .tell () > 0 :
408
- print ('\r Writing at 0x%08x... (%d %%)' %
409
- (address + seq * self .FLASH_WRITE_SIZE , 100 * (seq + 1 ) // blocks ), end = '' )
426
+ print (
427
+ "\r Writing at 0x%08x... (%d %%)"
428
+ % (
429
+ address + seq * self .FLASH_WRITE_SIZE ,
430
+ 100 * (seq + 1 ) // blocks ,
431
+ ),
432
+ end = "" ,
433
+ )
410
434
block = file .read (self .FLASH_WRITE_SIZE )
411
435
# Pad the last block
412
- block = block + b' \xff ' * (self .FLASH_WRITE_SIZE - len (block ))
413
- #print(block)
436
+ block = block + b" \xff " * (self .FLASH_WRITE_SIZE - len (block ))
437
+ # print(block)
414
438
self .flash_block (block , seq , timeout = 2 )
415
439
seq += 1
416
440
written += len (block )
417
- print ("Took %.2fs to write %d bytes" %
418
- (time .monotonic ()- stamp , filesize ))
441
+ print ("Took %.2fs to write %d bytes" % (time .monotonic () - stamp , filesize ))
419
442
if md5 :
420
443
print ("Verifying MD5sum " , md5 )
421
444
calcd = self .md5 (offset , filesize )
@@ -427,7 +450,9 @@ def _sync(self):
427
450
any hardware resetting"""
428
451
self .send_command (0x08 , SYNC_PACKET )
429
452
for _ in range (8 ):
430
- reply , data = self .get_response (0x08 , 0.1 ) # pylint: disable=unused-variable
453
+ reply , data = self .get_response (
454
+ 0x08 , 0.1
455
+ ) # pylint: disable=unused-variable
431
456
if not data :
432
457
continue
433
458
if len (data ) > 1 and data [0 ] == 0 and data [1 ] == 0 :
@@ -460,10 +485,10 @@ def slip_encode(buffer):
460
485
0xdb is replaced with 0xdb 0xdd and 0xc0 is replaced with 0xdb 0xdc"""
461
486
encoded = []
462
487
for b in buffer :
463
- if b == 0xdb :
464
- encoded += [0xdb , 0xdd ]
465
- elif b == 0xc0 :
466
- encoded += [0xdb , 0xdc ]
488
+ if b == 0xDB :
489
+ encoded += [0xDB , 0xDD ]
490
+ elif b == 0xC0 :
491
+ encoded += [0xDB , 0xDC ]
467
492
else :
468
493
encoded += [b ]
469
494
return bytearray (encoded )
0 commit comments