MCXE31B HSE Firmware Installation#

This notebook demonstrates how to install HSE (Hardware Security Engine) firmware on MCXE31B devices.

What is HSE Firmware?#

The Hardware Security Engine (HSE) is a dedicated security subsystem that provides:

  • Cryptographic Services: AES, RSA, ECC, hash functions

  • Secure Boot: Code authentication and verification

  • Key Management: Secure key storage and provisioning

  • Secure Memory Regions (SMR): Runtime code integrity verification

  • Lifecycle Management: Device state transitions

Important Notes#

⚠️ Critical Information:

  • One-Time Installation: HSE firmware installation is a one-time process

  • Cannot Be Uninstalled: Once installed, HSE firmware cannot be removed

  • Can Be Updated: HSE firmware can only be updated to newer versions

  • Factory State: All MCXE31 devices are delivered without HSE firmware

❌ Warning: Do not interrupt the installation process! Power loss or interruption during HSE firmware installation may brick the device.

1. Prerequisites#

Before starting, ensure you have:

  • SPSDK installed: pip install spsdk[examples]

  • MCXE31B Freedom board

  • J-Link debugger connected to the board

  • UART connection established (for blhost communication)

  • HSE firmware binary file (.pink format)

  • Stable power supply to the board

ℹ️ Note: The HSE firmware binary typically has a .pink extension and follows the naming pattern: mcxe3xb_hse_fw_[version].bin.pink

import os
import time

# This env variable sets colored logger output to STDOUT
%env JUPYTER_SPSDK=1

# Set a magic for command execution and echo
%alias execute echo %l && %l
%alias_magic ! execute
env: JUPYTER_SPSDK=1
Created `%!` as an alias for `%execute`.

2. Configuration#

Configure the paths and communication parameters for your setup.

# Workspace and input directories
WORKSPACE = "workspace/"
INPUTS = "inputs/"

# Communication parameters
BLHOST_CONNECT = "-p COM26"  # Change this to your actual COM port
FAMILY = "mcxe31b"

# HSE firmware file
HSE_FW = INPUTS + "mcxe3xb_hse_fw_0.5.0_2.55.0_pb250324.bin.pink"

# Flash addresses
HSE_FW_ADDRESS = "0x420000"  # HSE firmware installation address
HSE_FW_SIZE = "0x40000"  # 256KB reserved for HSE firmware
HSE_INSTALL_TRIGGER = "0x1b000000"  # HSE installation trigger address

# Installation trigger pattern
HSE_TRIGGER_PATTERN = "{{{{ AA BB CC DD DD CC BB AA }}}}"

# Timeout for HSE installation (in seconds)
HSE_INSTALL_TIMEOUT = "120"

# Create workspace directory
os.makedirs(WORKSPACE, exist_ok=True)

print("✅ Configuration loaded successfully!")
✅ Configuration loaded successfully!

3. Pre-Installation Checks#

Before installing HSE firmware, let’s verify the setup and check if HSE is already installed.

3.1 Initialize Flashloader#

Initialize the flashloader using J-Link to enable communication with the device.

# Initialize flashloader using J-Link
# Make sure J-Link is connected to the board and the board is powered on
%! "JLink.exe" -NoGui 1 -ExitOnError 1 -CommandFile "inputs/init_flashloader_cmd.jlink"

print("\n✅ Flashloader initialized successfully!")
"JLink.exe" -NoGui 1 -ExitOnError 1 -CommandFile "inputs/init_flashloader_cmd.jlink" 
SEGGER J-Link Commander V8.44 (Compiled Jun 18 2025 12:17:39)
DLL version V8.44, compiled Jun 18 2025 12:16:46

J-Link Commander will now exit on Error

J-Link Command File read successfully.
Processing script file...
J-Link>device S32K314
J-Link connection not established yet but required for command.
Connecting to J-Link via USB...O.K.
Firmware: J-Link V9 compiled May  7 2021 16:26:12
Hardware version: V9.20
J-Link uptime (since boot): N/A (Not supported by this model)
S/N: 59201842
License(s): GDB
VTref=3.322V
J-Link>si SWD
Selecting SWD as current target interface.
J-Link>speed 4000
Selecting 4000 kHz as target interface speed
J-Link>connect
Device "S32K314" selected.


