Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 56 additions & 49 deletions stm32loader.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3

# -*- coding: utf-8 -*-
# vim: sw=4:ts=4:si:et:enc=utf-8
Expand All @@ -25,6 +25,8 @@
import sys, getopt
import serial
import time
from functools import reduce # add this at the top


try:
from progressbar import *
Expand All @@ -50,7 +52,7 @@

def mdebug(level, message):
if(QUIET >= level):
print >> sys.stderr , message
print(message, file=sys.stderr)


class CmdException(Exception):
Expand All @@ -59,7 +61,7 @@ class CmdException(Exception):
class CommandInterface:
extended_erase = 0

def open(self, aport='/dev/tty.usbserial-ftCYPMYJ', abaudrate=115200) :
def open(self, aport='/dev/ttyUSB0', abaudrate=115200) :
self.sp = serial.Serial(
port=aport,
baudrate=abaudrate, # baudrate
Expand All @@ -75,7 +77,10 @@ def open(self, aport='/dev/tty.usbserial-ftCYPMYJ', abaudrate=115200) :
def _wait_for_ask(self, info = ""):
# wait for ask
try:
ask = ord(self.sp.read())
data = self.sp.read(1)
if not data:
raise CmdException("Can't read port or timeout")
ask = data[0]
except:
raise CmdException("Can't read port or timeout")
else:
Expand All @@ -102,25 +107,25 @@ def initChip(self):
self.sp.setRTS(0)
self.reset()

self.sp.write("\x7F") # Syncro
self.sp.write(b"\x7F") # Syncro
return self._wait_for_ask("Syncro")

def releaseChip(self):
self.sp.setRTS(1)
self.reset()

def cmdGeneric(self, cmd):
self.sp.write(chr(cmd))
self.sp.write(chr(cmd ^ 0xFF)) # Control byte
self.sp.write(bytes([cmd]))
self.sp.write(bytes([cmd ^ 0xFF])) # Control byte
return self._wait_for_ask(hex(cmd))

def cmdGet(self):
if self.cmdGeneric(0x00):
mdebug(10, "*** Get command");
len = ord(self.sp.read())
version = ord(self.sp.read())
len = self.sp.read()[0]
version = self.sp.read()[0]
mdebug(10, " Bootloader version: "+hex(version))
dat = map(lambda c: hex(ord(c)), self.sp.read(len))
dat = list(map(lambda c: hex(c), self.sp.read(len)))
if '0x44' in dat:
self.extended_erase = 1
mdebug(10, " Available commands: "+", ".join(dat))
Expand All @@ -132,7 +137,7 @@ def cmdGet(self):
def cmdGetVersion(self):
if self.cmdGeneric(0x01):
mdebug(10, "*** GetVersion command")
version = ord(self.sp.read())
version = self.sp.read()[0]
self.sp.read(2)
self._wait_for_ask("0x01 end")
mdebug(10, " Bootloader version: "+hex(version))
Expand All @@ -143,21 +148,21 @@ def cmdGetVersion(self):
def cmdGetID(self):
if self.cmdGeneric(0x02):
mdebug(10, "*** GetID command")
len = ord(self.sp.read())
id = self.sp.read(len+1)
length = self.sp.read()[0]
id_bytes = self.sp.read(length + 1)
self._wait_for_ask("0x02 end")
return reduce(lambda x, y: x*0x100+y, map(ord, id))
# Python 3: bytes are already ints, no need for ord()
return reduce(lambda x, y: x*0x100 + y, id_bytes)
else:
raise CmdException("GetID (0x02) failed")


def _encode_addr(self, addr):
byte3 = (addr >> 0) & 0xFF
byte2 = (addr >> 8) & 0xFF
byte1 = (addr >> 16) & 0xFF
byte0 = (addr >> 24) & 0xFF
crc = byte0 ^ byte1 ^ byte2 ^ byte3
return (chr(byte0) + chr(byte1) + chr(byte2) + chr(byte3) + chr(crc))
return bytes([byte0, byte1, byte2, byte3, crc])


def cmdReadMemory(self, addr, lng):
Expand All @@ -168,9 +173,9 @@ def cmdReadMemory(self, addr, lng):
self._wait_for_ask("0x11 address failed")
N = (lng - 1) & 0xFF
crc = N ^ 0xFF
self.sp.write(chr(N) + chr(crc))
self.sp.write(bytes([N, crc]))
self._wait_for_ask("0x11 length failed")
return map(lambda c: ord(c), self.sp.read(lng))
return list(map(lambda c: c, self.sp.read(lng))) # or keep the ord if needed
else:
raise CmdException("ReadMemory (0x11) failed")

Expand All @@ -193,12 +198,12 @@ def cmdWriteMemory(self, addr, data):
#map(lambda c: hex(ord(c)), data)
lng = (len(data)-1) & 0xFF
mdebug(10, " %s bytes to write" % [lng+1]);
self.sp.write(chr(lng)) # len really
self.sp.write(bytes([lng])) # len really
crc = 0xFF
for c in data:
crc = crc ^ c
self.sp.write(chr(c))
self.sp.write(chr(crc))
self.sp.write(bytes([c]))
self.sp.write(bytes([crc]))
self._wait_for_ask("0x31 programming failed")
mdebug(10, " Write memory done")
else:
Expand All @@ -213,16 +218,16 @@ def cmdEraseMemory(self, sectors = None):
mdebug(10, "*** Erase memory command")
if sectors is None:
# Global erase
self.sp.write(chr(0xFF))
self.sp.write(chr(0x00))
self.sp.write(bytes([0xFF]))
self.sp.write(bytes([0x00]))
else:
# Sectors erase
self.sp.write(chr((len(sectors)-1) & 0xFF))
self.sp.write(bytes([(len(sectors)-1) & 0xFF]))
crc = 0xFF
for c in sectors:
crc = crc ^ c
self.sp.write(chr(c))
self.sp.write(chr(crc))
self.sp.write(bytes([c]))
self.sp.write(bytes([crc]))
self._wait_for_ask("0x43 erasing failed")
mdebug(10, " Erase memory done")
else:
Expand All @@ -232,28 +237,29 @@ def cmdExtendedEraseMemory(self):
if self.cmdGeneric(0x44):
mdebug(10, "*** Extended Erase memory command")
# Global mass erase
self.sp.write(chr(0xFF))
self.sp.write(chr(0xFF))
self.sp.write(bytes([0xFF]))
self.sp.write(bytes([0xFF]))
# Checksum
self.sp.write(chr(0x00))
self.sp.write(bytes([0x00]))
tmp = self.sp.timeout
self.sp.timeout = 30
print "Extended erase (0x44), this can take ten seconds or more"
print("Extended erase (0x44), this can take ten seconds or more")
self._wait_for_ask("0x44 erasing failed")
self.sp.timeout = tmp
mdebug(10, " Extended Erase memory done")
else:
raise CmdException("Extended Erase memory (0x44) failed")


def cmdWriteProtect(self, sectors):
if self.cmdGeneric(0x63):
mdebug(10, "*** Write protect command")
self.sp.write(chr((len(sectors)-1) & 0xFF))
self.sp.write(bytes([(len(sectors)-1) & 0xFF]))
crc = 0xFF
for c in sectors:
crc = crc ^ c
self.sp.write(chr(c))
self.sp.write(chr(crc))
self.sp.write(bytes([c]))
self.sp.write(bytes([crc]))
self._wait_for_ask("0x63 write protect failed")
mdebug(10, " Write protect done")
else:
Expand Down Expand Up @@ -294,7 +300,7 @@ def readMemory(self, addr, lng):
if usepbar:
widgets = ['Reading: ', Percentage(),', ', ETA(), ' ', Bar()]
pbar = ProgressBar(widgets=widgets,maxval=lng, term_width=79).start()

while lng > 256:
if usepbar:
pbar.update(pbar.maxval-lng)
Expand All @@ -316,7 +322,7 @@ def writeMemory(self, addr, data):
if usepbar:
widgets = ['Writing: ', Percentage(),' ', ETA(), ' ', Bar()]
pbar = ProgressBar(widgets=widgets, maxval=lng, term_width=79).start()

offs = 0
while lng > 256:
if usepbar:
Expand All @@ -337,12 +343,12 @@ def writeMemory(self, addr, data):



def __init__(self) :
def __init__(self):
pass


def usage():
print """Usage: %s [-hqVewvr] [-l length] [-p port] [-b baud] [-a addr] [-g addr] [file.bin]
print("""Usage: %s [-hqVewvr] [-l length] [-p port] [-b baud] [-a addr] [-g addr] [file.bin]
-h This help
-q Quiet
-V Verbose
Expand All @@ -358,21 +364,21 @@ def usage():

./stm32loader.py -e -w -v example/main.bin

""" % sys.argv[0]
""" % sys.argv[0])


