summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien George <damien@micropython.org>2022-01-31 16:55:50 +1100
committerDamien George <damien@micropython.org>2022-01-31 18:26:55 +1100
commitca1914fb474dd7a2a6e94ba835cea45b0bcd742b (patch)
tree39bb6cdaaefb08437954db437a37a1a47410cd05
parent29867a24391ae3938ae43b354297139b7a229b73 (diff)
stm32/mboot: Support H7 MCUs in fwupdate.py.
And optimise the speed of flash writing. Signed-off-by: Damien George <damien@micropython.org>
-rw-r--r--ports/stm32/mboot/fwupdate.py153
1 files changed, 101 insertions, 52 deletions
diff --git a/ports/stm32/mboot/fwupdate.py b/ports/stm32/mboot/fwupdate.py
index d7c8f46db..8a366dae2 100644
--- a/ports/stm32/mboot/fwupdate.py
+++ b/ports/stm32/mboot/fwupdate.py
@@ -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.")