Connecting to target via SWD
ConfigTargetSettings() start
ConfigTargetSettings() end - Took 20us
InitTarget() start
SDA_AP detected
Unlocking device if necessary...
  Device is not locked. Proceeding without the unlock procedure.
Checking if debug access is already enabled...
  Core already enabled
Checking if HSE firmware is installed...
  HSE firmware not installed
Checking if Cortex-M7_0 and Cortex-M7_1 are operating in lockstep mode
  Lock step mode disabled or not available
InitTarget() end - Took 5.38ms
Found SW-DP with ID 0x6BA02477
DPIDR: 0x6BA02477
CoreSight SoC-400 or earlier
AP map detection skipped. Manually configured AP map found.
AP[0]: MEM-AP (IDR: Not set, ADDR: 0x00000000)
AP[1]: APB-AP (IDR: Not set, ADDR: 0x00000000)
AP[2]: MEM-AP (IDR: Not set, ADDR: 0x00000000)
AP[3]: AHB-AP (IDR: Not set, ADDR: 0x00000000)
AP[4]: AHB-AP (IDR: Not set, ADDR: 0x00000000)
AP[5]: AHB-AP (IDR: Not set, ADDR: 0x00000000)
AP[6]: MEM-AP (IDR: Not set, ADDR: 0x00000000)
AP[7]: MEM-AP (IDR: Not set, ADDR: 0x00000000)
AP[4]: Skipped ROMBASE read. CoreBaseAddr manually set by user
AP[4]: Core found
CPUID register: 0x411FC272. Implementer code: 0x41 (ARM)
Cache: L1 I/D-cache present
Found Cortex-M7 r1p2, Little endian.
FPUnit: 8 code (BP) slots and 0 literal slots
ROM table scan skipped. CoreBaseAddr manually set by user: 0x40250400
I-Cache L1: 8 KB, 128 Sets, 32 Bytes/Line, 2-Way
D-Cache L1: 8 KB, 64 Sets, 32 Bytes/Line, 4-Way
SetupTarget() start
Initializing ECC RAM...
  RAMCodeAddr: 0x20000000
  RAMInitAddr: 0x20000010
  RAMInitSize: 0x00007FF0
  InitPattern: 0xDEADBEEF
  ECC RAM initialized successfully
Initializing ECC RAM...
  RAMCodeAddr: 0x20000000
  RAMInitAddr: 0x20400000
  RAMInitSize: 0x00004000
  InitPattern: 0xDEADBEEF
  ECC RAM initialized successfully
SetupTarget() end - Took 19.1ms
Memory zones:
  Zone: "Default" Description: Default access mode
Cortex-M7 identified.
J-Link>reset
Reset delay: 0 ms
ResetTarget() start
-- Identifying target device...
-- SWD selected. Executing JTAG -> SWD switching sequence...
SDA_AP detected
Checking if core is already enabled...
  Core is not enabled yet. Performing enable core sequence...
  Core enabled
Unlocking device if necessary...
  Device is not locked. Proceeding without the unlock procedure.
ResetTarget() end - Took 412ms
Device specific reset executed.
J-Link>halt
PC = 0040411C, CycleCnt = 00000000
R0 = 00000000, R1 = 00000000, R2 = 00000000, R3 = 00000000
R4 = 00000000, R5 = 00000000, R6 = 00000000, R7 = 00000000
R8 = 00000000, R9 = 00000000, R10= 00000000, R11= 00000000
R12= 00000000
SP(R13)= 20404000, MSP= 20404000, PSP= 00000000, R14(LR) = FFFFFFFF
XPSR = 01000000: APSR = nzcvq, EPSR = 01000000, IPSR = 000 (NoException)
CFBP = 00000000, CONTROL = 00, FAULTMASK = 00, BASEPRI = 00, PRIMASK = 00

