From: Joseph Coffland Date: Sat, 14 Jan 2017 08:55:23 +0000 (-0800) Subject: Added AVR programming script X-Git-Url: https://git.buildbotics.com/?a=commitdiff_plain;h=ff6596c5c73711c0ffb8a299394b95d0e21896b9;p=bbctrl-firmware Added AVR programming script --- diff --git a/scripts/avr109-flash.py b/scripts/avr109-flash.py new file mode 100755 index 0000000..f151dad --- /dev/null +++ b/scripts/avr109-flash.py @@ -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')