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.
This commit is contained in:
parent
e2390d5a2f
commit
632e3b7acc
347
ports/stm32/boards/NUCLEO_WB55/rfcore.py
Normal file
347
ports/stm32/boards/NUCLEO_WB55/rfcore.py
Normal file
@ -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()
|
Loading…
x
Reference in New Issue
Block a user