|
|
@ -1,5 +1,5 @@ |
|
|
|
# Update Mboot or MicroPython from a .dfu.gz file on the board's filesystem |
|
|
|
# MIT license; Copyright (c) 2019-2020 Damien P. George |
|
|
|
# MIT license; Copyright (c) 2019-2022 Damien P. George |
|
|
|
|
|
|
|
from micropython import const |
|
|
|
import struct, time |
|
|
@ -16,9 +16,6 @@ _ELEM_TYPE_MOUNT = const(2) |
|
|
|
_ELEM_TYPE_FSLOAD = const(3) |
|
|
|
_ELEM_TYPE_STATUS = const(4) |
|
|
|
|
|
|
|
FLASH_KEY1 = 0x45670123 |
|
|
|
FLASH_KEY2 = 0xCDEF89AB |
|
|
|
|
|
|
|
|
|
|
|
def check_mem_contains(addr, buf): |
|
|
|
mem8 = stm.mem8 |
|
|
@ -29,15 +26,6 @@ def check_mem_contains(addr, buf): |
|
|
|
return True |
|
|
|
|
|
|
|
|
|
|
|
def check_mem_erased(addr, size): |
|
|
|
mem16 = stm.mem16 |
|
|
|
r = range(0, size, 2) |
|
|
|
for off in r: |
|
|
|
if mem16[addr + off] != 0xFFFF: |
|
|
|
return False |
|
|
|
return True |
|
|
|
|
|
|
|
|
|
|
|
def dfu_read(filename): |
|
|
|
f = open(filename, "rb") |
|
|
|
|
|
|
@ -85,39 +73,99 @@ def dfu_read(filename): |
|
|
|
return elems |
|
|
|
|
|
|
|
|
|
|
|
def flash_wait_not_busy(): |
|
|
|
while stm.mem32[stm.FLASH + stm.FLASH_SR] & 1 << 16: |
|
|
|
machine.idle() |
|
|
|
|
|
|
|
|
|
|
|
def flash_unlock(): |
|
|
|
stm.mem32[stm.FLASH + stm.FLASH_KEYR] = FLASH_KEY1 |
|
|
|
stm.mem32[stm.FLASH + stm.FLASH_KEYR] = FLASH_KEY2 |
|
|
|
|
|
|
|
|
|
|
|
def flash_lock(): |
|
|
|
stm.mem32[stm.FLASH + stm.FLASH_CR] = 1 << 31 # LOCK |
|
|
|
|
|
|
|
|
|
|
|
def flash_erase_sector(sector): |
|
|
|
assert 0 <= sector <= 7 # for F722 |
|
|
|
flash_wait_not_busy() |
|
|
|
cr = 2 << 8 | sector << 3 | 1 << 1 # PSIZE = 32 bits # SNB # SER |
|
|
|
stm.mem32[stm.FLASH + stm.FLASH_CR] = cr |
|
|
|
stm.mem32[stm.FLASH + stm.FLASH_CR] = cr | 1 << 16 # STRT |
|
|
|
flash_wait_not_busy() |
|
|
|
stm.mem32[stm.FLASH + stm.FLASH_CR] = 0 |
|
|
|
|
|
|
|
|
|
|
|
def flash_write(addr, buf): |
|
|
|
assert len(buf) % 4 == 0 |
|
|
|
flash_wait_not_busy() |
|
|
|
cr = 2 << 8 | 1 << 0 # PSIZE = 32 bits # PG |
|
|
|
stm.mem32[stm.FLASH + stm.FLASH_CR] = cr |
|
|
|
for off in range(0, len(buf), 4): |
|
|
|
stm.mem32[addr + off] = struct.unpack_from("I", buf, off)[0] |
|
|
|
flash_wait_not_busy() |
|
|
|
stm.mem32[stm.FLASH + stm.FLASH_CR] = 0 |
|
|
|
class Flash: |
|
|
|
_FLASH_KEY1 = 0x45670123 |
|
|
|
_FLASH_KEY2 = 0xCDEF89AB |
|
|
|
|
|
|
|
def __init__(self): |
|
|
|
import os, uctypes |
|
|
|
|
|
|
|
self.addressof = uctypes.addressof |
|
|
|
|
|
|
|
# Detect MCU. |
|
|
|
machine = os.uname().machine |
|
|
|
if "STM32F4" in machine or "STM32F7" in machine: |
|
|
|
dev_id = stm.mem32[0xE004_2000] & 0xFFF |
|
|
|
elif "STM32H7" in machine: |
|
|
|
dev_id = stm.mem32[0x5C00_1000] & 0xFFF |
|
|
|
else: |
|
|
|
dev_id = 0 |
|
|
|
|
|
|
|
# Configure flash parameters based on MCU. |
|
|
|
if dev_id in (0x413, 0x419, 0x431, 0x451, 0x452): |
|
|
|
# 0x413: STM32F405/407, STM32F415/417 |
|
|
|
# 0x419: STM32F42x/43x |
|
|
|
# 0x431: STM32F411 |
|
|
|
# 0x451: STM32F76x/77x |
|
|
|
# 0x452: STM32F72x/73x |
|
|
|
self._keyr = stm.FLASH + stm.FLASH_KEYR |
|
|
|
self._sr = stm.FLASH + stm.FLASH_SR |
|
|
|
self._sr_busy = 1 << 16 |
|
|
|
self._cr = stm.FLASH + stm.FLASH_CR |
|
|
|
self._cr_lock = 1 << 31 |
|
|
|
self._cr_init_erase = lambda s: 2 << 8 | s << 3 | 1 << 1 # PSIZE=32-bits, SNB, SER |
|
|
|
self._cr_start_erase = 1 << 16 # STRT |
|
|
|
self._cr_init_write = 2 << 8 | 1 << 0 # PSIZE=32-bits, PG |
|
|
|
self._cr_flush = None |
|
|
|
self._write_multiple = 4 |
|
|
|
if dev_id == 0x451 and stm.mem32[0x1FFF_0008] & 1 << 13: # check nDBANK |
|
|
|
# STM32F76x/77x in single-bank mode |
|
|
|
self.sector0_size = 32 * 1024 |
|
|
|
else: |
|
|
|
self.sector0_size = 16 * 1024 |
|
|
|
elif dev_id == 0x450: |
|
|
|
# 0x450: STM32H742, STM32H743/753, STM32H750 |
|
|
|
self._keyr = stm.FLASH + stm.FLASH_KEYR1 |
|
|
|
self._sr = stm.FLASH + stm.FLASH_SR1 |
|
|
|
self._sr_busy = 1 << 2 # QW1 |
|
|
|
self._cr = stm.FLASH + stm.FLASH_CR1 |
|
|
|
self._cr_lock = 1 << 0 # LOCK1 |
|
|
|
self._cr_init_erase = lambda s: s << 8 | 3 << 4 | 1 << 2 # SNB1, PSIZE1=64-bits, SER1 |
|
|
|
self._cr_start_erase = 1 << 7 # START1 |
|
|
|
self._cr_init_write = 3 << 4 | 1 << 1 # PSIZE1=64-bits, PG1=1 |
|
|
|
self._cr_flush = 1 << 6 # FW1=1 |
|
|
|
self._write_multiple = 16 |
|
|
|
self.sector0_size = 128 * 1024 |
|
|
|
else: |
|
|
|
raise Exception(f"unknown MCU {machine} DEV_ID=0x{dev_id:x}") |
|
|
|
|
|
|
|
def wait_not_busy(self): |
|
|
|
while stm.mem32[self._sr] & self._sr_busy: |
|
|
|
machine.idle() |
|
|
|
|
|
|
|
def unlock(self): |
|
|
|
if stm.mem32[self._cr] & self._cr_lock: |
|
|
|
stm.mem32[self._keyr] = self._FLASH_KEY1 |
|
|
|
stm.mem32[self._keyr] = self._FLASH_KEY2 |
|
|
|
|
|
|
|
def lock(self): |
|
|
|
stm.mem32[self._cr] = self._cr_lock |
|
|
|
|
|
|
|
def erase_sector(self, sector): |
|
|
|
assert 0 <= sector <= 7 |
|
|
|
self.wait_not_busy() |
|
|
|
stm.mem32[self._cr] = self._cr_init_erase(sector) |
|
|
|
stm.mem32[self._cr] |= self._cr_start_erase |
|
|
|
self.wait_not_busy() |
|
|
|
stm.mem32[self._cr] = 0 |
|
|
|
|
|
|
|
# This method is optimised for speed, to reduce the time data is being written. |
|
|
|
def write(self, addr, buf): |
|
|
|
assert len(buf) % 4 == 0 |
|
|
|
mem32 = stm.mem32 |
|
|
|
buf_addr = self.addressof(buf) |
|
|
|
r = range(0, len(buf), 4) |
|
|
|
self.wait_not_busy() |
|
|
|
mem32[self._cr] = self._cr_init_write |
|
|
|
for off in r: |
|
|
|
mem32[addr + off] = mem32[buf_addr + off] |
|
|
|
if off % self._write_multiple == 0: |
|
|
|
while mem32[self._sr] & self._sr_busy: |
|
|
|
pass |
|
|
|
if self._cr_flush is not None: |
|
|
|
mem32[self._cr] |= self._cr_flush |
|
|
|
self.wait_not_busy() |
|
|
|
mem32[self._cr] = 0 |
|
|
|
|
|
|
|
|
|
|
|
def update_mboot(filename): |
|
|
@ -144,13 +192,14 @@ def update_mboot(filename): |
|
|
|
print("Programming Mboot, do not turn off!") |
|
|
|
time.sleep_ms(50) |
|
|
|
|
|
|
|
flash = Flash() |
|
|
|
irq = machine.disable_irq() |
|
|
|
flash_unlock() |
|
|
|
flash_erase_sector(0) |
|
|
|
if len(mboot_fw) > 16 * 1024 and not check_mem_erased(mboot_addr + 16 * 1024, 16 * 1024): |
|
|
|
flash_erase_sector(1) |
|
|
|
flash_write(mboot_addr, mboot_fw) |
|
|
|
flash_lock() |
|
|
|
flash.unlock() |
|
|
|
flash.erase_sector(0) |
|
|
|
if len(mboot_fw) > flash.sector0_size: |
|
|
|
flash.erase_sector(1) |
|
|
|
flash.write(mboot_addr, mboot_fw) |
|
|
|
flash.lock() |
|
|
|
machine.enable_irq(irq) |
|
|
|
|
|
|
|
print("New Mboot programmed.") |
|
|
|