|
|
@@ -5,6 +5,7 @@ import binascii
|
|
5
|
5
|
import random
|
|
6
|
6
|
import pprint
|
|
7
|
7
|
import collections
|
|
|
8
|
+import struct
|
|
8
|
9
|
|
|
9
|
10
|
import elffile
|
|
10
|
11
|
|
|
|
@@ -36,7 +37,20 @@ RETURN_CODE = {
|
|
36
|
37
|
|
|
37
|
38
|
Section = collections.namedtuple('Section', 'name address content')
|
|
38
|
39
|
|
|
|
40
|
+def fix_vectors(data):
|
|
|
41
|
+ """Patch the vector table so the bootloader recognises the code
|
|
|
42
|
+ as valid. Sum of the first eight is zero.
|
|
|
43
|
+ """
|
|
|
44
|
+ first = data[:4*7]
|
|
|
45
|
+ remainder = data[4*8:]
|
|
|
46
|
+
|
|
|
47
|
+ vectors = struct.unpack('<IIIIIII', first)
|
|
|
48
|
+ last = -sum(vectors) & 0xFFFFFFFF
|
|
|
49
|
+
|
|
|
50
|
+ return first + struct.pack('<I', last) + remainder
|
|
|
51
|
+
|
|
39
|
52
|
class ELFReader:
|
|
|
53
|
+ """Reads an ELF file into sections."""
|
|
40
|
54
|
def __init__(self, name):
|
|
41
|
55
|
elf = elffile.open(name)
|
|
42
|
56
|
|
|
|
@@ -44,17 +58,24 @@ class ELFReader:
|
|
44
|
58
|
self.sections = []
|
|
45
|
59
|
|
|
46
|
60
|
for header in elf.sectionHeaders:
|
|
47
|
|
- if header.name in ['.text', '.data']:
|
|
48
|
|
- self.sections.append(Section(header.name, header.addr, header.content))
|
|
|
61
|
+ if header.name in ['.text', '.data', '.vectors']:
|
|
|
62
|
+ content = header.content
|
|
|
63
|
+
|
|
|
64
|
+ if header.name == '.vectors':
|
|
|
65
|
+ content = fix_vectors(content)
|
|
|
66
|
+
|
|
|
67
|
+ self.sections.append(Section(header.name, header.addr, content))
|
|
49
|
68
|
|
|
50
|
69
|
class Loader:
|
|
|
70
|
+ """Talk with a LPC1114 over the serial bootloader protocol."""
|
|
|
71
|
+
|
|
51
|
72
|
SYNCHRONIZED = 'Synchronized\r\n'
|
|
52
|
73
|
OK = 'OK\r\n'
|
|
53
|
74
|
|
|
54
|
|
- def __init__(self, verbose=False):
|
|
|
75
|
+ def __init__(self, port='/dev/ttyUSB0', verbose=True):
|
|
55
|
76
|
self.verbose = verbose
|
|
56
|
77
|
|
|
57
|
|
- self.port = serial.Serial('/dev/ttyUSB0', 115200, timeout=0.5)
|
|
|
78
|
+ self.port = serial.Serial(port, 115200, timeout=0.5)
|
|
58
|
79
|
|
|
59
|
80
|
def log(self, msg, eol=True):
|
|
60
|
81
|
if self.verbose:
|
|
|
@@ -69,6 +90,12 @@ class Loader:
|
|
69
|
90
|
def set_bsl(self, level):
|
|
70
|
91
|
self.port.setRTS(level == 0)
|
|
71
|
92
|
|
|
|
93
|
+ def run(self):
|
|
|
94
|
+ self.set_bsl(1)
|
|
|
95
|
+ self.set_reset(1)
|
|
|
96
|
+ self.set_reset(0)
|
|
|
97
|
+ self.set_reset(1)
|
|
|
98
|
+
|
|
72
|
99
|
def sync(self):
|
|
73
|
100
|
for tries in range(3):
|
|
74
|
101
|
self.set_bsl(0)
|
|
|
@@ -123,6 +150,40 @@ class Loader:
|
|
123
|
150
|
else:
|
|
124
|
151
|
raise Error('Protocol error')
|
|
125
|
152
|
|
|
|
153
|
+ def prepare(self, first, last=None):
|
|
|
154
|
+ if last == None:
|
|
|
155
|
+ last = first
|
|
|
156
|
+
|
|
|
157
|
+ self.execute('P', (), first, last)
|
|
|
158
|
+
|
|
|
159
|
+ def erase(self, first, last=None):
|
|
|
160
|
+ if last == None:
|
|
|
161
|
+ last = first
|
|
|
162
|
+
|
|
|
163
|
+ self.prepare(first, last)
|
|
|
164
|
+ self.execute('E', (), first, last)
|
|
|
165
|
+
|
|
|
166
|
+ def program(self, address, data):
|
|
|
167
|
+ page_size = 256
|
|
|
168
|
+ chunk = 512
|
|
|
169
|
+ load_address = 0x10000400
|
|
|
170
|
+
|
|
|
171
|
+ if address % page_size != 0:
|
|
|
172
|
+ raise Error('Address must be page size aligned')
|
|
|
173
|
+
|
|
|
174
|
+ remainder = len(data) % page_size
|
|
|
175
|
+
|
|
|
176
|
+ if remainder != 0:
|
|
|
177
|
+ data += '\xff' * (page_size - remainder)
|
|
|
178
|
+
|
|
|
179
|
+ assert len(data) % page_size == 0
|
|
|
180
|
+
|
|
|
181
|
+ for offset in range(0, len(data), chunk):
|
|
|
182
|
+ part = data[offset:offset+chunk]
|
|
|
183
|
+ self.load(load_address, part)
|
|
|
184
|
+ self.prepare(0)
|
|
|
185
|
+ self.execute('C', (), address + offset, load_address, len(part))
|
|
|
186
|
+
|
|
126
|
187
|
def go(self, address):
|
|
127
|
188
|
self.execute('G', (), address, 'T')
|
|
128
|
189
|
|
|
|
@@ -138,7 +199,15 @@ class Loader:
|
|
138
|
199
|
self.execute('U', (), 23130)
|
|
139
|
200
|
|
|
140
|
201
|
def check_ok(self):
|
|
141
|
|
- assert self.readline() == '0'
|
|
|
202
|
+ code = self.readline()
|
|
|
203
|
+
|
|
|
204
|
+ try:
|
|
|
205
|
+ code = int(code)
|
|
|
206
|
+ except ValueError:
|
|
|
207
|
+ raise Error('Invalid result code')
|
|
|
208
|
+
|
|
|
209
|
+ if code != 0:
|
|
|
210
|
+ raise Error(RETURN_CODE[code])
|
|
142
|
211
|
|
|
143
|
212
|
def execute(self, command, result, *kargs):
|
|
144
|
213
|
send = command
|
|
|
@@ -147,11 +216,7 @@ class Loader:
|
|
147
|
216
|
send += ' %s' % arg
|
|
148
|
217
|
|
|
149
|
218
|
self.send(send)
|
|
150
|
|
-
|
|
151
|
|
- code = int(self.readline())
|
|
152
|
|
-
|
|
153
|
|
- if code != 0:
|
|
154
|
|
- raise Error(RETURN_CODE[code])
|
|
|
219
|
+ self.check_ok()
|
|
155
|
220
|
|
|
156
|
221
|
values = []
|
|
157
|
222
|
|
|
|
@@ -210,13 +275,18 @@ def main():
|
|
210
|
275
|
loader.sync()
|
|
211
|
276
|
loader.unlock()
|
|
212
|
277
|
|
|
|
278
|
+ loader.erase(0)
|
|
|
279
|
+
|
|
213
|
280
|
for arg in sys.argv[1:]:
|
|
214
|
281
|
data = ELFReader(arg)
|
|
215
|
282
|
|
|
216
|
283
|
for section in data.sections:
|
|
217
|
|
- loader.load(section.address, section.content)
|
|
|
284
|
+ loader.program(section.address, section.content)
|
|
218
|
285
|
|
|
219
|
|
- loader.go(data.entry)
|
|
|
286
|
+ loader.sync()
|
|
|
287
|
+ loader.run()
|
|
|
288
|
+# loader.unlock()
|
|
|
289
|
+# loader.go(data.entry)
|
|
220
|
290
|
|
|
221
|
291
|
if __name__ == '__main__':
|
|
222
|
292
|
main()
|