1 | #!/usr/bin/python
|
2 |
|
3 | ################################################################################
|
4 | #
|
5 | # A script to program a LPC800 devices via ISP serial interface
|
6 | #
|
7 | # Author: Axel Heider, axelheider(_at_)gmx.de
|
8 | # Created: 2014-Mar-20
|
9 | # Last Change: 2014-Jan-01
|
10 | #
|
11 | # License: Creative Commons, CC-BY-NC-SA 3.0/de
|
12 | # German: http://creativecommons.org/licenses/by-nc-sa/3.0/de/
|
13 | # General: http://creativecommons.org/licenses/by-nc-sa/3.0/
|
14 | #
|
15 | #
|
16 | # This script is based on the work of Lars Ole Belhage (belhage@midibel.com),
|
17 | # who published it together with a minimal development enviroment for the
|
18 | # LPC800.
|
19 | #
|
20 | ################################################################################
|
21 |
|
22 | import sys
|
23 | import argparse
|
24 | import serial
|
25 |
|
26 | #
|
27 | # http://www.nxp.com/documents/user_manual/UM10601.pdf
|
28 | #
|
29 | # Memory map:
|
30 | # 0x00000000
|
31 | # Flash (4 Kb)
|
32 | # 0x00001000
|
33 | # Flash (on devices with 8 Kb)
|
34 | # 0x00002000
|
35 | # Flash (on devices with 16 Kb)
|
36 | # 0x00004000
|
37 | # ...
|
38 | # 0x10000000
|
39 | # SRAM (1 Kb)
|
40 | # 0x10000400
|
41 | # SRAM (on devices with 2 Kb)
|
42 | # 0x10000800
|
43 | # SRAM (on devices with 4 Kb)
|
44 | # 0x10001000
|
45 | # ...
|
46 | # 0x14000000
|
47 | # Micro Trace Buffer (1 Kb)
|
48 | # 0x14000400
|
49 | # ...
|
50 | # 0x1FFF0000
|
51 | # Boot ROM (8 Kb)
|
52 | # 0x1FFF2000
|
53 | # ....
|
54 | #
|
55 | # Flash:
|
56 | # page size: 64 Byte
|
57 | # sector size: 1 kB (16 pages)
|
58 | #
|
59 | # Sector Page Address 4 KB 8 KB 16 Kb
|
60 | # 0 0 - 15 0x00000000 - 0x000003FF x x x
|
61 | # 1 16 - 31 0x00000400 - 0x000007FF x x x
|
62 | # 2 32 - 47 0x00000800 - 0x00000BFF x x x
|
63 | # 3 48 - 63 0x00000C00 - 0x00000FFF x x x
|
64 | # 4 64 - 79 0x00001000 - 0x000013FF - x x
|
65 | # 5 80 - 95 0x00001400 - 0x000017FF - x x
|
66 | # 6 96 - 111 0x00001800 - 0x00001BFF - x x
|
67 | # 7 112 - 127 0x00001C00 - 0x00001FFF - x x
|
68 | # 8 128 - 143 0x00002000 - 0x000023FF - - x
|
69 | # 9 144 - 159 0x00002400 - 0x000027FF - - x
|
70 | # 10 160 - 175 0x00002800 - 0x00002BFF - - x
|
71 | # 11 176 - 191 0x00002C00 - 0x00002FFF - - x
|
72 | # 12 192 - 207 0x00003000 - 0x000033FF - - x
|
73 | # 13 208 - 223 0x00003400 - 0x000037FF - - x
|
74 | # 14 224 - 239 0x00003800 - 0x00003BFF - - x
|
75 | # 15 240 - 255 0x00003C00 - 0x00003FFF - - x
|
76 | #
|
77 | # 80 byte of SRAM from 0x10000000 to 0x10000050 are not used by the bootloader,
|
78 | # thus content in this area is retained during reset. SRAM memory is not
|
79 | # retained for deep power-down mode for full power.
|
80 | #
|
81 |
|
82 | ADDR_CHECKSUM = 0x001C
|
83 |
|
84 | ADDR_CRP = 0x02fc
|
85 | NO_ISP = 0x4E697370
|
86 | CRP1 = 0x12345678
|
87 | CRP2 = 0x87654321
|
88 | CRP3 = 0x43218765
|
89 |
|
90 |
|
91 |
|
92 | #-------------------------------------------------------------------------------
|
93 | def printVerbose(level,string):
|
94 | if (args.verbose >= level):
|
95 | print(string)
|
96 |
|
97 | #-------------------------------------------------------------------------------
|
98 | def hexdump(data, indentStr="", printOffs=0, length=16, sep='.'):
|
99 | FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or sep for x in range(256)])
|
100 | lines = []
|
101 | for c in xrange(0, len(data), length):
|
102 | chars = data[c:c+length]
|
103 | hexStr = ' '.join(["%02x"%x for x in chars])
|
104 | if len(hexStr) > 24:
|
105 | hexStr = "%s %s"%(hexStr[:24], hexStr[24:])
|
106 | printable = ''.join(["%s"%((x<=127 and FILTER[x]) or sep) for x in chars])
|
107 | lines.append("%s%08x: %-*s | %s"%(indentStr,printOffs+c, length*3, hexStr, printable))
|
108 | print "\n".join(lines)
|
109 |
|
110 | #-------------------------------------------------------------------------------
|
111 | def get_uint32_le(data, offset):
|
112 | return data[offset] \
|
113 | | (data[offset+1] << 8) \
|
114 | | (data[offset+2] << 16) \
|
115 | | (data[offset+3] << 24)
|
116 |
|
117 |
|
118 | #-------------------------------------------------------------------------------
|
119 | def set_uint32_le(data,offset,val):
|
120 | data[offset] = (val >> 0) & 0xff
|
121 | data[offset+1] = (val >> 8) & 0xff
|
122 | data[offset+2] = (val >> 16) & 0xff
|
123 | data[offset+3] = (val >> 24) & 0xff
|
124 |
|
125 | #-------------------------------------------------------------------------------
|
126 | def get_uint16_le(data, offset):
|
127 | return data[offset] \
|
128 | | (data[offset+1] << 8)
|
129 |
|
130 | #-------------------------------------------------------------------------------
|
131 | def set_uint16_le(data,offset,val):
|
132 | data[offset] = (val >> 0) & 0xff
|
133 | data[offset+1] = (val >> 8) & 0xff
|
134 |
|
135 | #-------------------------------------------------------------------------------
|
136 | def append_uint16_le(data,val):
|
137 | data.append( (val >> 0) & 0xff );
|
138 | data.append( (val >> 8) & 0xff );
|
139 |
|
140 | #-------------------------------------------------------------------------------
|
141 | def append_uint32_le(data,val):
|
142 | data.append( (val >> 0) & 0xff );
|
143 | data.append( (val >> 8) & 0xff );
|
144 | data.append( (val >> 16) & 0xff );
|
145 | data.append( (val >> 24) & 0xff );
|
146 |
|
147 |
|
148 | #-------------------------------------------------------------------------------
|
149 | def sendSer(data):
|
150 | printVerbose(2,"sendRaw: <"+data+">")
|
151 | ser.write(data)
|
152 | ser.flush()
|
153 |
|
154 | #-------------------------------------------------------------------------------
|
155 | def sendSerCrLf(data):
|
156 | printVerbose(2,"sendCrLf: <"+data+"> CR LF")
|
157 | ser.write(data+"\r\n")
|
158 | ser.flush()
|
159 |
|
160 | #-------------------------------------------------------------------------------
|
161 | def readSer():
|
162 | ret = ser.readline().rstrip()
|
163 | printVerbose(2,"read: <"+ret+">")
|
164 | return ret
|
165 |
|
166 | #-------------------------------------------------------------------------------
|
167 | CMD_SUCCESS = 0
|
168 | ERR_INVALID_CMD = 1
|
169 | ERR_SRC_ADDR = 2 # not on word boundary.
|
170 | ERR_DST_ADDR = 3 # not on a correct boundary.
|
171 | ERR_SRC_ADDR_NOT_MAPPED = 4 # not mapped in memory map. Count value is taken in to consideration where applicable.
|
172 | ERR_DST_ADDR_NOT_MAPPED = 5 # not mapped in memory map. Count value is taken in to consideration where applicable.
|
173 | ERR_COUNT = 6 # Byte count is not multiple of 4 or is not a permitted value.
|
174 | ERR_INVALID_SECTOR = 7 # Sector number is invalid or end sector number is greater than start sector number.
|
175 | ERR_SECTOR_NOT_BLANK = 8
|
176 | ERR_SECTOR_NOT_PREPARED = 9 # Command to prepare sector for write operation was not executed.
|
177 | ERR_COMPARE = 10
|
178 | ERR_BUSY = 11 # Flash programming hardware interface is busy.
|
179 | ERR_PARAM = 12
|
180 | ERR_ADDR = 13 # not on word boundary
|
181 | ERR_ADDR_NOT_MAPPED = 14 # Address is not mapped in the memory map. Count value is taken in to consideration where applicable.
|
182 | ERR_CMD_LOCKED = 15
|
183 | ERR_INVALID_CODE = 16
|
184 | ERR_INVALID_BAUD_RATE = 17
|
185 | ERR_INVALID_STOP_BIT = 18
|
186 | ERR_CRP_ENABLED = 19
|
187 |
|
188 |
|
189 | #-------------------------------------------------------------------------------
|
190 | def cmdErr2Str(cmdErr):
|
191 | return { CMD_SUCCESS: "SUCCESS",
|
192 | ERR_INVALID_CMD: "ERR_INVALID_CMD",
|
193 | ERR_SRC_ADDR: "ERR_SRC_ADDR",
|
194 | ERR_DST_ADDR: "ERR_DST_ADDR",
|
195 | ERR_SRC_ADDR_NOT_MAPPED: "ERR_SRC_ADDR_NOT_MAPPED",
|
196 | ERR_DST_ADDR_NOT_MAPPED: "ERR_DST_ADDR_NOT_MAPPED",
|
197 | ERR_COUNT: "ERR_COUNT",
|
198 | ERR_INVALID_SECTOR: "ERR_INVALID_SECTOR",
|
199 | ERR_SECTOR_NOT_BLANK: "ERR_SECTOR_NOT_BLANK",
|
200 | ERR_SECTOR_NOT_PREPARED: "ERR_SECTOR_NOT_PREPARED",
|
201 | ERR_COMPARE: "ERR_COMPARE",
|
202 | ERR_BUSY: "ERR_BUSY",
|
203 | ERR_PARAM: "ERR_PARAM",
|
204 | ERR_ADDR: "ERR_ADDR",
|
205 | ERR_ADDR_NOT_MAPPED: "ERR_ADDR_NOT_MAPPED",
|
206 | ERR_CMD_LOCKED: "ERR_CMD_LOCKED",
|
207 | ERR_INVALID_CODE: "ERR_INVALID_CODE",
|
208 | ERR_INVALID_BAUD_RATE: "ERR_INVALID_BAUD_RATE",
|
209 | ERR_INVALID_STOP_BIT: "ERR_INVALID_STOP_BIT",
|
210 | ERR_CRP_ENABLED: "ERR_CRP_ENABLED",
|
211 | }.get(cmdErr, "ERR_%d_ ???"%(cmdErr))
|
212 |
|
213 | #-------------------------------------------------------------------------------
|
214 | def sendCmd(cmd, dataResp=0):
|
215 |
|
216 | sendSerCrLf(cmd)
|
217 | if (echo != 0):
|
218 | cmdEcho = readSer()
|
219 | printVerbose(2,"ECHO: <"+cmdEcho+">")
|
220 |
|
221 | respCode = 0
|
222 | if cmd.startswith("G "):
|
223 | while (1):
|
224 | c = ser.read()
|
225 | if (c >= '0') and (c <= '9'):
|
226 | respCode = 10*respCode + (ord(c)-ord('0'))
|
227 | else:
|
228 | print("ERROR: response for G command broken")
|
229 | quit()
|
230 | else:
|
231 | respStr = readSer()
|
232 | respCode = int(respStr)
|
233 |
|
234 | if (respCode != 0):
|
235 | print("ERROR: command <%s> failed, ret=%s (%s)"%(cmd,respCode,cmdErr2Str(respCode)))
|
236 |
|
237 | return respCode
|
238 |
|
239 | #-------------------------------------------------------------------------------
|
240 | def Cmd_A(val):
|
241 | printVerbose(1,"Set Echo to %d"%(val))
|
242 | cmdStr = "A %d"%(val)
|
243 | cmdRet = sendCmd(cmdStr)
|
244 | if (cmdRet != CMD_SUCCESS):
|
245 | quit()
|
246 |
|
247 | global echo
|
248 | echo = val
|
249 |
|
250 | #-------------------------------------------------------------------------------
|
251 | def Cmd_C(addrFlash, addrRam, numBytes):
|
252 | printVerbose(1,"Copy %d byte from 0x%08x in RAM to 0x%08x in flash"%(numBytes,addrRam,addrFlash))
|
253 | cmdStr = "C %d %d %d"%(addrFlash,addrRam,numBytes)
|
254 | cmdRet = sendCmd(cmdStr)
|
255 | if (cmdRet != CMD_SUCCESS):
|
256 | quit()
|
257 |
|
258 | #-------------------------------------------------------------------------------
|
259 | def Cmd_E(startSector,endSector):
|
260 | printVerbose(1,"Erasing sector %d - %d"%(startSector,endSector))
|
261 | cmdStr = "E %d %d"%(startSector,endSector)
|
262 | cmdRet = sendCmd(cmdStr)
|
263 | if (cmdRet != CMD_SUCCESS):
|
264 | quit()
|
265 |
|
266 | #-------------------------------------------------------------------------------
|
267 | def Cmd_G(addr):
|
268 | # execute a program residing in RAM or flash memory. Sddress must
|
269 | # 0x00000200 or greater. "T" is thumb mode
|
270 | printVerbose(1,"Executing code at 0x%08x"%(addr))
|
271 | cmdStr = "G %d T"%(addr)
|
272 | cmdRet = sendCmd(cmdStr)
|
273 |
|
274 | #-------------------------------------------------------------------------------
|
275 | def Cmd_J():
|
276 | cmdRet = sendCmd("J")
|
277 | if (cmdRet != CMD_SUCCESS):
|
278 | quit()
|
279 | partID = int(readSer())
|
280 | return partID
|
281 |
|
282 |
|
283 | #-------------------------------------------------------------------------------
|
284 | def Cmd_K():
|
285 | cmdRet = sendCmd("K")
|
286 | if (cmdRet != CMD_SUCCESS):
|
287 | quit()
|
288 | bootRomMinor = int(readSer())
|
289 | bootRomMajor = int(readSer())
|
290 |
|
291 | return (bootRomMajor, bootRomMinor)
|
292 |
|
293 | #-------------------------------------------------------------------------------
|
294 | def Cmd_M(addr1,addr2,numBytes):
|
295 | printVerbose(1,"Compare %d bytes at 0x%08x and 0x%08x"%(numBytes,addr1,addr2))
|
296 | cmdStr = "M %d %d %d"%(addr1,addr2,numBytes)
|
297 | cmdRet = sendCmd(cmdStr)
|
298 | return cmdRet
|
299 |
|
300 | #-------------------------------------------------------------------------------
|
301 | def Cmd_N():
|
302 | cmdRet = sendCmd("N")
|
303 | if (cmdRet != CMD_SUCCESS):
|
304 | quit()
|
305 | uid1 = int(readSer())
|
306 | uid2 = int(readSer())
|
307 | uid3 = int(readSer())
|
308 | uid4 = int(readSer())
|
309 | return (uid1,uid2,uid3,uid4)
|
310 |
|
311 | #-------------------------------------------------------------------------------
|
312 | def Cmd_P(startSector,endSector):
|
313 | printVerbose(1,"Prepare sector %d - %d for write operation"%(startSector,endSector))
|
314 | cmdStr = "P %d %d"%(startSector,endSector)
|
315 | cmdRet = sendCmd(cmdStr)
|
316 | if (cmdRet != CMD_SUCCESS):
|
317 | quit()
|
318 |
|
319 | #-------------------------------------------------------------------------------
|
320 | def Cmd_R(addr,numBytes):
|
321 | printVerbose(1,"Read %d bytes from 0x%08x"%(numBytes,addr))
|
322 | cmdStr = "R %d %d"%(addr,numBytes)
|
323 | cmdRet = sendCmd(cmdStr,numBytes)
|
324 | if (cmdRet != CMD_SUCCESS):
|
325 | quit()
|
326 |
|
327 | data = []
|
328 | while (numBytes != 0):
|
329 | c = ord(ser.read())
|
330 | data.append(c)
|
331 | numBytes -= 1
|
332 |
|
333 | if (args.verbose >= 2):
|
334 | hexdump(data)
|
335 |
|
336 | return data
|
337 |
|
338 | #-------------------------------------------------------------------------------
|
339 | def Cmd_S(ramAddr,numBytes):
|
340 | printVerbose(1,"Read CRC checksum of block at 0x%08x len &d"%(ramAddr,numBytes))
|
341 | cmdStr = "S %d %d"%(ramAddr,numBytes)
|
342 | cmdRet = sendCmd(cmdStr)
|
343 | if (cmdRet != CMD_SUCCESS):
|
344 | quit()
|
345 | crc = int(readSer())
|
346 | return crc
|
347 |
|
348 | #-------------------------------------------------------------------------------
|
349 | def Cmd_U(val):
|
350 | printVerbose(1,"unlocking with code %d"%(val))
|
351 | cmdStr = "U %d"%(val)
|
352 | cmdRet = sendCmd(cmdStr)
|
353 | if (cmdRet != CMD_SUCCESS):
|
354 | quit()
|
355 |
|
356 | #-------------------------------------------------------------------------------
|
357 | def Cmd_W(addr,data):
|
358 | numBytes = len(data)
|
359 | printVerbose(1,"Write %d byte to RAM at 0x%08x"%(numBytes,addr))
|
360 |
|
361 | if (args.verbose >= 2):
|
362 | hexdump(data)
|
363 |
|
364 | cmdStr = "W %d %d"%(addr,numBytes)
|
365 | cmdRet = sendCmd(cmdStr)
|
366 | if (cmdRet != CMD_SUCCESS):
|
367 | quit()
|
368 |
|
369 | ser.write(data)
|
370 |
|
371 | #-------------------------------------------------------------------------------
|
372 | def getPartName(partID):
|
373 | return { 0x00008100: "LPC810M021FN8",
|
374 | # 0x00008110: "LPC811M001JDH16",
|
375 | # 0x00008120: "LPC812M101JDH16",
|
376 | # 0x00008121: "LPC812M101JD20",
|
377 | # 0x00008122: "LPC812M101JDH20"
|
378 | }.get(partID, "")
|
379 |
|
380 | #-------------------------------------------------------------------------------
|
381 | def unlock():
|
382 | UNLOCK_MAGIC = 23130 # magic value
|
383 | Cmd_U(UNLOCK_MAGIC)
|
384 |
|
385 |
|
386 | #-------------------------------------------------------------------------------
|
387 | def printInfo():
|
388 |
|
389 | partID = Cmd_J()
|
390 | (uid1,uid2,uid3,uid4) = Cmd_N()
|
391 | (bootRomMajor, bootRomMinor) = Cmd_K()
|
392 |
|
393 | partName = getPartName(partID);
|
394 | partNameStr = partName
|
395 | if (partNameStr == ""):
|
396 | partNameStr = "unknown"
|
397 |
|
398 | print("Device:")
|
399 | print(" PartID: 0x%08x (%s)"%(partID,partNameStr))
|
400 | print(" UID: %08x-%08x-%08x-%08x"%(uid1,uid2,uid3,uid4))
|
401 | print(" Boot Loder: V%d.%d"%(bootRomMajor,bootRomMinor))
|
402 |
|
403 |
|
404 | #-------------------------------------------------------------------------------
|
405 | def checkIfSupportedCotroller():
|
406 | partID = Cmd_J()
|
407 | partName = getPartName(partID);
|
408 | if (partName == ""):
|
409 | printInfo()
|
410 | quit()
|
411 |
|
412 |
|
413 |
|
414 | #-------------------------------------------------------------------------------
|
415 | def init():
|
416 | # serial setting: 8 data bits, 1 stop bit, no parity.
|
417 | # Device detects baud rate automatically when host sends "?" (0x3F) as the
|
418 | # first character. ASCII string "Synchronized"+CR+LF is send back then with
|
419 | # the detected baud rate. Host must send the same "Synchronized"+CR+LF
|
420 | # back, so device can verify the baud rate. If synchronization is verified
|
421 | # then device sends "OK"+CR+LF.
|
422 | # Then host must send the crystal frequency (in kHz) at which the part is
|
423 | # running. The response is required for backward compatibility of the boot
|
424 | # loader code. On the LPC800 it is ignored, boot loader configures 12 MHz
|
425 | # IRC frequency.
|
426 | # Now ISP command handler is invoked. For safety reasons an "Unlock"
|
427 | # command is required before executing the commands resulting in flash
|
428 | # erase/write operations and the "Go" command. The rest of the commands
|
429 | # can be executed without the unlock command. The Unlock command is
|
430 | # required to be executed once per ISP session.
|
431 |
|
432 | isEcho = 1
|
433 | syncStr = "Synchronized"
|
434 |
|
435 | ser.flushInput()
|
436 | ser.flushOutput()
|
437 |
|
438 | ser.timeout = 2
|
439 | sendSer("?")
|
440 | j = readSer()
|
441 | ser.timeout = 1
|
442 | if j == syncStr:
|
443 | print("LPC8xx ISP setup")
|
444 | sendSerCrLf(syncStr)
|
445 | readSer() # cmd echo
|
446 | readSer() # "OK"
|
447 | sendSerCrLf("12") # backwards compatibility dummy
|
448 | readSer() # cmd echo
|
449 | readSer() # "OK"
|
450 | else:
|
451 | sendSerCrLf("")
|
452 | c = readSer()
|
453 | if (j != "?"):
|
454 | # already in ISP more with echo off?
|
455 | isEcho = 0
|
456 | else:
|
457 | # already in ISP more with echo on?
|
458 | if (c != ""):
|
459 | print("LPC8xx ISP mode error 1, read: <"+c+">")
|
460 | quit()
|
461 | c = readSer()
|
462 |
|
463 | if (c != "1"):
|
464 | print("LPC8xx ISP mode error 2, read: <"+c+">")
|
465 | quit()
|
466 |
|
467 | global echo
|
468 | echo = isEcho
|
469 |
|
470 | # try echo off command
|
471 | Cmd_A(0)
|
472 |
|
473 | print("LPC8xx ISP ready")
|
474 |
|
475 |
|
476 | #-------------------------------------------------------------------------------
|
477 | def calcChecksum(data):
|
478 |
|
479 | # The reserved Cortex-M0+ exception vector (offset 0x1C) contains the
|
480 | # 2-complement of the check-sum of vector table entries 0 through 6. This
|
481 | # causes the checksum of the first 8 table entries to be 0. The bootloader
|
482 | # code checksums the first 8 locations in sector 0 of the flash. If the
|
483 | # result is 0, then execution control is transferred to the user code.
|
484 |
|
485 | dlen = len(data)
|
486 | if (dlen < ADDR_CHECKSUM+4):
|
487 | print("Error: not enough data to insert the checksum")
|
488 | quit()
|
489 |
|
490 | sig = 0
|
491 | for v in range(0, 7):
|
492 | sig += get_uint32_le(data, 4*v)
|
493 |
|
494 | sig ^= 0xffffffff
|
495 | sig += 1
|
496 |
|
497 | print("setting checksum: 0x%08x"%(sig))
|
498 |
|
499 | set_uint32_le(data,ADDR_CHECKSUM,sig)
|
500 |
|
501 |
|
502 | #-------------------------------------------------------------------------------
|
503 | def checkCrp(data):
|
504 |
|
505 | # Code Read Protection (CRP)
|
506 | # any CRP change becomes effective in the next power cycle.
|
507 | #
|
508 | # CRP User ISP entry SWD Enters partial flash
|
509 | # Code pin at enabled ISP mode update in
|
510 | # Valid reset ISP mode
|
511 | #
|
512 | # None No x Yes Yes Yes
|
513 | # None Yes High Yes No NA
|
514 | # None Yes Low Yes Yes Yes
|
515 | # CRP1 Yes High No No NA
|
516 | # CRP1 Yes Low No Yes Yes
|
517 | # CRP2 Yes High No No NA
|
518 | # CRP2 Yes Low No Yes No
|
519 | # CRP3 Yes x No No NA
|
520 | # CRP1 No x No Yes Yes
|
521 | # CRP2 No x No Yes No
|
522 | # CRP3 No x No Yes No
|
523 |
|
524 |
|
525 | dlen = len(data)
|
526 | if (dlen >= ADDR_CRP+4):
|
527 | crp = get_uint32_le(data,ADDR_CRP)
|
528 | if (crp in [NO_ISP, CRP1, CRP2, CRP3]):
|
529 | print("Error: found CRP-Magic word 0x%08x"%(magic))
|
530 | quit()
|
531 |
|
532 |
|
533 | #-------------------------------------------------------------------------------
|
534 | def flash(image):
|
535 |
|
536 | data = bytearray(image.read())
|
537 | image.close()
|
538 |
|
539 | dlen = len(data)
|
540 | if (0 == dlen):
|
541 | print("no data found")
|
542 | quit()
|
543 |
|
544 | sectEnd = (dlen-1)/1024
|
545 | pageCnt = (dlen + 63) / 64
|
546 | rlen = pageCnt * 64
|
547 |
|
548 | data += bytearray(rlen-dlen) # add padding
|
549 |
|
550 | checkCrp(data)
|
551 | calcChecksum(data)
|
552 |
|
553 | print("flashing %d byte (%d pages)"%(dlen, pageCnt))
|
554 |
|
555 | unlock()
|
556 | Cmd_P(0,sectEnd)
|
557 | Cmd_E(0,sectEnd)
|
558 |
|
559 | tmpRamAddr = 0x10000000
|
560 | dataOffset = 0
|
561 | flashAddr = 0
|
562 | blockLen = 64
|
563 |
|
564 | while (dataOffset < dlen):
|
565 | if (args.verbose == 0):
|
566 | sys.stdout.write(".")
|
567 | sys.stdout.flush()
|
568 | else:
|
569 | printVerbose(1,"Write block: 0x%08x"%(flashAddr))
|
570 |
|
571 | Cmd_P(0,sectEnd)
|
572 |
|
573 | Cmd_W(tmpRamAddr,data[dataOffset:dataOffset+blockLen])
|
574 | Cmd_R(tmpRamAddr,blockLen)
|
575 |
|
576 | Cmd_C(flashAddr,tmpRamAddr,blockLen)
|
577 | Cmd_R(flashAddr,blockLen)
|
578 |
|
579 | flashAddr += blockLen
|
580 | dataOffset += blockLen
|
581 |
|
582 | if (args.verbose == 0):
|
583 | print("done")
|
584 |
|
585 | print("%d bytes were written"%(dlen))
|
586 |
|
587 | #-------------------------------------------------------------------------------
|
588 | def systemReset():
|
589 |
|
590 | print("resetting device...")
|
591 |
|
592 | # issue system reset as described in in LPC800 user manual section 22.5.1.8
|
593 | # AIRCR_VECTKEY = (0x05FA << 8) // magic number
|
594 | # AIRCR_SYSRESETREQ = (1U << 2) // request reset
|
595 | # LPC8xx_SCS->AIRCR = (AIRCR_VECTKEY << 8) | AIRCR_SYSRESETREQ;
|
596 |
|
597 | data = []
|
598 | append_uint16_le(data,0x4a01) # 00: ldr r0, [pc, #4] ; r0 = [08]
|
599 | append_uint16_le(data,0x4b02) # 02: ldr r1, [pc, #8] ; r0 = [0c]
|
600 | append_uint16_le(data,0x601a) # 04: str r0, [r1] ; write
|
601 | append_uint16_le(data,0xe7fe) # 06: b . ; dummy failsafe loop
|
602 | append_uint32_le(data,0xe000ed0c) # 08: .word 0x05fa0004 ; (VECTKEY << 8) | SYSRESETREQ
|
603 | append_uint32_le(data,0x05fa0004) # 0c: .word 0xe000ed0c ; &(LPC8xx_SCS->AIRCR)
|
604 |
|
605 | Cmd_W(0x10000000, bytearray(data))
|
606 | unlock();
|
607 | Cmd_G(0x10000000)
|
608 |
|
609 | #-------------------------------------------------------------------------------
|
610 | if __name__ == '__main__':
|
611 | parser = argparse.ArgumentParser()
|
612 | parser.add_argument("-p", dest="port", default="/dev/ttyUSB0", help="serial/USB port, default is /dev/ttyUSB0")
|
613 | parser.add_argument('--verbose', '-v', default=0, action='count', help="verbosity level, -v or -vv or -vvv ...")
|
614 | parser.add_argument("--reset", '-r', action='store_true', help="reset target")
|
615 | parser.add_argument("--dump", action='store_true', help="dump Flash and RAM")
|
616 | parser.add_argument("image", nargs="?", type=argparse.FileType('rt'), help="image to flash")
|
617 |
|
618 | args = parser.parse_args()
|
619 | if (args.verbose > 0):
|
620 | print(args)
|
621 |
|
622 | try:
|
623 | ser = serial.Serial(args.port,
|
624 | baudrate=115200, bytesize=8, parity='N', stopbits=1,
|
625 | timeout=10, xonxoff=0, rtscts=0)
|
626 | except serial.serialutil.SerialException as e:
|
627 | print("Error: %s"%e)
|
628 | quit()
|
629 | except:
|
630 | print("Error: %s"%sys.exc_info()[0])
|
631 | quit()
|
632 |
|
633 | init()
|
634 | checkIfSupportedCotroller()
|
635 | printInfo()
|
636 |
|
637 | if (args.dump):
|
638 | print("RAM dump (first 0x80 survive reset):")
|
639 | data = Cmd_R(0x10000000, 0x400)
|
640 | hexdump(data," ")
|
641 | print("Flash dump:")
|
642 | data = Cmd_R(0x00000000, 0x1000)
|
643 | print(" Image checksum at 0x%08x: 0x%08x"%(ADDR_CHECKSUM,get_uint32_le(data,ADDR_CHECKSUM)))
|
644 | print(" CRP at 0x%08x: 0x%08x"%(ADDR_CRP,get_uint32_le(data,ADDR_CRP)))
|
645 | hexdump(data," ")
|
646 | #else:
|
647 | # print("RAM dump of contents surviving a reset:")
|
648 | # data = Cmd_R(0x10000000, 80)
|
649 | # hexdump(data," ")
|
650 |
|
651 | if (args.image):
|
652 | flash(args.image)
|
653 |
|
654 | if (args.reset):
|
655 | systemReset()
|