#!/usr/bin/env python3 # # stm32_mem.py: STM32 memory access using USB DFU class # Copyright (C) 2011 Black Sphere Technologies # Copyright (C) 2017, 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) # 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 . from time import sleep import struct import os from sys import stdout import argparse import dfu CMD_GETCOMMANDS = 0x00 CMD_SETADDRESSPOINTER = 0x21 CMD_ERASE = 0x41 def stm32_erase(dev, addr): erase_cmd = struct.pack(" 1 and not args.serial_target: if test: return print("Found multiple devices:\n") for dev in bmp_devs: dfudev = dfu.dfu_device(*dev) man = dfudev.handle.getString(dfudev.dev.iManufacturer, 30).decode('utf8') product = dfudev.handle.getString(dfudev.dev.iProduct, 96).decode('utf8') serial_no = dfudev.handle.getString(dfudev.dev.iSerialNumber, 30).decode('utf8') print("Device ID:\t %04x:%04x" % (dfudev.dev.idVendor, dfudev.dev.idProduct)) print("Manufacturer:\t %s" % man) print("Product:\t %s" % product) print("Serial:\t\t %s\n" % serial_no) print("Select device with serial number!") exit(-1) for dev in bmp_devs: dfudev = dfu.dfu_device(*dev) man = dfudev.handle.getString(dfudev.dev.iManufacturer, 30).decode('utf8') product = dfudev.handle.getString(dfudev.dev.iProduct, 96).decode('utf8') serial_no = dfudev.handle.getString(dfudev.dev.iSerialNumber, 30).decode('utf8') if args.serial_target: if man == "Black Sphere Technologies" and serial_no == args.serial_target: break else: if man == "Black Sphere Technologies": break print("Device ID:\t %04x:%04x" % (dfudev.dev.idVendor, dfudev.dev.idProduct)) print("Manufacturer:\t %s" % man) print("Product:\t %s" % product) print("Serial:\t\t %s" % serial_no) if args.serial_target and serial_no != args.serial_target: print("Serial number doesn't match %s vs %s!\n" % (serial_no, args.serial_target)) exit(-2) return dfudev if __name__ == "__main__": print("-") print("USB Device Firmware Upgrade - Host Utility -- version 1.2") print("Copyright (C) 2011 Black Sphere Technologies") print("License GPLv3+: GNU GPL version 3 or later ") print("-") print("** WARNING: This utility has been deprecated in favour of bmputil and dfu-util **") print(" Please see https://github.com/blackmagic-debug/bmputil") print("-") print("If this utility fails then for native please run `dfu-util -d 1d50:6018,:6017 -s 0x08002000:leave -D src/blackmagic.bin`") print("otherwise see the readme for your platform for the dfu-util line to use.") print("-") parser = argparse.ArgumentParser() parser.add_argument("progfile", help="Binary file to program") parser.add_argument("-s", "--serial_target", help="Match Serial Number") parser.add_argument("-a", "--address", help="Start address for firmware") parser.add_argument("-m", "--manifest", help="Start application, if in DFU mode", action='store_true') args = parser.parse_args() dfudev = stm32_scan(args, False) try: state = dfudev.get_state() except: if args.manifest: exit(0) print("Failed to read device state! Assuming APP_IDLE") state = dfu.STATE_APP_IDLE if state == dfu.STATE_APP_IDLE: try: dfudev.detach() except: pass dfudev.release() print("Invoking DFU Device") timeout = 0 while True: sleep(1) timeout = timeout + 0.5 dfudev = stm32_scan(args, True) if dfudev: break if timeout > 5: print("Error: DFU device did not appear") exit(-1) if args.manifest: stm32_manifest(dfudev) print("Invoking Application Device") exit(0) dfudev.make_idle() file = open(args.progfile, "rb") if (os.path.getsize(args.progfile) > 0x1f800): print("File too large") exit(0) bin = file.read() product = dfudev.handle.getString(dfudev.dev.iProduct, 64).decode('utf8') if args.address: start = int(args.address, 0) else: if "F4" in product or "STLINK-V3" in product: start = 0x8004000 else: start = 0x8002000 addr = start while bin: print("Programming memory at 0x%08X" % addr, end="\r") stdout.flush() try: # STM DFU bootloader erases always. # BPM Bootloader only erases once per sector # To support the STM DFU bootloader, the interface descriptor must # get evaluated and erase called only once per sector! stm32_erase(dfudev, addr) except: print("\nErase Timed out\n") break try: stm32_set_address(dfudev, addr) except: print("\nSet Address Timed out\n") break stm32_write(dfudev, bin[:1024]) bin = bin[1024:] addr += 1024 file.seek(0) bin = file.read() len = len(bin) addr = start print("\n-") while bin: try: stm32_set_address(dfudev, addr) data = stm32_read(dfudev) except: # Abort silent if bootloader does not support upload break print("Verifying memory at 0x%08X" % addr, end="\r") stdout.flush() if len > 1024: size = 1024 else: size = len if bin[:size] != bytearray(data[:size]): print("\nMismatch in block at 0x%08X" % addr) break bin = bin[1024:] addr += 1024 len -= 1024 if len <= 0: print("\nVerified!") stm32_manifest(dfudev) print("All operations complete!\n")