FPS0 = 00000000, FPS1 = 00000000, FPS2 = 00000000, FPS3 = 00000000
FPS4 = 00000000, FPS5 = 00000000, FPS6 = 00000000, FPS7 = 00000000
FPS8 = 00000000, FPS9 = 00000000, FPS10= 00000000, FPS11= 00000000
FPS12= 00000000, FPS13= 00000000, FPS14= 00000000, FPS15= FFFFFFFF
FPS16= 00000000, FPS17= 00000000, FPS18= 00000000, FPS19= 00000000
FPS20= 00000000, FPS21= 00000000, FPS22= 00000000, FPS23= 00000000
FPS24= 00000000, FPS25= 00000000, FPS26= 00000000, FPS27= 00000000
FPS28= 00000000, FPS29= 00000000, FPS30= 00000000, FPS31= FFFFFFFF
FPSCR= 00000000
J-Link>loadfile ./inputs/flashloader_loader.elf
'loadfile': Performing implicit reset & halt of MCU.
ResetTarget() start
-- Identifying target device...
-- SWD selected. Executing JTAG -> SWD switching sequence...
SDA_AP detected
Checking if core is already enabled...
  Core is not enabled yet. Performing enable core sequence...
  Core enabled
Unlocking device if necessary...
  Device is not locked. Proceeding without the unlock procedure.
ResetTarget() end - Took 411ms
Device specific reset executed.
Downloading file [./inputs/flashloader_loader.elf]...
Comparing flash   [000%000%050%050%100%] Done.
J-Link: Flash download: Bank 0 @ 0x00400000: Skipped. Contents already match
O.K.
J-Link>loadfile ./inputs/flashloader.elf
'loadfile': Performing implicit reset & halt of MCU.
ResetTarget() start
-- Identifying target device...
-- SWD selected. Executing JTAG -> SWD switching sequence...
SDA_AP detected
Checking if core is already enabled...
  Core is not enabled yet. Performing enable core sequence...
  Core enabled
Unlocking device if necessary...
  Device is not locked. Proceeding without the unlock procedure.
ResetTarget() end - Took 412ms
Device specific reset executed.
Downloading file [./inputs/flashloader.elf]...
O.K.
J-Link>go
Memory map 'after startup completion point' is active
J-Link>exit

Script processing completed.


✅ Flashloader initialized successfully!

3.2 Check Current HSE Firmware Status#

Let’s check if HSE firmware is already installed and what version it is.

ℹ️ Understanding the Response:

  • No HSE firmware: Command will fail or return invalid version

  • HSE installed: Returns version in format H[major].[minor].[patch] (e.g., H2.55.0)

# Check HSE firmware version (property 24)
%! blhost $BLHOST_CONNECT get-property 24 1

print("\n📝 If you see a valid version (e.g., H2.55.0), HSE firmware is already installed.")
print("📝 If the command return FW with version 0.0.0, HSE firmware is not installed.")
blhost -p COM26 get-property 24 1 
Response status = 0 (0x0) Success.
Response word 1 = 0 (0x0)
Target Version = 0.0.0

📝 If you see a valid version (e.g., H2.55.0), HSE firmware is already installed.
📝 If the command return FW with version 0.0.0, HSE firmware is not installed.

4. HSE Firmware Installation Process#

The HSE firmware installation involves three main steps:

  1. Erase the HSE firmware region in flash

  2. Write the HSE firmware binary to flash

  3. Trigger the installation by writing a magic pattern

⚠️ Important: The installation process may take up to 2 minutes. Do not interrupt or power off the device during this time!

4.1 Erase HSE Firmware Region#

print("🔄 Step 1/3: Erasing HSE firmware region...")
print(f"   Address: {HSE_FW_ADDRESS}")
print(f"   Size: {HSE_FW_SIZE} ({int(HSE_FW_SIZE, 16):,} bytes)\n")

%! blhost $BLHOST_CONNECT flash-erase-region $HSE_FW_ADDRESS $HSE_FW_SIZE

print("\n✅ HSE firmware region erased successfully!")
🔄 Step 1/3: Erasing HSE firmware region...
   Address: 0x420000
   Size: 0x40000 (262,144 bytes)

blhost -p COM26 flash-erase-region 0x420000 0x40000 
Response status = 0 (0x0) Success.

✅ HSE firmware region erased successfully!

4.2 Write HSE Firmware to Flash#

This step writes the HSE firmware binary to the flash memory.

