RW61x Shadow Registers#
Introduction#
The NXP tool, shadowregs (see User Guide), control your OTP fuses during development or testing. It enables the creation of “copies” of OTP fuses in the form of shadow registers. After each power-on reset, these shadow registers are cleared, and the default OTP fuses are loaded. It’s important to note two small limitations: the device must be in a lifecycle that supports shadow registers, and certain registers are not included in shadow registers.
Supported Commands#
fuses-script - Generate BLHOST script to burn up fuses in device by configuration.
get-template - Generate the template of Shadow registers YAML configuration file.
getreg - Print the current value of one shadow register.
loadconfig - Load new state of shadow registers from YAML file into micro controller.
printregs - Print all Shadow registers including theirs current values.
reset - Reset connected device.
saveconfig - Save current state of shadow registers to YAML file.
setreg - The command sets a value of one shadow register defined by parameter.
Let’s prepare the environment#
%run ../init_notebook.ipynb
import os
import pprint
import yaml
pp = pprint.PrettyPrinter(indent=4)
WORKSPACE = "workspace/" # change this to path to your workspace
INPUTS = "inputs/"
# choose debug interface
INTERFACE = "-i jlink"
# family
FAMILY = "-f rw61x"
env: JUPYTER_SPSDK=1
Created `%!` as an alias for `%execute`.
Device preparation#
Have the device in debug mode.
# check availability of debug probe
%! nxpdebugmbox $INTERFACE test-connection
nxpdebugmbox -i jlink test-connection
# Interface Id Description
-------------------------------------------------------
0 Jlink 1061995210 Segger J-Link MCU-Link
The device is accessible for debugging.
Compare the current state of shadowregs with defaults#
Verify that your shadow registers are in the default state.
# save differences comparing to defaults
SR_DIFF_PATH = os.path.join(WORKSPACE, "sr_diff_rw61x.yml")
%! shadowregs $INTERFACE $FAMILY saveconfig -o $SR_DIFF_PATH -d
shadowregs -i jlink -f rw61x saveconfig -o workspace/sr_diff_rw61x.yml -d
# Interface Id Description
-------------------------------------------------------
0 Jlink 1061995210 Segger J-Link MCU-Link
The Shadow registers has been saved into spsdk\examples\rw61x_shadowregs\workspace\sr_diff_rw61x.yml YAML file
# optional but recommended: reset connected device
%! shadowregs $INTERFACE $FAMILY reset
shadowregs -i jlink -f rw61x reset
# Interface Id Description
-------------------------------------------------------
0 Jlink 1061995210 Segger J-Link MCU-Link
The target has been reset.
Generate shadowregs template#
# generate the template of shadow registers
SR_TEMPLATE_PATH = os.path.join(WORKSPACE, "sr_template_rw61x.yml")
%! shadowregs $FAMILY get-template -o $SR_TEMPLATE_PATH --force
shadowregs -f rw61x get-template -o workspace/sr_template_rw61x.yml --force
The Shadow registers template for rw61x has been saved into spsdk\examples\rw61x_shadowregs\workspace\sr_template_rw61x.yml YAML file
Prepare shadowregs for dual boot#
In this section, one of the possible use cases of shadow registers will be presented.
Dual boot is normally not possible on RW61x devices without configuring the registers.
Dual boot represents the possibility to write two images and always boot the image that has the higher image version.
NOTICE: Switch the device to ISP mode (U38: OFF OFF OFF ON)!
# modification of shadowregs for dual boot
with open(SR_TEMPLATE_PATH) as sr_rw61x:
# load yaml configuration to dictionary
sr = yaml.safe_load(sr_rw61x)
# change paths
sr["registers"]["BOOT_CFG0"]["DICE_SKIP"] = "DISABLED"
sr["registers"]["BOOT_CFG0"]["PRIMARY_BOOT_SOURCE"] = "FLEXSPI_BOOT"
sr["registers"]["BOOT_CFG2"]["FLEXSPI_IMAGE_OFFSET"] = "0x1"
sr["registers"]["LIFE_CYCLE_STATE"]["LCS[7:0]"] = "Develop2"
sr["registers"]["LIFE_CYCLE_STATE"]["LCS_REDUNDANT[7:0]"] = "Develop2"
with open(SR_TEMPLATE_PATH, "w+") as sr_rw61x:
print("Shadowregs config:")
pp.pprint(sr)
# dump the dictionary back to YAML
yaml.dump(sr, sr_rw61x)
Shadowregs config:
{ 'family': 'rt5xx',
'registers': { 'BOOT_CFG0': { 'BOOT_CLK_SPEED': 0,
'BOOT_FAIL_PIN': 0,
'BOOT_FAIL_PORT': 0,
'DEFAULT_ISP_MODE': 'AUTO_ISP',
'DICE_INC_OTP': 'NOT_INCLUDED',
'DICE_SKIP': 'DISABLED',
'PRIMARY_BOOT_SOURCE': 'FLEXSPI_BOOT',
'REDUNDANT_SPI_PORT': 'FC0',
'SECURE_BOOT_EN': 'DISABLED',
'STOP_ON_FAILURE': 0,
'TZM_IMAGE_TYPE': 'IGNORED'},
'BOOT_CFG1': { 'FLEXSPI_AUTO_PROBE_EN': 'FLASH_AUTO_PROBE',
'FLEXSPI_DUMMY_CYCLES': 'AUTO_PROB',
'FLEXSPI_FLASH_TYPE': 'FLEXSPI_SDR_3B',
'FLEXSPI_FREQUENCY': 'FLEXSPI_100MHZ',
'FLEXSPI_HOLD_TIME': 'NO_DELAY',
'FLEXSPI_PROBE_TYPE': 'QSPI_NOR',
'FLEXSPI_PWR_HOLD_TIME': 'NO_DELAY',
'FLEXSPI_RST_HOLD_TIME': 'NO_DELAY',
'FLEXSPI_RST_SEQ': 'NO_RESET_PERFORMED',
'FLEXSPI_WUP_HOLD_TIME': 'NO_DELAY',
'FLEXSPI_WUP_SEQ': 'NO_RESET_PERFORMED'},
'BOOT_CFG2': { 'FLEXSPI_DELAY_CELL_NUM': 0,
'FLEXSPI_IMAGE_OFFSET': '0x1',
'FLEXSPI_IMAGE_SIZE': 'SIZE_OFFSET'},
'BOOT_CFG3': { 'ENABLE_CRC_CHECK': 0,
'ENF_CNSA': 'P-256_KEY',
'FIPS_AES_STEN': 'SKIP_SELF_TEEST_RUN',
'FIPS_CMAC_STEN': 'SKIP_SELF_TEEST_RUN',
'FIPS_DRBG_STEN': 'SKIP_SELF_TEEST_RUN',
'FIPS_ECDSA_STEN': 'SKIP_SELF_TEEST_RUN',
'FIPS_KDF_STEN': 'SKIP_SELF_TEEST_RUN',
'FIPS_SHA_STEN': 'SKIP_SELF_TEEST_RUN',
'ROTK0_USAGE': 'DebugCA_ImageCA_FwCA_ImageKey_FwKey',
'ROTK1_USAGE': 'DebugCA_ImageCA_FwCA_ImageKey_FwKey',
'ROTK2_USAGE': 'DebugCA_ImageCA_FwCA_ImageKey_FwKey',
'ROTK3_USAGE': 'DebugCA_ImageCA_FwCA_ImageKey_FwKey',
'SKIP_PM_SIGN_VERIFCATION': 0},
'BOOT_CFG5': {'USB_PID': 0, 'USB_VID': 0},
'BOOT_CFG6': {'SDIO_PID': 0, 'SDIO_VID': 0},
'DCFG_CC_SOCU': { 'DFLT_CPU1DBGEN': 'DISABLED',
'DFLT_CPU1NIDEN': 'DISABLED',
'DFLT_CPU2DBGEN': 'DISABLED',
'DFLT_CPU2NIDEN': 'DISABLED',
'DFLT_DBGEN': 'DISABLED',
'DFLT_FACMDEN': 'DISABLED',
'DFLT_ISPCMDEN': 'DISABLED',
'DFLT_NIDEN': 'DISABLED',
'DFLT_SPIDEN': 'DISABLED',
'DFLT_SPNIDEN': 'DISABLED',
'DFLT_TAPEN': 'DISABLED',
'FORCE_UUID_MATCH': 0,
'PINNED_CPU1DBGEN': 'DAR_CC',
'PINNED_CPU1NIDEN': 'DAR_CC',
'PINNED_CPU2DBGEN': 'DAR_CC',
'PINNED_CPU2NIDEN': 'DAR_CC',
'PINNED_DBGEN': 'DAR_CC',
'PINNED_FACMDEN': 'DAR_CC',
'PINNED_ISPCMDEN': 'DAR_CC',
'PINNED_NIDEN': 'DAR_CC',
'PINNED_SPIDEN': 'DAR_CC',
'PINNED_SPNIDEN': 'DAR_CC',
'PINNED_TAPEN': 'DAR_CC'},
'DCFG_CC_SOCU_AP': '0x00000000',
'DCFG_CC_SOCU_NS': { 'DFLT_CPU1DBGEN_NS': 'DISABLED',
'DFLT_CPU1NIDEN_NS': 'DISABLED',
'DFLT_CPU2DBGEN_NS': 'DISABLED',
'DFLT_CPU2NIDEN_NS': 'DISABLED',
'DFLT_DBGEN_NS': 'DISABLED',
'DFLT_FACMDEN_NS': 'DISABLED',
'DFLT_ISPCMDEN_NS': 'DISABLED',
'DFLT_NIDEN_NS': 'DISABLED',
'DFLT_SPIDEN_NS': 'DISABLED',
'DFLT_SPNIDEN_NS': 'DISABLED',
'DFLT_TAPEN_NS': 'DISABLED',
'FORCE_UUID_MATCH_NS': 0,
'PINNED_CPU1DBGEN_NS': 'DAR_CC',
'PINNED_CPU1NIDEN_NS': 'DAR_CC',
'PINNED_CPU2DBGEN_NS': 'DAR_CC',
'PINNED_CPU2NIDEN_NS': 'DAR_CC',
'PINNED_DBGEN_NS': 'DAR_CC',
'PINNED_FACMDEN_NS': 'DAR_CC',
'PINNED_ISPCMDEN_NS': 'DAR_CC',
'PINNED_NIDEN_NS': 'DAR_CC',
'PINNED_SPIDEN_NS': 'DAR_CC',
'PINNED_SPNIDEN_NS': 'DAR_CC',
'PINNED_TAPEN_NS': 'DAR_CC'},
'LIFE_CYCLE_STATE': { 'LCS[7:0]': 'Develop2',
'LCS_REDUNDANT[7:0]': 'Develop2',
'Redundancy': 0},
'RKTH': '0000000000000000000000000000000000000000000000000000000000000000',
'SEC_BOOT_CFG0': { 'FA_MODE_EN': 0,
'REVOKE_ROOTKEY0': 'ENABLED',
'REVOKE_ROOTKEY1': 'ENABLED',
'REVOKE_ROOTKEY2': 'ENABLED',
'REVOKE_ROOTKEY3': 'ENABLED',
'Redundancy': 0},
'SEC_BOOT_CFG1': {'DAP_VENDOR_USAGE': 0, 'Redundancy': 0},
'SEC_BOOT_CFG2': { 'REVOKE_IMG_KEY[15:0]': 0,
'Redundancy': 0},
'SEC_BOOT_CFG3': { 'REVOKE_IMG_KEY[31:16]': 0,
'Redundancy': 0}},
'revision': 'latest'}
# list available connected devices
%! nxpdevscan
nxpdevscan
-------- Connected NXP SDIO Devices --------
-------- Connected NXP USB Devices --------
-------- Connected NXP UART Devices --------
Port: COM5
Type: mboot device
-------- Connected NXP SIO Devices --------
# choose com port for rw61x
UART_CONNECTION = "-p com5"
# memory configuration
FCB_PATH = os.path.join(INPUTS, "converted_fcb.bin")
%! blhost $UART_CONNECTION write-memory 0x2000F000 $FCB_PATH
%! blhost $UART_CONNECTION configure-memory 9 0x2000F000
%! blhost $UART_CONNECTION flash-erase-region 0x08000000 25000
%! blhost $UART_CONNECTION flash-erase-region 0x08040000 25000
%! blhost $UART_CONNECTION fill-memory 0x2000F000 4 0xF000000F
%! blhost $UART_CONNECTION configure-memory 9 0x2000F000
%! blhost $UART_CONNECTION write-memory 0x08040400 $FCB_PATH
blhost -p com5 write-memory 0x2000F000 inputs/converted_fcb.bin
Writing memory
Response status = 0 (0x0) Success.
Response word 1 = 512 (0x200)
blhost -p com5 configure-memory 9 0x2000F000
Response status = 0 (0x0) Success.
blhost -p com5 flash-erase-region 0x08000000 25000
Response status = 0 (0x0) Success.
blhost -p com5 flash-erase-region 0x08040000 25000
Response status = 0 (0x0) Success.
blhost -p com5 fill-memory 0x2000F000 4 0xF000000F
Response status = 0 (0x0) Success.
blhost -p com5 configure-memory 9 0x2000F000
Response status = 0 (0x0) Success.
blhost -p com5 write-memory 0x08040400 inputs/converted_fcb.bin
Writing memory
Response status = 0 (0x0) Success.
Response word 1 = 512 (0x200)
# write images and versions
LED_BLINKY_PATH = os.path.join(INPUTS, "mbi_crc_led_blinky.bin")
HELLO_WORLD_PATH = os.path.join(INPUTS, "mbi_crc_hello_world.bin")
IMG_V0_PATH = os.path.join(INPUTS, "img_v0.bin")
IMG_V1_PATH = os.path.join(INPUTS, "img_v1.bin")
%! blhost $UART_CONNECTION write-memory 0x08000600 $IMG_V0_PATH
%! blhost $UART_CONNECTION write-memory 0x08001000 $LED_BLINKY_PATH
%! blhost $UART_CONNECTION write-memory 0x08040600 $IMG_V1_PATH
%! blhost $UART_CONNECTION write-memory 0x08041000 $HELLO_WORLD_PATH
blhost -p com5 write-memory 0x08000600 inputs/img_v0.bin
Writing memory
Response status = 0 (0x0) Success.
Response word 1 = 4 (0x4)
blhost -p com5 write-memory 0x08001000 inputs/mbi_crc_led_blinky.bin
Writing memory
Response status = 0 (0x0) Success.
Response word 1 = 14008 (0x36b8)
blhost -p com5 write-memory 0x08040600 inputs/img_v1.bin
Writing memory
Response status = 0 (0x0) Success.
Response word 1 = 4 (0x4)
blhost -p com5 write-memory 0x08041000 inputs/mbi_crc_hello_world.bin
Writing memory
Response status = 0 (0x0) Success.
Response word 1 = 22044 (0x561c)
# load modified shadowregs
%! shadowregs $INTERFACE $FAMILY loadconfig -c $SR_TEMPLATE_PATH
shadowregs -i jlink -f rw61x loadconfig -c workspace/sr_template_rw61x.yml
# Interface Id Description
-------------------------------------------------------
0 Jlink 1061995210 Segger J-Link MCU-Link
The Shadow registers has been loaded by configuration in spsdk\examples\rw61x_shadowregs\workspace\sr_template_rw61x.yml YAML file
# reset the device and run image
%! shadowregs $INTERFACE $FAMILY reset
shadowregs -i jlink -f rw61x reset
# Interface Id Description
-------------------------------------------------------
0 Jlink 1061995210 Segger J-Link MCU-Link
The target has been reset.