circuitpython/ports/stm32/boards/NUCLEO_WB55/rfcore.py

349 lines
12 KiB
Python
Raw Normal View History

# 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
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
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)
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)
# Disable interrupts, the code here uses polling
mem32[stm.IPCC + stm.IPCC_C1CR] = 0
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()