LPC1114 Cortex-M0 hacks.

prog.py 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. import serial
  2. import sys
  3. import time
  4. import binascii
  5. import random
  6. import pprint
  7. import collections
  8. import struct
  9. import elffile
  10. class Error(Exception):
  11. pass
  12. RETURN_CODE = {
  13. 0: 'CMD_SUCCESS',
  14. 1: 'INVALID_COMMAND',
  15. 2: 'SRC_ADDR_ERROR',
  16. 3: 'DST_ADDR_ERROR',
  17. 4: 'SRC_ADDR_NOT_MAPPED',
  18. 5: 'DST_ADDR_NOT_MAPPED',
  19. 6: 'COUNT_ERROR',
  20. 7: 'INVALID_SECTOR',
  21. 8: 'SECTOR_NOT_BLANK',
  22. 9: 'SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION',
  23. 10: 'COMPARE_ERROR',
  24. 11: 'BUSY',
  25. 12: 'PARAM_ERROR',
  26. 13: 'ADDR_ERROR',
  27. 14: 'ADDR_NOT_MAPPED',
  28. 15: 'CMD_LOCKED',
  29. 16: 'INVALID_CODE',
  30. 17: 'INVALID_BAUD_RATE',
  31. 18: 'INVALID_STOP_BIT',
  32. 19: 'CODE_READ_PROTECTION_ENABLED ',
  33. }
  34. Section = collections.namedtuple('Section', 'name address content')
  35. def fix_vectors(data):
  36. """Patch the vector table so the bootloader recognises the code
  37. as valid. Sum of the first eight is zero.
  38. """
  39. first = data[:4*7]
  40. remainder = data[4*8:]
  41. vectors = struct.unpack('<IIIIIII', first)
  42. last = -sum(vectors) & 0xFFFFFFFF
  43. return first + struct.pack('<I', last) + remainder
  44. class ELFReader:
  45. """Reads an ELF file into sections."""
  46. def __init__(self, name):
  47. elf = elffile.open(name)
  48. self.entry = elf.fileHeader.entry
  49. self.sections = []
  50. for header in elf.sectionHeaders:
  51. if header.name in ['.text', '.data', '.vectors']:
  52. content = header.content
  53. if header.name == '.vectors':
  54. content = fix_vectors(content)
  55. self.sections.append(Section(header.name, header.addr, content))
  56. class Loader:
  57. """Talk with a LPC1114 over the serial bootloader protocol."""
  58. SYNCHRONIZED = 'Synchronized\r\n'
  59. OK = 'OK\r\n'
  60. def __init__(self, port='/dev/ttyUSB0', verbose=True):
  61. self.verbose = verbose
  62. self.port = serial.Serial(port, 115200, timeout=0.5)
  63. def log(self, msg, eol=True):
  64. if self.verbose:
  65. if eol:
  66. print msg
  67. else:
  68. print msg,
  69. def set_reset(self, level):
  70. self.port.setDTR(level == 0)
  71. def set_bsl(self, level):
  72. self.port.setRTS(level == 0)
  73. def run(self):
  74. self.set_bsl(1)
  75. self.set_reset(1)
  76. self.set_reset(0)
  77. self.set_reset(1)
  78. def sync(self):
  79. for tries in range(3):
  80. self.set_bsl(0)
  81. self.set_reset(1)
  82. self.set_reset(0)
  83. self.set_reset(1)
  84. self.read(100)
  85. self.write('?')
  86. got = self.read(len(self.SYNCHRONIZED))
  87. if got == self.SYNCHRONIZED:
  88. self.send('Synchronized')
  89. got = self.read(len(self.OK))
  90. if got == self.OK:
  91. self.send('12000')
  92. got = self.read(len(self.OK))
  93. if got == self.OK:
  94. self.log(self.execute('N', (int, int, int, int)))
  95. return
  96. def load(self, address, data):
  97. chunk = 512
  98. per_line = 45
  99. for offset in range(0, len(data), 512):
  100. part = data[offset:offset+512]
  101. self.send('W %d %d' % (address + offset, len(part)))
  102. self.check_ok()
  103. for micro in range(0, len(part), per_line):
  104. encoded = binascii.b2a_uu(part[micro:micro+per_line])
  105. assert encoded.endswith('\n')
  106. encoded = encoded[:-1]
  107. self.send(encoded)
  108. check = sum(ord(x) for x in part)
  109. self.send('%d' % check)
  110. got = self.readline()
  111. if got == 'OK':
  112. pass
  113. elif got == 'RESEND':
  114. raise Error('Checksum error on write')
  115. else:
  116. raise Error('Protocol error')
  117. def prepare(self, first, last=None):
  118. if last == None:
  119. last = first
  120. self.execute('P', (), first, last)
  121. def erase(self, first, last=None):
  122. if last == None:
  123. last = first
  124. self.prepare(first, last)
  125. self.execute('E', (), first, last)
  126. def program(self, address, data):
  127. page_size = 256
  128. chunk = 512
  129. load_address = 0x10000400
  130. if address % page_size != 0:
  131. raise Error('Address must be page size aligned')
  132. remainder = len(data) % page_size
  133. if remainder != 0:
  134. data += '\xff' * (page_size - remainder)
  135. assert len(data) % page_size == 0
  136. for offset in range(0, len(data), chunk):
  137. part = data[offset:offset+chunk]
  138. self.load(load_address, part)
  139. self.prepare(0)
  140. self.execute('C', (), address + offset, load_address, len(part))
  141. def go(self, address):
  142. self.execute('G', (), address, 'T')
  143. for tries in range(5):
  144. try:
  145. self.execute('J', (int, ))
  146. break
  147. except Error:
  148. self.read(100)
  149. time.sleep(0.1)
  150. def unlock(self):
  151. self.execute('U', (), 23130)
  152. def check_ok(self):
  153. code = self.readline()
  154. try:
  155. code = int(code)
  156. except ValueError:
  157. raise Error('Invalid result code')
  158. if code != 0:
  159. raise Error(RETURN_CODE[code])
  160. def execute(self, command, result, *kargs):
  161. send = command
  162. for arg in kargs:
  163. send += ' %s' % arg
  164. self.send(send)
  165. self.check_ok()
  166. values = []
  167. for t in result:
  168. values.append(t(self.readline()))
  169. return values
  170. def readline(self):
  171. v = ''
  172. self.log('<', eol=False)
  173. try:
  174. while True:
  175. got = self.read(1, True)
  176. if got == '':
  177. raise Error('No response')
  178. if got == '\r':
  179. got = self.read(1, True)
  180. if got == '\n':
  181. return v
  182. else:
  183. v += got
  184. finally:
  185. self.log('')
  186. def write(self, v):
  187. self.log('> %r' % v)
  188. self.port.write(v)
  189. def send(self, v):
  190. v += '\r\n'
  191. self.write(v)
  192. got = self.read(len(v))
  193. if got != v:
  194. raise Error('Echo error. Sent %r, got %r' % (v, got))
  195. def read(self, limit, partial=False):
  196. got = self.port.read(limit)
  197. if partial:
  198. self.log('%r' % got, eol=False)
  199. else:
  200. self.log('< %r' % got)
  201. return got
  202. def main():
  203. loader = Loader()
  204. loader.sync()
  205. loader.unlock()
  206. loader.erase(0)
  207. for arg in sys.argv[1:]:
  208. data = ELFReader(arg)
  209. for section in data.sections:
  210. loader.program(section.address, section.content)
  211. loader.sync()
  212. loader.run()
  213. # loader.unlock()
  214. # loader.go(data.entry)
  215. if __name__ == '__main__':
  216. main()