if __name__ == "__main__":

# Import Psyco if available
try:
import psyco
psyco.full()
print "Using Psyco..."
print("Using Psyco...")
except ImportError:
pass

conf = {
'port': '/dev/tty.usbserial-ftCYPMYJ',
'port': '/dev/ttyUSB0',
'baud': 115200,
'address': 0x08000000,
'erase': 0,
Expand All @@ -386,9 +392,9 @@ def usage():

try:
opts, args = getopt.getopt(sys.argv[1:], "hqVewvrp:b:a:l:g:")
except getopt.GetoptError, err:
except getopt.GetoptError as err:
# print help information and exit:
print str(err) # will print something like "option -a not recognized"
print(str(err)) # will print something like "option -a not recognized"
usage()
sys.exit(2)

Expand Down Expand Up @@ -430,7 +436,7 @@ def usage():
try:
cmd.initChip()
except:
print "Can't init. Ensure that BOOT0 is enabled and reset device"
print("Can't init. Ensure that BOOT0 is enabled and reset device")


bootversion = cmd.cmdGet()
Expand All @@ -444,24 +450,25 @@ def usage():
# cmd.cmdWriteProtect([0, 1])

if (conf['write'] or conf['verify']):
data = map(lambda c: ord(c), file(args[0], 'rb').read())
data = list(map(lambda c: c, open(args[0], 'rb').read()))

if conf['erase']:
cmd.cmdEraseMemory()
time.sleep(0.5)

if conf['write']:
cmd.writeMemory(conf['address'], data)

if conf['verify']:
verify = cmd.readMemory(conf['address'], len(data))
if(data == verify):
print "Verification OK"
print("Verification OK")
else:
print "Verification FAILED"
print str(len(data)) + ' vs ' + str(len(verify))
print("Verification FAILED")
print(str(len(data)) + ' vs ' + str(len(verify)))
for i in xrange(0, len(data)):
if data[i] != verify[i]:
print hex(i) + ': ' + hex(data[i]) + ' vs ' + hex(verify[i])
print(hex(i) + ': ' + hex(data[i]) + ' vs ' + hex(verify[i]))

if not conf['write'] and conf['read']:
rdata = cmd.readMemory(conf['address'], conf['len'])
Expand Down