ℹ️ Note: This operation uses an extended timeout (120 seconds) because writing the firmware can take some time.

assert os.path.exists(HSE_FW), f"HSE firmware file not found: {HSE_FW}"

print("🔄 Step 2/3: Writing HSE firmware to flash...")
print(f"   Source: {HSE_FW}")
print(f"   Destination: {HSE_FW_ADDRESS}")
print(f"   Timeout: {HSE_INSTALL_TIMEOUT} seconds\n")
print("⏳ This may take a while, please wait...\n")

%! blhost $BLHOST_CONNECT --timeout $HSE_INSTALL_TIMEOUT write-memory $HSE_FW_ADDRESS $HSE_FW

print("\n✅ HSE firmware written to flash successfully!")
🔄 Step 2/3: Writing HSE firmware to flash...
   Source: inputs/mcxe3xb_hse_fw_0.5.0_2.55.0_pb250324.bin.pink
   Destination: 0x420000
   Timeout: 120 seconds

⏳ This may take a while, please wait...

blhost -p COM26 --timeout 120 write-memory 0x420000 inputs/mcxe3xb_hse_fw_0.5.0_2.55.0_pb250324.bin.pink 
Writing memory
Response status = 0 (0x0) Success.
Response word 1 = 135264 (0x21060)

✅ HSE firmware written to flash successfully!

4.3 Trigger HSE Firmware Installation#

The final step triggers the actual installation by writing a magic pattern to a special address.

⚠️ Critical Step: After this command, the device will perform the HSE firmware installation. This process:

  • Takes up to 2 minutes to complete

  • Cannot be interrupted

  • Will cause the device to reset automatically

print("🔄 Step 3/3: Triggering HSE firmware installation...")
print(f"   Trigger address: {HSE_INSTALL_TRIGGER}")
print(f"   Trigger pattern: {HSE_TRIGGER_PATTERN}\n")

%! blhost $BLHOST_CONNECT write-memory $HSE_INSTALL_TRIGGER "$HSE_TRIGGER_PATTERN"

print("\n✅ HSE firmware installation triggered!")

time.sleep(1)
%! blhost $BLHOST_CONNECT --timeout $HSE_INSTALL_TIMEOUT reset
print("\n✅ Installation process initiated successfully!")
🔄 Step 3/3: Triggering HSE firmware installation...
   Trigger address: 0x1b000000
   Trigger pattern: {{{{ AA BB CC DD DD CC BB AA }}}}

blhost -p COM26 write-memory 0x1b000000 "{{ AA BB CC DD DD CC BB AA }}" 
Writing memory
Response status = 0 (0x0) Success.
Response word 1 = 8 (0x8)

✅ HSE firmware installation triggered!
blhost -p COM26 --timeout 120 reset 
Response status = 0 (0x0) Success.

✅ Installation process initiated successfully!

5. Post-Installation Verification#

After installation, we need to verify that HSE firmware was installed successfully.

5.1 Re-initialize Flashloader#

After the device reset, we need to re-initialize the flashloader.

print("🔄 Re-initializing flashloader after reset...\n")

%! "JLink.exe" -NoGui 1 -ExitOnError 1 -CommandFile "inputs/init_flashloader_cmd.jlink"

print("\n✅ Flashloader re-initialized!")
🔄 Re-initializing flashloader after reset...

"JLink.exe" -NoGui 1 -ExitOnError 1 -CommandFile "inputs/init_flashloader_cmd.jlink" 
SEGGER J-Link Commander V8.44 (Compiled Jun 18 2025 12:17:39)
DLL version V8.44, compiled Jun 18 2025 12:16:46

J-Link Commander will now exit on Error

J-Link Command File read successfully.
Processing script file...
J-Link>device S32K314
J-Link connection not established yet but required for command.
Connecting to J-Link via USB...O.K.
Firmware: J-Link V9 compiled May  7 2021 16:26:12
Hardware version: V9.20
J-Link uptime (since boot): N/A (Not supported by this model)
S/N: 59201842
License(s): GDB
VTref=3.325V
J-Link>si SWD
Selecting SWD as current target interface.
J-Link>speed 4000
Selecting 4000 kHz as target interface speed
J-Link>connect
Device "S32K314" selected.


