Architecture
An OpenSMA image is a layered C/C++/Ada firmware built per SoC core and linked into a single downloadable image. This chapter shows how the pieces fit; the Build System chapter shows how the build drives them.
Layer composition
flowchart TB
subgraph proj[Project: mcxn547helloworld]
C0[core0/main.cpp]
C1[core1/main.cpp]
end
subgraph nv[nv:: firmware — src/nv/]
FEAT[Feature subsystems:<br/>mctp, pldm, spdm, vrot,<br/>fancontrol, telemetry, ...]
COMMON[common / logger / ipc]
end
subgraph mod[Shared C++ modules — corepdk/modules/]
MCTP[mctp-cpp]
PLDM[pldm-fd]
SPDM[spdm]
end
subgraph bsp[BSP — src/sys/ + src/boards/]
SYS[sys/mcxn556, sys/mcu]
BOARD[boards/mcxn547helloworld]
end
SDK[(NXP MCUXpresso SDK<br/>libexec/sdk)]
C0 --> FEAT
C1 --> FEAT
FEAT --> COMMON
FEAT --> MCTP
FEAT --> PLDM
FEAT --> SPDM
COMMON --> SYS
SYS --> BOARD
BOARD --> SDK
The nv:: firmware layer
All firmware code lives in the nv:: namespace under src/nv/. The
umbrella header src/nv/nv.h pulls in the common utilities
(src/nv/nv.h:20) and defines the error-propagation macros the codebase
uses everywhere — NV_TRY (src/nv/nv.h:24) and the NV_ROE_*
“return-on-error” family (src/nv/nv.h:27), which check a status enum
against ::Ok and early-return. This expected/status style (rather
than exceptions) is characteristic of the whole tree.
Subsystems are directories under src/nv/ — e.g. src/nv/mctp/,
src/nv/pldm/, src/nv/vrot/. The heavier protocol subsystems are thin
nv:: wrappers over shared modules: src/nv/mctp/composer.h:22 simply
aliases pdk::mctp::app::Composer from
corepdk/modules/mctp-cpp/.
Shared modules (corepdk/modules/)
Three reusable C++ modules are consumed by the nv:: subsystems:
| Module | Path | Wrapped by |
|---|---|---|
| MCTP | corepdk/modules/mctp-cpp/ |
src/nv/mctp/ |
| PLDM FD | corepdk/modules/pldm-fd/ |
src/nv/pldm/ |
| SPDM | corepdk/modules/spdm/ |
src/nv/spdm/ |
Keeping the protocol engines in corepdk lets them be reused across
projects while src/nv/ supplies the platform wiring.
BSP and the bootloader
The board/SoC layer lives under src/sys/ (mcu, mcxn236,
mcxn556, x86) and src/boards/. The firmware bootloader wraps the
SoC bootloader: nv::bootloader::Driver (src/nv/bootloader.h:28)
derives from sys::bootloader::Driver (src/nv/bootloader.h:21),
layering the nv:: API over the BSP primitive. See
Platform / BSP & Projects.
Dual-core composition (core0 + core1)
The MCXN556S is dual-core. Building PLATFORM=mcxn556-both
(mcu_build.sh:99) produces two images and folds them into one:
sequenceDiagram
participant B as mcu_build.sh
participant U as ./ubs (make)
participant O as objcopy
B->>U: build core1 (run_build_flow mcxn556-core1)
U-->>B: core1.elf
B->>O: objcopy core1.elf -> core1.bin
O-->>B: core1.bin
B->>B: xxd -i core1.bin -> core0/core1_image.c
Note over B: array tagged .core1_image section
B->>U: build core0 (embeds core1 image)
U-->>B: core0 image (both cores)
Concretely, mcu_build.sh derives the per-core platforms
(mcu_build.sh:106), builds core1 first, runs objcopy to get a raw
binary (mcu_build.sh:120), then xxd -i turns that binary into
src/projects/<project>/core0/core1_image.c (mcu_build.sh:131),
rewriting the array into a .core1_image linker section
(mcu_build.sh:133). core0 is then built with that image linked in, so
the single downloaded artifact carries both cores. Each core has its own
entry point: src/projects/mcxn547helloworld/core0/main.cpp and
.../core1/main.cpp.
Next
- Build System — the make/UBS flow and signing.
- Transports & Buses — the first feature section.