stm32/boards/NUCLEO_WB55: Add standalone WB55 FUS/WS firmware updater.

This commit adds a script that can be run on-device to install FUS and WS
binaries from the filesystem.  Instructions for use are provided in
the rfcore_firmware.py file.

The commit also removes unneeded functionality from the existing rfcore.py
debug script (and renames it rfcore_debug.py).
This commit is contained in:
Jim Mussared
2020-09-29 18:37:45 +10:00
committed by Damien George
parent 7c76a2dfcf
commit 222ec1a4a8
3 changed files with 630 additions and 115 deletions
@@ -27,85 +27,16 @@
# mechanism in the WB55, and works with the memory layout configured in
# ports/stm32/rfcore.c -- i.e. it expects that rfcore_init() has been run.
# At this stage this is useful for debugging, but can be extended to support
# FUS/WS firmware updates.
# e.g.
# ../../tools/pyboard.py --device /dev/ttyACM0 boards/NUCLEO_WB55/rfcore.py
# to print out SRAM2A, register state and FUS/WS info.
#
# The `stm` module provides some helper functions to access rfcore functionality.
# See rfcore_firmware.py for more information.
from machine import mem8, mem16, mem32
import time, struct
import stm
def addressof(buf):
assert type(buf) is bytearray
return mem32[id(buf) + 12]
class Flash:
FLASH_KEY1 = 0x45670123
FLASH_KEY2 = 0xCDEF89AB
def wait_not_busy(self):
while mem32[stm.FLASH + stm.FLASH_SR] & 1 << 16:
machine.idle()
def unlock(self):
mem32[stm.FLASH + stm.FLASH_KEYR] = Flash.FLASH_KEY1
mem32[stm.FLASH + stm.FLASH_KEYR] = Flash.FLASH_KEY2
def lock(self):
mem32[stm.FLASH + stm.FLASH_CR] = 1 << 31 # LOCK
def erase_page(self, page):
print("erase", page)
assert 0 <= page <= 255 # 1MiB range (4k page)
self.wait_not_busy()
cr = page << 3 | 1 << 1 # PNB # PER
mem32[stm.FLASH + stm.FLASH_CR] = cr
mem32[stm.FLASH + stm.FLASH_CR] = cr | 1 << 16 # STRT
self.wait_not_busy()
mem32[stm.FLASH + stm.FLASH_CR] = 0
def write(self, addr, buf):
assert len(buf) % 4 == 0
self.wait_not_busy()
cr = 1 << 0 # PG
mem32[stm.FLASH + stm.FLASH_CR] = cr
buf_addr = addressof(buf)
off = 0
while off < len(buf):
mem32[addr + off] = mem32[buf_addr + off]
off += 4
if off % 8 == 0:
self.wait_not_busy()
if off % 8:
mem32[addr + off] = 0
self.wait_not_busy()
mem32[stm.FLASH + stm.FLASH_CR] = 0
def copy_file_to_flash(filename, addr):
flash = Flash()
flash.unlock()
try:
with open(filename, "rb") as f:
buf = bytearray(4096)
while 1:
sz = f.readinto(buf)
if sz == 0:
break
print("write", hex(addr), sz)
flash.erase_page((addr - 0x08000000) // 4096)
print("done e")
flash.write(addr, buf)
print("done")
addr += 4096
finally:
flash.lock()
SRAM2A_BASE = const(0x2003_0000)
# for vendor OGF
@@ -205,49 +136,6 @@ def ipcc_init():
print("BLE: 0x%08x 0x%08x 0x%08x" % (BLE_CMD_BUF, BLE_CS_BUF, BLE_EVT_QUEUE))
def tl_list_init(addr):
mem32[addr] = addr # next
mem32[addr + 4] = addr # prev
def tl_list_append(head, n):
sram2a_dump(1024)
print("Appending 0x%08x to 0x%08x" % (head, n))
# item->next = head
mem32[n] = head
# item->prev = head->prev
mem32[n + 4] = mem32[head + 4]
# head->prev->next = item
mem32[mem32[head + 4]] = n
# head->prev = item
mem32[head + 4] = n
def tl_list_unlink(n):
# next = item->next
next = mem32[n]
# prev = item->prev
prev = mem32[n + 4]
# prev->next = item->next
mem32[prev] = next
# item->next->prev = prev
mem32[next + 4] = prev
return next
def tl_list_dump(head):
print(
"list(%08x, %08x, %08x):" % (head, mem32[head] & 0xFFFFFFFF, mem32[head + 4] & 0xFFFFFFFF),
end="",
)
cur = mem32[head]
while cur != head:
print(" %08x" % (cur & 0xFFFFFFFF), end="")
cur = mem32[cur]
print()
def fus_active():
return get_ipcc_table_word(TABLE_DEVICE_INFO, 0) == MAGIC_FUS_ACTIVE
@@ -346,3 +234,4 @@ sram2a_dump(264)
ipcc_init()
info()
dev_info()
ipcc_state()
File diff suppressed because it is too large Load Diff
+79
View File
@@ -0,0 +1,79 @@
#!/usr/bin/env python3
#
# This file is part of the MicroPython project, http://micropython.org/
#
# The MIT License (MIT)
#
# Copyright (c) 2020 Jim Mussared
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# This script obfuscates the ST wireless binaries so they can be safely copied
# to the flash filesystem and not be accidentally discovered by the FUS during
# an update. See more information (and the corresponding de-obfuscation) in
# rfcore_firmware.py as well as instructions on how to use.
import os
import struct
import sys
# Must match rfcore_firmware.py.
_OBFUSCATION_KEY = 0x0573B55AA
_FIRMWARE_FILES = {
"stm32wb5x_FUS_fw_1_0_2.bin": "fus_102.bin",
"stm32wb5x_FUS_fw.bin": "fus_110.bin",
"stm32wb5x_BLE_HCILayer_fw.bin": "ws_ble_hci.bin",
}
def main(src_path, dest_path):
for src_file, dest_file in _FIRMWARE_FILES.items():
src_file = os.path.join(src_path, src_file)
dest_file = os.path.join(dest_path, dest_file)
if not os.path.exists(src_file):
print("Unable to find: {}".format(src_file))
continue
sz = 0
with open(src_file, "rb") as src:
with open(dest_file, "wb") as dest:
while True:
b = src.read(4)
if not b:
break
(v,) = struct.unpack("<I", b)
v ^= _OBFUSCATION_KEY
dest.write(struct.pack("<I", v))
sz += 4
print("Written {} ({} bytes)".format(dest_file, sz))
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: {} src_path dest_path".format(sys.argv[0]))
print()
print(
'"src_path" should be the location of the ST binaries from https://github.com/STMicroelectronics/STM32CubeWB/tree/master/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x'
)
print(
'"dest_path" will be where fus_102.bin, fus_110.bin, and ws_ble_hci.bin will be written to.'
)
sys.exit(1)
main(sys.argv[1], sys.argv[2])