Added AVR programming script
authorJoseph Coffland <joseph@cauldrondevelopment.com>
Sat, 14 Jan 2017 08:55:23 +0000 (00:55 -0800)
committerJoseph Coffland <joseph@cauldrondevelopment.com>
Sat, 14 Jan 2017 08:55:23 +0000 (00:55 -0800)
scripts/avr109-flash.py [new file with mode: 0755]

diff --git a/scripts/avr109-flash.py b/scripts/avr109-flash.py
new file mode 100755 (executable)
index 0000000..f151dad
--- /dev/null
@@ -0,0 +1,162 @@
+#!/usr/bin/env python3
+
+import sys
+import time
+import serial
+import binascii
+from subprocess import call
+
+
+dev = '/dev/ttyAMA0'
+baud = 115200
+boot_id = 'bbctrl '
+verbose = False
+
+
+def crc16(data):
+    crc = 0xffff
+
+    for x in data:
+        crc = crc ^ int(x)
+        for bit in range(8):
+            if crc & 1: crc = (crc >> 1) ^ 0xa001
+            else: crc = crc >> 1
+
+    return crc
+
+
+def read_intel_hex(f):
+    base = 0
+    pos = 0
+    start = 0
+    chunk = None
+
+    for line in f:
+        line = line.strip()
+        if not line or line[0] != ':': continue
+
+        count = int(line[1:3], 16)
+        addr = int(line[3:7], 16)
+        type = int(line[7:9], 16)
+        data = line[9:-2]
+        checksum = int(line[-2:], 16)
+
+        if type == 0:
+            addr += base
+            data = binascii.unhexlify(bytes(data, 'utf8'))
+
+            if chunk is None or pos != addr:
+                if chunk is not None: yield (start, chunk)
+                start = addr
+                chunk = data
+
+            else: chunk += data
+
+            pos = addr + len(data)
+
+        if type == 2: base = int(data, 16) * 16
+
+    if chunk is not None: yield (start, chunk)
+
+
+def send(data):
+    if verbose: print('Sending:', data)
+    sp.write(bytes(data, 'utf8'))
+
+
+def send_int(x, size):
+    if verbose: print('Sending: %d', x)
+    sp.write((x).to_bytes(size, byteorder = 'big'))
+
+
+def recv(count):
+    data = sp.read(count).decode('utf8')
+    if count and verbose: print('Received:', data)
+    return data
+
+
+def recv_int(size):
+    x = int.from_bytes(sp.read(size), byteorder = 'big')
+    if verbose: print('Received:', x)
+    return x
+
+
+# Read firmware hex file
+data = read_intel_hex(open(sys.argv[1], 'r'))
+
+# Open serial  port
+sp = serial.Serial(dev, baud, timeout = 10)
+
+# Reset AVR
+call(['gpio', '-g', 'write', '27', '0'])
+call(['gpio', '-g', 'write', '27', '1'])
+time.sleep(0.1)
+
+# Sync
+send('\x1b')
+
+# Flush serial
+recv(sp.in_waiting)
+
+# Get bootloader ID
+send('S')
+if boot_id != recv(len(boot_id)):
+    raise Exception('Failed to communicate with bootloader')
+
+# Get page size
+send('b')
+if recv(1) != 'Y': raise Exception('Cannot get page size')
+page_size = recv_int(2)
+print('Page size:', page_size)
+
+# Program
+print('Programming', end = '')
+count = 0
+retry = 0
+for addr, chunk in data:
+    # Set address
+    send('H')
+    send_int(addr, 3)
+    if recv(1) != '\r': raise Exception('Failed to set address')
+
+    while len(chunk):
+        sys.stdout.flush()
+        page = chunk[0:512]
+
+        # Block command
+        send('B')
+
+        # Send block size
+        send_int(len(page), 2)
+
+        # Send memory type
+        send('F')
+
+        # Send block
+        sp.write(page)
+
+        if recv(1) != '\r': raise Exception('Failed to write block')
+
+        # Get and check block CRC
+        send('i')
+        crc = recv_int(2)
+        expect = crc16(page)
+        if crc != expect:
+            retry += 1
+            if retry == 5:
+                raise Exception('CRC mismatch %d != %d' % (crc, expect))
+
+            print('x', end = '')
+            continue
+
+        count += len(page)
+        chunk = chunk[512:]
+        retry = 0
+        print('.', end = '')
+
+
+print('done')
+print('Wrote %d bytes' % count)
+
+# Exit bootloader
+send('E')