BSP, boards & projects

This page catalogs the board/SoC support layer that sits beneath the nv:: firmware and the buildable projects the Build System turns into images. Three source trees cooperate, and the build’s three main selectors map onto them one-for-one:

Selector Source tree Provides
PROJECT src/projects/<name>/ Per-core main.cpp, config.h, sign params, linker/core-image glue
PLATFORM src/sys/<soc>/ (+ project sys/<soc>/) SoC drivers, startup, FreeRTOSConfig.h, linker script
BOARD src/boards/<name>/ Pin mux, clocks, peripherals (from an .mex)
flowchart TD
    subgraph sel[Build selectors]
      P[PROJECT=mcxn547helloworld]
      PL[PLATFORM=mcxn556-both]
      B[BOARD=mcxn547helloworld]
    end
    P --> PRJ["src/projects/mcxn547helloworld<br/>core0/ + core1/ + config.h"]
    PL --> SYS["src/sys/mcxn556<br/>SoC drivers + startup"]
    PL --> PSYS["project sys/mcxn556<br/>FreeRTOSConfig + linker + start.S"]
    B --> BRD["src/boards/mcxn547helloworld<br/>pin_mux / clock_config / peripherals"]
    PRJ --> IMG[[signed image]]
    SYS --> IMG
    PSYS --> IMG
    BRD --> IMG

The example selectors above are the ones the Build System chapter uses (mcu_build.sh:22); note that the mcxn547helloworld project is built here on the mcxn556 platform against the mcxn547helloworld board — project, platform and board are chosen independently.

SoC BSPs (src/sys/)

Each supported SoC has a parallel subsystem tree under src/sys/<soc>/sys/ (adc/, bootloader/, common/, crypto/, flash/, gpio/, i2c/, i3c/, ipc/, spi/, uart/, usb/, watchdog/, …). The nv:: firmware calls into these through sys:: interfaces, so swapping the platform swaps the whole driver tree.

BSP Role Notes
src/sys/mcu/ Cross-SoC shared code Currently only a placeholder sys/i3c/driver.cpp (license-only, 17 lines) — shared home for future common drivers (interpretation)
src/sys/mcxn236/ NXP MCXN236 (single-core) BSP Full driver set; used by the testrunner project
src/sys/mcxn556/ NXP MCXN556S BSP (baseline MCU) Adds dual-core support: sys/c2c_mailbox/, sys/ipc_bm/, sys/smartdma/, and an NC-SI-over-USB stack in lib/ncsi/
src/sys/x86/ Host build for emulation / unit tests Same subsystem tree compiled for x86, plus a FreeRTOS shim in freertos/

Fact: common/system.h defines the SoC-neutral System class (src/sys/mcxn556/sys/common/system.h:22) that each project starts with common::System::inst().scheduler_start().

The x86 host build and FreeRTOS shim

src/sys/x86/ lets the firmware build and run on a Linux host for emulation and unit tests. Instead of a real RTOS port it uses a shim under src/sys/x86/freertos/: FreeRTOS tasks are implemented on POSIX threads (class Thread, src/sys/x86/freertos/port.cpp:42, using <pthread.h>, src/sys/x86/freertos/port.cpp:26), and blocking waits use a pthread condition-variable Event (src/sys/x86/freertos/event.h:23). The host System::scheduler_start() just calls vTaskStartScheduler() (src/sys/x86/sys/common/system.cpp:38) and shutdown maps onto std::exit() (src/sys/x86/sys/common/system.cpp:63) so a test run returns a process exit code. See Reference for how these host builds feed CI.

Boards (src/boards/)

A board directory pairs an NXP MCUXpresso .mex configuration with the C sources generated from it. Only the two .mex/board/ pairs below are in scope:

Board .mex processor board/ sources
src/boards/mcxn547helloworld/ MCXN547 (src/boards/mcxn547helloworld/mcxn547helloworld.mex:2) pin_mux.c, clock_config.c, peripherals.c, plus a trustzone/resource_config.c
src/boards/p3957_cxx/ MCXN556S (src/boards/p3957_cxx/p3957_cxx.mex:2) pin_mux.c, clock_config.c, peripherals.c

The .mex is the source of truth (pin labels such as THERM_OVERT and BMC I2C SDA live in the .mex and its generated pin_mux.c), and the generated code exposes the BOARD_Init* entry points the projects call: BOARD_InitBootPins (src/boards/mcxn547helloworld/board/pin_mux.c:73, src/boards/p3957_cxx/board/pin_mux.c:149), with clocks and peripherals in the sibling clock_config.c / peripherals.c. Board-specific electrical differences are documented per board, e.g. src/boards/mcxn547helloworld/note.md:3 records FLEXCOMM0 I²C at 100 kHz.

Projects (src/projects/)

A project is what PROJECT= selects. It owns the main() entry point(s), the big compile-time config.h, the signing parameters, and the linker/startup glue — one sys/<soc>/ subdirectory per platform it can target.

Per-core main.cpp

