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