summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Mussared <jim.mussared@gmail.com>2020-08-28 15:51:15 +1000
committerDamien George <damien@micropython.org>2020-09-08 23:54:02 +1000
commit632e3b7acc51b3b28f310ef5e23b0983c8e8b700 (patch)
tree821105402e84b1f43e3ac360f92396aec3c1d39d
parente2390d5a2f4f18912878596965b0c794ac153cb4 (diff)
stm32/boards/NUCLEO_WB55: Add Python helper code for rfcore.
This allows prototyping rfcore.c improvements from Python. This was mostly written by @dpgeorge with small modifications to work after rfcore_init() by @jimmo.
-rw-r--r--ports/stm32/boards/NUCLEO_WB55/rfcore.py347
1 files changed, 347 insertions, 0 deletions
diff --git a/ports/stm32/boards/NUCLEO_WB55/rfcore.py b/ports/stm32/boards/NUCLEO_WB55/rfcore.py
new file mode 100644
index 000000000..e612499a7
--- /dev/null
+++ b/ports/stm32/boards/NUCLEO_WB55/rfcore.py
@@ -0,0 +1,347 @@
+# This file is part of the MicroPython project, http://micropython.org/
+#
+# The MIT License (MIT)
+#
+# Copyright (c) 2020 Damien P. George
+# 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 provides some helpers to allow Python code to access the IPCC
+# 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.
+
+from machine import mem8, mem16, mem32
+import time, struct, uctypes
+import stm
+
+
+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 = uctypes.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
+OGF_VENDOR = const(0x3F)
+OCF_FUS_GET_STATE = const(0x52)
+OCF_FUS_FW_UPGRADE = const(0x54)
+OCF_FUS_FW_DELETE = const(0x55)
+OCF_FUS_START_WS = const(0x5A)
+OCF_BLE_INIT = const(0x66)
+
+
+@micropython.asm_thumb
+def asm_sev_wfe():
+ data(2, 0xBF40) # sev
+ data(2, 0xBF20) # wfe
+
+
+TABLE_DEVICE_INFO = const(0)
+TABLE_BLE = const(1)
+TABLE_SYS = const(3)
+TABLE_MEM_MANAGER = const(4)
+
+CHANNEL_BLE = const(1)
+CHANNEL_SYS = const(2)
+CHANNEL_TRACES = const(4)
+CHANNEL_ACL = const(6)
+
+INDICATOR_HCI_COMMAND = const(0x01)
+INDICATOR_HCI_EVENT = const(0x04)
+INDICATOR_FUS_COMMAND = const(0x10)
+INDICATOR_FUS_RESPONSE = const(0x11)
+INDICATOR_FUS_EVENT = const(0x12)
+
+MAGIC_FUS_ACTIVE = const(0xA94656B9)
+
+
+def get_ipccdba():
+ return mem32[stm.FLASH + stm.FLASH_IPCCBR] & 0x3FFF
+
+
+def get_ipcc_table(table):
+ return mem32[SRAM2A_BASE + get_ipccdba() + table * 4]
+
+
+def get_ipcc_table_word(table, offset):
+ return mem32[get_ipcc_table(table) + offset * 4] & 0xFFFFFFFF
+
+
+def get_ipcc_table_byte(table, offset):
+ return mem8[get_ipcc_table(table) + offset] & 0xFF
+
+
+def sram2a_dump(num_words=64, width=8):
+ print("SRAM2A @%08x" % SRAM2A_BASE)
+ for i in range((num_words + width - 1) // width):
+ print(" %04x " % (i * 4 * width), end="")
+ for j in range(width):
+ print(" %08x" % (mem32[SRAM2A_BASE + (i * width + j) * 4] & 0xFFFFFFFF), end="")
+ print()
+
+
+SYS_CMD_BUF = 0 # next*,prev*,type8,...; 272 bytes
+SYS_SYS_QUEUE = 0 # next*,prev*
+
+MM_BLE_SPARE_EVT_BUF = 0 # next*,prev*; 272 bytes
+MM_SYS_SPARE_EVT_BUF = 0 # next*,prev*; 272 bytes
+MM_BLE_POOL = 0 # ?
+MM_BLE_POOL_SIZE = 0 # ?
+MM_FREE_BUF_QUEUE = 0 # next*,prev*
+MM_EV_POOL = 0 # ?
+MM_EV_POOL_SIZE = 0 # ?
+
+BLE_CMD_BUF = 0
+BLE_CS_BUF = 0
+BLE_EVT_QUEUE = 0
+BLE_HCI_ACL_DATA_BUF = 0
+
+
+def ipcc_init():
+ global SYS_CMD_BUF, SYS_SYS_QUEUE
+ SYS_CMD_BUF = get_ipcc_table_word(TABLE_SYS, 0)
+ SYS_SYS_QUEUE = get_ipcc_table_word(TABLE_SYS, 1)
+
+ global MM_BLE_SPARE_EVT_BUF, MM_SYS_SPARE_EVT_BUF, MM_BLE_POOL, MM_BLE_POOL_SIZE, MM_FREE_BUF_QUEUE, MM_EV_POOL, MM_EV_POOL_SIZE
+ MM_BLE_SPARE_EVT_BUF = get_ipcc_table_word(TABLE_MEM_MANAGER, 0)
+ MM_SYS_SPARE_EVT_BUF = get_ipcc_table_word(TABLE_MEM_MANAGER, 1)
+ MM_BLE_POOL = get_ipcc_table_word(TABLE_MEM_MANAGER, 2)
+ MM_BLE_POOL_SIZE = get_ipcc_table_word(TABLE_MEM_MANAGER, 3)
+ MM_FREE_BUF_QUEUE = get_ipcc_table_word(TABLE_MEM_MANAGER, 4)
+ MM_EV_POOL = get_ipcc_table_word(TABLE_MEM_MANAGER, 5)
+ MM_EV_POOL_SIZE = get_ipcc_table_word(TABLE_MEM_MANAGER, 6)
+
+ global BLE_CMD_BUF, BLE_CS_BUF, BLE_EVT_QUEUE, BLE_HCI_ACL_DATA_BUF
+ BLE_CMD_BUF = get_ipcc_table_word(TABLE_BLE, 0)
+ BLE_CS_BUF = get_ipcc_table_word(TABLE_BLE, 1)
+ BLE_EVT_QUEUE = get_ipcc_table_word(TABLE_BLE, 2)
+ BLE_HCI_ACL_DATA_BUF = get_ipcc_table_word(TABLE_BLE, 3)
+
+ print("IPCC initialised")
+ print("SYS: 0x%08x 0x%08x" % (SYS_CMD_BUF, SYS_SYS_QUEUE))
+ 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
+
+
+def info():
+ sfr = mem32[stm.FLASH + stm.FLASH_SFR]
+ srrvr = mem32[stm.FLASH + stm.FLASH_SRRVR]
+
+ print("IPCCDBA : 0x%08x" % (get_ipccdba() & 0x3FFF))
+ print("DDS : %r" % bool(sfr & (1 << 12)))
+ print("FSD : %r" % bool(sfr & (1 << 8)))
+ print("SFSA : 0x%08x" % (sfr & 0xFF))
+ print("C2OPT : %r" % bool(srrvr & (1 << 31)))
+ print("NBRSD : %r" % bool(srrvr & (1 << 30)))
+ print("SNBRSA : 0x%08x" % ((srrvr >> 25) & 0x1F))
+ print("BRSD : %r" % bool(srrvr & (1 << 23)))
+ print("SBRSA : 0x%08x" % ((srrvr >> 18) & 0x1F))
+ print("SBRV : 0x%08x" % (srrvr & 0x3FFFF))
+
+
+def dev_info():
+ def dump_version(offset):
+ x = get_ipcc_table_word(TABLE_DEVICE_INFO, offset)
+ print(
+ "0x%08x (%u.%u.%u.%u.%u)"
+ % (x, x >> 24, x >> 16 & 0xFF, x >> 8 & 0xFF, x >> 4 & 0xF, x & 0xF)
+ )
+
+ def dump_memory_size(offset):
+ x = get_ipcc_table_word(TABLE_DEVICE_INFO, offset)
+ print(
+ "0x%08x (SRAM2b=%uk SRAM2a=%uk flash=%uk)"
+ % (x, x >> 24, x >> 16 & 0xFF, (x & 0xFF) * 4)
+ )
+
+ print("Device information table @%08x:" % get_ipcc_table(TABLE_DEVICE_INFO))
+ if fus_active():
+ # layout when running FUS
+ print("FUS is active")
+ print("state : 0x%08x" % get_ipcc_table_word(TABLE_DEVICE_INFO, 0))
+ print("last FUS active state : 0x%02x" % get_ipcc_table_byte(TABLE_DEVICE_INFO, 5))
+ print("last wireless stack state: 0x%02x" % get_ipcc_table_byte(TABLE_DEVICE_INFO, 6))
+ print("cur wireless stack type : 0x%02x" % get_ipcc_table_byte(TABLE_DEVICE_INFO, 7))
+ print("safe boot version : ", end="")
+ dump_version(2)
+ print("FUS version : ", end="")
+ dump_version(3)
+ print("FUS memory size : ", end="")
+ dump_memory_size(4)
+ print("wireless stack version : ", end="")
+ dump_version(5)
+ print("wireless stack mem size : ", end="")
+ dump_memory_size(6)
+ print("wireless FW-BLE info : 0x%08x" % get_ipcc_table_word(TABLE_DEVICE_INFO, 7))
+ print("wireless FW-thread info : 0x%08x" % get_ipcc_table_word(TABLE_DEVICE_INFO, 8))
+ print(
+ "UID64 : 0x%08x 0x%08x"
+ % (
+ get_ipcc_table_word(TABLE_DEVICE_INFO, 9),
+ get_ipcc_table_word(TABLE_DEVICE_INFO, 10),
+ )
+ )
+ print("device ID : 0x%04x" % get_ipcc_table_word(TABLE_DEVICE_INFO, 11))
+ else:
+ # layout when running WS
+ print("WS is active")
+ print("safe boot version : ", end="")
+ dump_version(0)
+ print("FUS version : ", end="")
+ dump_version(1)
+ print("FUS memory size : ", end="")
+ dump_memory_size(2)
+ print("FUS info : 0x%08x" % get_ipcc_table_word(TABLE_DEVICE_INFO, 3))
+ print("wireless stack version : ", end="")
+ dump_version(4)
+ print("wireless stack mem size : ", end="")
+ dump_memory_size(5)
+ print("wireless stack info : 0x%08x" % get_ipcc_table_word(TABLE_DEVICE_INFO, 7))
+ print("wireless reserved : 0x%08x" % get_ipcc_table_word(TABLE_DEVICE_INFO, 7))
+
+
+def ipcc_state():
+ print("IPCC:")
+ print(" C1CR: 0x%08x" % (mem32[stm.IPCC + stm.IPCC_C1CR] & 0xFFFFFFFF), end="")
+ print(" C2CR: 0x%08x" % (mem32[stm.IPCC + stm.IPCC_C2CR] & 0xFFFFFFFF))
+ print(" C1MR: 0x%08x" % (mem32[stm.IPCC + stm.IPCC_C1MR] & 0xFFFFFFFF), end="")
+ print(" C2MR: 0x%08x" % (mem32[stm.IPCC + stm.IPCC_C2MR] & 0xFFFFFFFF))
+ # these always read 0
+ # print(' C1SCR: 0x%08x' % (mem32[stm.IPCC + stm.IPCC_C1SCR] & 0xffffffff), end='')
+ # print(' C2SCR: 0x%08x' % (mem32[stm.IPCC + stm.IPCC_C2SCR] & 0xffffffff))
+ print(" C1TOC2SR: 0x%08x" % (mem32[stm.IPCC + stm.IPCC_C1TOC2SR] & 0xFFFFFFFF), end="")
+ print(" C2TOC1SR: 0x%08x" % (mem32[stm.IPCC + stm.IPCC_C2TOC1SR] & 0xFFFFFFFF))
+
+
+sram2a_dump(264)
+ipcc_init()
+info()
+dev_info()