Verison 1.0.3 Release
Based on Buildbotics 0.4.14
This commit is contained in:
206
scripts/avr109-flash.py
Normal file
206
scripts/avr109-flash.py
Normal file
@@ -0,0 +1,206 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import time
|
||||
import serial
|
||||
import binascii
|
||||
|
||||
|
||||
dev = '/dev/ttyAMA0'
|
||||
baud = 921600
|
||||
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 avr_crc32(data, length):
|
||||
mem = [0xff] * length
|
||||
|
||||
for addr, chunk in data:
|
||||
for x in chunk:
|
||||
mem[addr] = x
|
||||
addr += 1
|
||||
|
||||
return binascii.crc32(bytes(mem))
|
||||
|
||||
|
||||
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 = list(read_intel_hex(open(sys.argv[1], 'r')))
|
||||
|
||||
# Open serial port
|
||||
sp = serial.Serial(dev, baud, timeout = 10)
|
||||
|
||||
# Reset AVR
|
||||
import RPi.GPIO as gpio
|
||||
gpio.setwarnings(False)
|
||||
gpio.setmode(gpio.BCM)
|
||||
gpio.setup(27, gpio.OUT)
|
||||
gpio.output(27, 0)
|
||||
gpio.output(27, 1)
|
||||
gpio.setup(27, gpio.IN, pull_up_down = gpio.PUD_UP)
|
||||
time.sleep(0.1)
|
||||
|
||||
# Sync
|
||||
for i in range(10): send('\x1b')
|
||||
|
||||
# Flush serial
|
||||
try:
|
||||
recv(sp.in_waiting)
|
||||
except: pass
|
||||
|
||||
# Get bootloader ID
|
||||
send('S')
|
||||
if boot_id != recv(len(boot_id)):
|
||||
raise Exception('Failed to communicate with bootloader')
|
||||
|
||||
# Get version
|
||||
send('V')
|
||||
major = int(recv(1))
|
||||
minor = int(recv(1))
|
||||
print('Bootloader version: %d.%d' % (major, minor))
|
||||
|
||||
# If bootloader is new enough compare checksums
|
||||
if 0 < major or 1 < minor:
|
||||
# Get flash length
|
||||
send('n')
|
||||
flash_len = recv_int(3)
|
||||
|
||||
# Get current flash CRC
|
||||
send('X')
|
||||
new_crc = avr_crc32(data, flash_len)
|
||||
old_crc = recv_int(4)
|
||||
if old_crc == new_crc:
|
||||
print('Flash already up to date')
|
||||
sys.exit(0)
|
||||
|
||||
print('CRC: old=0x%08x new=0x%08x' % (old_crc, new_crc))
|
||||
|
||||
# Erase
|
||||
send('e')
|
||||
if recv(1) != '\r': raise Exception('Flash erase failed')
|
||||
|
||||
# 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')
|
||||
Reference in New Issue
Block a user