main() follows the same shape everywhere: disable IRQs, run the board’s BOARD_Init* functions (src/projects/mcxn547helloworld/core0/main.cpp:243), start the watchdog, create each subsystem task (mctp::Task::make() …, src/projects/mcxn547helloworld/core0/main.cpp:266), then hand control to FreeRTOS via common::System::inst().scheduler_start() (src/projects/mcxn547helloworld/core0/main.cpp:313).

mcxn547helloworld is dual-core, so it has both core0/ and core1/. Core0 is the full application; core1 is deliberately minimal — it inits MCMGR, makes only its IPC task (src/projects/mcxn547helloworld/core1/main.cpp:157) and starts the scheduler, with every other *::Task::make() commented out (src/projects/mcxn547helloworld/core1/main.cpp:173). The single-core p3957_cxx project has only a core0/.

config.h — the compile-time product definition

Each project’s config.h is a large constexpr description of the product: task/queue/event tables, GPIO map, USB VID/PID, telemetry, and feature flags. The EnableDualCore flag is what distinguishes the two board projects — true for mcxn547helloworld (src/projects/mcxn547helloworld/config.h:144) and false for p3957_cxx (src/projects/p3957_cxx/config.h:156). The per-task core assignment (TaskInfos) pins Ipc1 to Core1 and everything else to Core0 (src/projects/mcxn547helloworld/config.h:206). See Architecture for how these tables drive the runtime.

Linker & core1-image glue

For dual-core targets, core0’s image embeds core1’s binary. Core0 declares a .core1_image section — a placeholder byte array at build time (src/projects/mcxn547helloworld/core0/core1_image.c:18) that the build replaces with the real core1 image. The linker keeps that section (src/projects/mcxn547helloworld/core0/sys/mcxn556/linker_script.ld:66) and INCLUDEs a generated address map (src/projects/mcxn547helloworld/core0/sys/mcxn556/linker_script.ld:23) whose CORE1_RAM_START / CORE1_TEXT_START symbols (src/projects/mcxn547helloworld/core0/sys/mcxn556/generated_core1.ld:18) place core1. Core0’s main() then boots core1 from __core1_text_start__ (src/projects/mcxn547helloworld/core0/sys/mcxn556/linker_script.ld:34), passing that address into its IPC task (src/projects/mcxn547helloworld/core0/main.cpp:300). Alongside the linker script, each sys/<soc>/ subdir carries the platform’s FreeRTOSConfig.h, start.S, and gpio_interrupt_handler.cpp.

Signing parameters

Two JSON files per platform tell the signer (see Build System) how to package the image: an MBI (masked-boot-image) descriptor and an SB (secure-binary) descriptor. For example the MBI file sets "mbi": true (src/projects/mcxn547helloworld/core0/sign-parameters_mbi_mcxn556.json:2) while the SB file sets "sb4": true and lists the flash erase/load commands (src/projects/mcxn547helloworld/core0/sign-parameters_sb_mcxn556.json:3). Files are suffixed by SoC (_mcxn547, _mcxn556, _mcxn236) so one project can be signed for several platforms.

testrunner — the unit-test project

testrunner is the project used for host and on-target tests rather than a shipping product. Its x86 main() boots a minimal task set (MCTP, PLDM, flash, USB, logger), then creates every queue/event and runs the supervisor to completion, returning a pass/fail exit code (src/projects/testrunner/sys/x86/main.cpp:135). It also demonstrates the Ada/SPARK toolchain: test.ads exports an Ada procedure to C++ as ada_print_hello (src/projects/testrunner/test.ads:25), test.adb implements it by calling Nv.Common.Console.Print (src/projects/testrunner/test.adb:24), and the C++ side declares and calls it after adainit() (src/projects/testrunner/sys/x86/main.cpp:137). A Lattice CPLD stub stands in for hardware (src/projects/testrunner/sys/x86/main.cpp:44), configured from config.h (src/projects/testrunner/config.h:62). Like a board project it also carries a regconfig.cpp/regconfig.h register table (src/projects/testrunner/regconfig.cpp:26) and a powersensor.h. Its on-target variant lives under src/projects/testrunner/sys/mcxn236/main.cpp and its host variant under src/projects/testrunner/sys/x86/.

SDK overrides (src/overrides/)

src/overrides/ holds local replacements for standard-library / SDK sources that must run in the firmware’s freestanding environment. The chrono, thread, cstring, and cwchar headers are trimmed partial implementations — e.g. src/overrides/chrono:20 and src/overrides/thread:24 both note they are “partial implementation[s] that can run in freestanding mode”. src/overrides/libc.cpp is a small C runtime shim. Interpretation: these are put on the include path ahead of the SDK copies so the firmware gets the stripped-down versions without patching the SDK in place.

Next

</content>


Built with Just the Docs. Source-traced against NVIDIA/OpenSMA at 9b183d3 (v02.0020.0000). Methodology under appendices/trace-methodology.

This site uses Just the Docs, a documentation theme for Jekyll.