Connecting to target via SWD
ConfigTargetSettings() start
ConfigTargetSettings() end - Took 19us
InitTarget() start
SDA_AP detected
Unlocking device if necessary...
  Device is not locked. Proceeding without the unlock procedure.
Checking if debug access is already enabled...
  Core already enabled
Checking if HSE firmware is installed...
  HSE firmware detected (SWAP disabled)
Checking if Cortex-M7_0 and Cortex-M7_1 are operating in lockstep mode
  Lock step mode disabled or not available
InitTarget() end - Took 5.46ms
Found SW-DP with ID 0x6BA02477
DPIDR: 0x6BA02477
CoreSight SoC-400 or earlier
AP map detection skipped. Manually configured AP map found.
AP[0]: MEM-AP (IDR: Not set, ADDR: 0x00000000)
AP[1]: APB-AP (IDR: Not set, ADDR: 0x00000000)
AP[2]: MEM-AP (IDR: Not set, ADDR: 0x00000000)
AP[3]: AHB-AP (IDR: Not set, ADDR: 0x00000000)
AP[4]: AHB-AP (IDR: Not set, ADDR: 0x00000000)
AP[5]: AHB-AP (IDR: Not set, ADDR: 0x00000000)
AP[6]: MEM-AP (IDR: Not set, ADDR: 0x00000000)
AP[7]: MEM-AP (IDR: Not set, ADDR: 0x00000000)
AP[4]: Skipped ROMBASE read. CoreBaseAddr manually set by user
AP[4]: Core found
CPUID register: 0x411FC272. Implementer code: 0x41 (ARM)
Cache: L1 I/D-cache present
Found Cortex-M7 r1p2, Little endian.
FPUnit: 8 code (BP) slots and 0 literal slots
ROM table scan skipped. CoreBaseAddr manually set by user: 0x40250400
I-Cache L1: 8 KB, 128 Sets, 32 Bytes/Line, 2-Way
D-Cache L1: 8 KB, 64 Sets, 32 Bytes/Line, 4-Way
SetupTarget() start
Initializing ECC RAM...
  RAMCodeAddr: 0x20000000
  RAMInitAddr: 0x20000010
  RAMInitSize: 0x00007FF0
  InitPattern: 0xDEADBEEF
  ECC RAM initialized successfully
Initializing ECC RAM...
  RAMCodeAddr: 0x20000000
  RAMInitAddr: 0x20400000
  RAMInitSize: 0x00004000
  InitPattern: 0xDEADBEEF
  ECC RAM initialized successfully
SetupTarget() end - Took 19.0ms
Memory zones:
  Zone: "Default" Description: Default access mode
Cortex-M7 identified.
J-Link>reset
Reset delay: 0 ms
ResetTarget() start
-- Identifying target device...
-- SWD selected. Executing JTAG -> SWD switching sequence...
SDA_AP detected
Checking if core is already enabled...
  Core is not enabled yet. Performing enable core sequence...
  Core enabled
Unlocking device if necessary...
  Device is not locked. Proceeding without the unlock procedure.
ResetTarget() end - Took 412ms
Device specific reset executed.
J-Link>halt
PC = 0040411C, CycleCnt = 00000000
R0 = 00000000, R1 = 00000000, R2 = 00000000, R3 = 00000000
R4 = 00000000, R5 = 00000000, R6 = 00000000, R7 = 00000000
R8 = 00000000, R9 = 00000000, R10= 00000000, R11= 00000000
R12= 00000000
SP(R13)= 20404000, MSP= 20404000, PSP= 00000000, R14(LR) = FFFFFFFF
XPSR = 01000000: APSR = nzcvq, EPSR = 01000000, IPSR = 000 (NoException)
CFBP = 00000000, CONTROL = 00, FAULTMASK = 00, BASEPRI = 00, PRIMASK = 00

