Skip to content

Commit 2d815a7

Browse files
committed
Merge branch 'cleanup' into python3
2 parents 156d81e + 7bf6f61 commit 2d815a7

File tree

1 file changed

+109
-86
lines changed

1 file changed

+109
-86
lines changed

stm32loader.py

Lines changed: 109 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,12 @@
2828
import serial
2929
import time
3030

31+
3132
# Verbose level
3233
QUIET = 20
3334

34-
# these come from AN2606
35-
chip_ids = {
35+
CHIP_IDS = {
36+
# see ST AN2606
3637
0x412: "STM32 Low-density",
3738
0x410: "STM32 Medium-density",
3839
0x414: "STM32 High-density",
@@ -56,6 +57,27 @@ class CmdException(Exception):
5657

5758
class CommandInterface:
5859

60+
class Command:
61+
# See ST AN3155
62+
GET = 0x00
63+
GET_VERSION = 0x01
64+
GET_ID = 0x02
65+
READ_MEMORY = 0x11
66+
GO = 0x21
67+
WRITE_MEMORY = 0x31
68+
ERASE = 0x43
69+
EXTENDED_ERASE = 0x44
70+
WRITE_PROTECT = 0x63
71+
WRITE_UNPROTECT = 0x73
72+
READOUT_PROTECT = 0x82
73+
READOUT_UNPROTECT = 0x92
74+
75+
class Reply:
76+
# See ST AN3155
77+
ACK = 0x79
78+
NACK = 0x1F
79+
EXTENDED_ERASE = 0x44
80+
5981
extended_erase = 0
6082

6183
def __init__(self):
@@ -73,24 +95,6 @@ def open(self, a_port='/dev/tty.usbserial-ftCYPMYJ', a_baud_rate=115200):
7395
timeout=5 # set a timeout value, None for waiting forever
7496
)
7597

76-
def _wait_for_ask(self, info=""):
77-
# wait for ask
78-
try:
79-
ask = self.serial.read()[0]
80-
except TypeError:
81-
raise CmdException("Can't read port or timeout")
82-
else:
83-
if ask == 0x79:
84-
# ACK
85-
return 1
86-
else:
87-
if ask == 0x1F:
88-
# NACK
89-
raise CmdException("NACK "+info)
90-
else:
91-
# Unknown response
92-
raise CmdException("Unknown response. "+info+": "+hex(ask))
93-
9498
def reset(self):
9599
self.serial.setDTR(0)
96100
time.sleep(0.1)
@@ -104,132 +108,116 @@ def init_chip(self):
104108

105109
# Syncro
106110
self.serial.write(b'\x7F')
107-
return self._wait_for_ask("Syncro")
111+
return self._wait_for_ack("Syncro")
108112

109113
def release_chip(self):
110114
self.serial.setRTS(1)
111115
self.reset()
112116

113-
def generic(self, command):
117+
def command(self, command):
114118
command_byte = bytes([command])
115119
control_byte = bytes([command ^ 0xFF])
116120

117121
self.serial.write(command_byte)
118122
self.serial.write(control_byte)
119123

120-
return self._wait_for_ask(hex(command))
124+
return self._wait_for_ack(hex(command))
121125

122126
def get(self):
123-
if not self.generic(0x00):
127+
if not self.command(self.Command.GET):
124128
raise CmdException("Get (0x00) failed")
125129
debug(10, "*** Get interface")
126130
length = self.serial.read()[0]
127131
version = self.serial.read()[0]
128132
debug(10, " Bootloader version: " + hex(version))
129-
data = [hex(c) for c in self.serial.read(length)]
130-
if '0x44' in data:
133+
data = self.serial.read(length)
134+
if self.Reply.EXTENDED_ERASE in data:
131135
self.extended_erase = 1
132136
debug(10, " Available commands: " + ", ".join(data))
133-
self._wait_for_ask("0x00 end")
137+
self._wait_for_ack("0x00 end")
134138
return version
135139

136140
def get_version(self):
137-
if not self.generic(0x01):
141+
if not self.command(self.Command.GET_VERSION):
138142
raise CmdException("GetVersion (0x01) failed")
139143

140144
debug(10, "*** GetVersion interface")
141145
version = self.serial.read()[0]
142146
self.serial.read(2)
143-
self._wait_for_ask("0x01 end")
147+
self._wait_for_ack("0x01 end")
144148
debug(10, " Bootloader version: " + hex(version))
145149
return version
146150

147151
def get_id(self):
148-
if not self.generic(0x02):
152+
if not self.command(self.Command.GET_ID):
149153
raise CmdException("GetID (0x02) failed")
150154

151155
debug(10, "*** GetID interface")
152156
length = self.serial.read()[0]
153157
id_data = self.serial.read(length + 1)
154-
self._wait_for_ask("0x02 end")
158+
self._wait_for_ack("0x02 end")
155159
_device_id = reduce(lambda x, y: x*0x100+y, id_data)
156160
return _device_id
157161

158-
@staticmethod
159-
def _encode_address(address):
160-
byte3 = (address >> 0) & 0xFF
161-
byte2 = (address >> 8) & 0xFF
162-
byte1 = (address >> 16) & 0xFF
163-
byte0 = (address >> 24) & 0xFF
164-
crc = byte0 ^ byte1 ^ byte2 ^ byte3
165-
return bytes([byte0, byte1, byte2, byte3, crc])
166-
167162
def read_memory(self, address, length):
168163
assert(length <= 256)
169-
if not self.generic(0x11):
164+
if not self.command(self.Command.READ_MEMORY):
170165
raise CmdException("ReadMemory (0x11) failed")
171166

172167
debug(10, "*** ReadMemory interface")
173168
self.serial.write(self._encode_address(address))
174-
self._wait_for_ask("0x11 address failed")
169+
self._wait_for_ack("0x11 address failed")
175170
n = (length - 1) & 0xFF
176-
crc = n ^ 0xFF
177-
self.serial.write(bytes([n, crc]))
178-
self._wait_for_ask("0x11 length failed")
171+
checksum = n ^ 0xFF
172+
self.serial.write(bytes([n, checksum]))
173+
self._wait_for_ack("0x11 length failed")
179174
return self.serial.read(length)
180175

181176
def go(self, address):
182-
if not self.generic(0x21):
177+
if not self.command(self.Command.GO):
183178
raise CmdException("Go (0x21) failed")
184179

185180
debug(10, "*** Go interface")
186181
self.serial.write(self._encode_address(address))
187-
self._wait_for_ask("0x21 go failed")
182+
self._wait_for_ack("0x21 go failed")
188183

189184
def write_memory(self, address, data):
190185
assert(len(data) <= 256)
191-
if not self.generic(0x31):
186+
if not self.command(self.Command.WRITE_MEMORY):
192187
raise CmdException("Write memory (0x31) failed")
193188

194189
debug(10, "*** Write memory interface")
195190
self.serial.write(self._encode_address(address))
196-
self._wait_for_ask("0x31 address failed")
191+
self._wait_for_ack("0x31 address failed")
197192
length = (len(data)-1) & 0xFF
198193
debug(10, " %s bytes to write" % [length + 1])
199194
self.serial.write(bytes([length]))
200-
crc = 0xFF
195+
checksum = 0xFF
201196
for c in data:
202-
crc = crc ^ c
197+
checksum = checksum ^ c
203198
self.serial.write(bytes([c]))
204-
self.serial.write(bytes([crc]))
205-
self._wait_for_ask("0x31 programming failed")
199+
self.serial.write(bytes([checksum]))
200+
self._wait_for_ack("0x31 programming failed")
206201
debug(10, " Write memory done")
207202

208203
def erase_memory(self, sectors=None):
209204
if self.extended_erase:
210205
return interface.extended_erase_memory()
211206

212-
if not self.generic(0x43):
207+
if not self.command(self.Command.ERASE):
213208
raise CmdException("Erase memory (0x43) failed")
214209

215210
debug(10, "*** Erase memory interface")
216-
if sectors is None:
217-
# Global erase and checksum byte
218-
self.serial.write(b'\xff')
219-
self.serial.write(b'\x00')
211+
212+
if sectors:
213+
self._page_erase(sectors)
220214
else:
221-
# Sectors erase
222-
self.serial.write(bytes([(len(sectors) - 1) & 0xFF]))
223-
crc = 0xFF
224-
for c in sectors:
225-
crc = crc ^ c
226-
self.serial.write(bytes([c]))
227-
self.serial.write(bytes([crc]))
228-
self._wait_for_ask("0x43 erasing failed")
215+
self._global_erase()
216+
self._wait_for_ack("0x43 erase failed")
229217
debug(10, " Erase memory done")
230218

231219
def extended_erase_memory(self):
232-
if not self.generic(0x44):
220+
if not self.command(self.Command.EXTENDED_ERASE):
233221
raise CmdException("Extended Erase memory (0x44) failed")
234222

235223
debug(10, "*** Extended Erase memory interface")
@@ -240,54 +228,51 @@ def extended_erase_memory(self):
240228
tmp = self.serial.timeout
241229
self.serial.timeout = 30
242230
print("Extended erase (0x44), this can take ten seconds or more")
243-
self._wait_for_ask("0x44 erasing failed")
231+
self._wait_for_ack("0x44 erasing failed")
244232
self.serial.timeout = tmp
245233
debug(10, " Extended Erase memory done")
246234

247235
def write_protect(self, sectors):
248-
if not self.generic(0x63):
236+
if not self.command(self.Command.WRITE_PROTECT):
249237
raise CmdException("Write Protect memory (0x63) failed")
250238

251239
debug(10, "*** Write protect interface")
252240
self.serial.write(bytes([((len(sectors) - 1) & 0xFF)]))
253-
crc = 0xFF
241+
checksum = 0xFF
254242
for c in sectors:
255-
crc = crc ^ c
243+
checksum = checksum ^ c
256244
self.serial.write(bytes([c]))
257-
self.serial.write(bytes([crc]))
258-
self._wait_for_ask("0x63 write protect failed")
245+
self.serial.write(bytes([checksum]))
246+
self._wait_for_ack("0x63 write protect failed")
259247
debug(10, " Write protect done")
260248

261249
def write_unprotect(self):
262-
if not self.generic(0x73):
250+
if not self.command(self.Command.WRITE_UNPROTECT):
263251
raise CmdException("Write Unprotect (0x73) failed")
264252

265253
debug(10, "*** Write Unprotect interface")
266-
self._wait_for_ask("0x73 write unprotect failed")
267-
self._wait_for_ask("0x73 write unprotect 2 failed")
254+
self._wait_for_ack("0x73 write unprotect failed")
255+
self._wait_for_ack("0x73 write unprotect 2 failed")
268256
debug(10, " Write Unprotect done")
269257

270258
def readout_protect(self):
271-
if not self.generic(0x82):
259+
if not self.command(self.Command.READOUT_PROTECT):
272260
raise CmdException("Readout protect (0x82) failed")
273261

274262
debug(10, "*** Readout protect interface")
275-
self._wait_for_ask("0x82 readout protect failed")
276-
self._wait_for_ask("0x82 readout protect 2 failed")
263+
self._wait_for_ack("0x82 readout protect failed")
264+
self._wait_for_ack("0x82 readout protect 2 failed")
277265
debug(10, " Read protect done")
278266

279267
def readout_unprotect(self):
280-
if not self.generic(0x92):
268+
if not self.command(self.Command.READOUT_UNPROTECT):
281269
raise CmdException("Readout unprotect (0x92) failed")
282270

283271
debug(10, "*** Readout Unprotect interface")
284-
self._wait_for_ask("0x92 readout unprotect failed")
285-
self._wait_for_ask("0x92 readout unprotect 2 failed")
272+
self._wait_for_ack("0x92 readout unprotect failed")
273+
self._wait_for_ack("0x92 readout unprotect 2 failed")
286274
debug(10, " Read Unprotect done")
287275

288-
289-
# Complex commands section
290-
291276
def read_memory_data(self, address, length):
292277
data = bytearray()
293278
while length > 256:
@@ -313,6 +298,44 @@ def write_memory_data(self, address, data):
313298
debug(5, "Write %(len)d bytes at 0x%(address)X" % {'address': address, 'len': 256})
314299
self.write_memory(address, data[offs:offs + length] + (b'\xff' * (256 - length)))
315300

301+
def _global_erase(self):
302+
# global erase: n=255, see ST AN3155
303+
self.serial.write(b'\xff')
304+
self.serial.write(b'\x00')
305+
306+
def _page_erase(self, pages):
307+
# page erase, see ST AN3155
308+
nr_of_pages = (len(pages) - 1) & 0xFF
309+
self.serial.write(bytes([nr_of_pages]))
310+
checksum = 0xFF
311+
for page_number in pages:
312+
self.serial.write(bytes([page_number]))
313+
checksum = checksum ^ page_number
314+
self.serial.write(bytes([checksum]))
315+
316+
def _wait_for_ack(self, info=""):
317+
try:
318+
ack = self.serial.read()[0]
319+
except TypeError:
320+
raise CmdException("Can't read port or timeout")
321+
322+
if ack == self.Reply.NACK:
323+
raise CmdException("NACK " + info)
324+
325+
if ack != self.Reply.ACK:
326+
raise CmdException("Unknown response. " + info + ": " + hex(ack))
327+
328+
return 1
329+
330+
@staticmethod
331+
def _encode_address(address):
332+
byte3 = (address >> 0) & 0xFF
333+
byte2 = (address >> 8) & 0xFF
334+
byte1 = (address >> 16) & 0xFF
335+
byte0 = (address >> 24) & 0xFF
336+
checksum = byte0 ^ byte1 ^ byte2 ^ byte3
337+
return bytes([byte0, byte1, byte2, byte3, checksum])
338+
316339

317340
def usage():
318341
print("""Usage: %s [-hqVewvr] [-l length] [-p port] [-b baud] [-a address] [-g address] [file.bin]
@@ -410,7 +433,7 @@ def usage():
410433
boot_version = interface.get()
411434
debug(0, "Bootloader version %X" % boot_version)
412435
device_id = interface.get_id()
413-
debug(0, "Chip id: 0x%x (%s)" % (device_id, chip_ids.get(device_id, "Unknown")))
436+
debug(0, "Chip id: 0x%x (%s)" % (device_id, CHIP_IDS.get(device_id, "Unknown")))
414437
# interface.get_version()
415438
# interface.get_id()
416439
# interface.readout_unprotect()

0 commit comments

Comments
 (0)