flushmagic.py


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)