FPS0 = 00000000, FPS1 = 00000000, FPS2 = 00000000, FPS3 = 00000000
FPS4 = 00000000, FPS5 = 00000000, FPS6 = 00000000, FPS7 = 00000000
FPS8 = 00000000, FPS9 = 00000000, FPS10= 00000000, FPS11= 00000000
FPS12= 00000000, FPS13= 00000000, FPS14= 00000000, FPS15= FFFFFFFF
FPS16= 00000000, FPS17= 00000000, FPS18= 00000000, FPS19= 00000000
FPS20= 00000000, FPS21= 00000000, FPS22= 00000000, FPS23= 00000000
FPS24= 00000000, FPS25= 00000000, FPS26= 00000000, FPS27= 00000000
FPS28= 00000000, FPS29= 00000000, FPS30= 00000000, FPS31= FFFFFFFF
FPSCR= 00000000
J-Link>loadfile ./inputs/flashloader_loader.elf
'loadfile': Performing implicit reset & halt of MCU.
ResetTarget() start
-- Identifying target device...
-- SWD selected. Executing JTAG -> SWD switching sequence...
SDA_AP detected
Checking if core is already enabled...
  Core is not enabled yet. Performing enable core sequence...
  Core enabled
Unlocking device if necessary...
  Device is not locked. Proceeding without the unlock procedure.
ResetTarget() end - Took 412ms
Device specific reset executed.
Downloading file [./inputs/flashloader_loader.elf]...
Comparing flash   [000%000%050%050%100%] Done.
J-Link: Flash download: Bank 0 @ 0x00400000: Skipped. Contents already match
O.K.
J-Link>loadfile ./inputs/flashloader.elf
'loadfile': Performing implicit reset & halt of MCU.
ResetTarget() start
-- Identifying target device...
-- SWD selected. Executing JTAG -> SWD switching sequence...
SDA_AP detected
Checking if core is already enabled...
  Core is not enabled yet. Performing enable core sequence...
  Core enabled
Unlocking device if necessary...
  Device is not locked. Proceeding without the unlock procedure.
ResetTarget() end - Took 412ms
Device specific reset executed.
Downloading file [./inputs/flashloader.elf]...
O.K.
J-Link>go
Memory map 'after startup completion point' is active
J-Link>exit

Script processing completed.


✅ Flashloader re-initialized!

5.2 Verify HSE Firmware Version#

Check that HSE firmware is now installed and verify its version.

print("🔍 Verifying HSE firmware installation...\n")

%! blhost $BLHOST_CONNECT get-property 24 1

print("\n" + "=" * 60)
print("📊 VERIFICATION RESULTS")
print("=" * 60)
print("\nIf you see a version like 'H2.55.0' above:")
print("  ✅ HSE firmware installation was SUCCESSFUL!")
print("\nIf the command failed or shows invalid data:")
print("  ❌ HSE firmware installation FAILED!")
print("  Please review the installation steps and try again.")
print("=" * 60)
🔍 Verifying HSE firmware installation...

blhost -p COM26 get-property 24 1 
Response status = 0 (0x0) Success.
Response word 1 = 1208104704 (0x48023700)
Target Version = H2.55.0

============================================================
📊 VERIFICATION RESULTS
============================================================

If you see a version like 'H2.55.0' above:
  ✅ HSE firmware installation was SUCCESSFUL!

If the command failed or shows invalid data:
  ❌ HSE firmware installation FAILED!
  Please review the installation steps and try again.
============================================================

6. Summary#

This notebook covered the complete HSE firmware installation process:

Installation Steps:#

  1. Pre-Installation

    • ✅ Initialized flashloader

    • ✅ Checked current HSE status

    • ✅ Verified firmware file

  2. Installation Process

    • ✅ Erased HSE firmware region

    • ✅ Wrote HSE firmware to flash

    • ✅ Triggered installation

  3. Post-Installation

    • ✅ Re-initialized flashloader

    • ✅ Verified HSE firmware version

Key Points to Remember:#

  • HSE firmware installation is a one-time process

  • HSE firmware cannot be uninstalled, only updated

  • Do not interrupt the installation process

  • Installation takes up to 2 minutes

  • Always verify installation success

Next Steps:#

After successful HSE firmware installation, you can:

  • Configure key catalogs

  • Provision cryptographic keys

  • Enable secure boot features

  • Configure Secure Memory Regions (SMR)

  • Implement application authentication

✅ Congratulations! You have successfully installed HSE firmware on your MCXE31B device. The device is now ready for advanced security features.