#!/usr/bin/env python3 # # bootprog.py: STM32 SystemMemory Production Programmer -- version 1.1 # Copyright (C) 2011 Black Sphere Technologies # Written by Gareth McMullin # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import serial import struct from time import sleep class stm32_boot: def __init__(self, port, baud=115200): self.serial = serial.Serial(port, baud, 8, 'E', 1, timeout=1) # Turn on target device in SystemMemory boot mode self.serial.setDTR(1) sleep(0.1) self._sync() def _sync(self): # Send sync byte #print("sending sync byte") self.serial.write(b"\x7f") self._checkack() def _sendcmd(self, cmd): cmd = ord(cmd) cmd = bytes((cmd, cmd ^ 0xff)) #print("sendcmd:", repr(cmd)) self.serial.write(cmd) def _send(self, data): csum = 0 for c in data: csum ^= c data = data + bytes((csum,)) #print("sending:", repr(data)) self.serial.write(data) def _checkack(self): ACK = b"\x79" b = self.serial.read(1) if b != ACK: raise Exception("Invalid ack: %r" % b) #print("got ack!") def get(self): self._sendcmd(b"\x00") self._checkack() num = self.serial.read(1)[0] data = self.serial.read(num+1) self._checkack() return data def eraseall(self): # Send erase cmd self._sendcmd(b"\x43") self._checkack() # Global erase self._sendcmd(b"\xff") self._checkack() def read(self, addr, len): # Send read cmd self._sendcmd(b"\x11") self._checkack() # Send address self._send(struct.pack(">L", addr)) self._checkack() # Send length self._sendcmd(bytes((len-1,))) self._checkack() return self.serial.read(len) def write(self, addr, data): # Send write cmd self._sendcmd(b"\x31") self._checkack() # Send address self._send(struct.pack(">L", addr)) self._checkack() # Send data self._send(bytes((len(data)-1,)) + data) self._checkack() def write_protect(self, sectors): # Send WP cmd self._sendcmd(b"\x63") self._checkack() # Send sector list self._send(bytes((len(sectors)-1,)) + bytes(sectors)) self._checkack() # Resync after system reset self._sync() def write_unprotect(self): self._sendcmd(b"\x73") self._checkack() self._checkack() self._sync() def read_protect(self): self._sendcmd(b"\x82") self._checkack() self._checkack() self._sync() def read_unprotect(self): self._sendcmd(b"\x92") self._checkack() self._checkack() self._sync() if __name__ == "__main__": from sys import stdout, argv, platform from getopt import getopt if platform == "linux": print("\x1b\x5b\x48\x1b\x5b\x32\x4a") # clear terminal screen print("STM32 SystemMemory Production Programmer -- version 1.1") print("Copyright (C) 2011 Black Sphere Technologies") print("License GPLv3+: GNU GPL version 3 or later ") print() dev = "COM1" if platform == "win32" else "/dev/ttyUSB0" baud = 115200 addr = 0x8000000 try: opts, args = getopt(argv[1:], "b:d:a:") for opt in opts: if opt[0] == "-b": baud = int(opt[1]) elif opt[0] == "-d": dev = opt[1] else: raise Exception() progfile = args[0] except: print("Usage %s [-d ] [-b ] [-a
] " % argv[0]) print("\t-d : Use target on interface (default: %s)" % dev) print("\t-b : Set device baudrate (default: %d)" % baud) print("\t-a : Set programming address (default: 0x%X)" % addr) print() exit(-1) prog = open(progfile, "rb").read() boot = stm32_boot(dev, baud) cmds = boot.get() print("Target bootloader version: %d.%d\n" % (cmds[0] >> 4, cmds[0] % 0xf)) print("Removing device protection...") boot.read_unprotect() boot.write_unprotect() print("Erasing target device...") boot.eraseall() addr = 0x8000000 while prog: print("Programming address 0x%08X..0x%08X...\r" % (addr, addr + min(len(prog), 255)), end=' ') stdout.flush() boot.write(addr, prog[:256]) addr += 256 prog = prog[256:] print print("Enabling device protection...") boot.write_protect(range(0,2)) #boot.read_protect() print("All operations completed.") print