System Initialization¶
NSX provides a modular system initialization API in nsx_system.h that
replaces ad-hoc startup boilerplate with composable, order-aware building
blocks.
Quick Start¶
#include "nsx_system.h"
int main(void) {
// One call sets up: core runtime, caches, HP mode, ITM debug, SpotManager
nsx_system_config_t cfg = nsx_system_development;
nsx_system_init(&cfg);
ns_printf("Hello from NSX\n");
}
Presets¶
Three built-in presets cover the most common scenarios:
| Preset | Perf | Cache | Debug | SpotMgr | BSP Init |
|---|---|---|---|---|---|
nsx_system_development |
HIGH | yes | ITM/SWO | yes | full |
nsx_system_inference |
HIGH | yes | none | yes | full |
nsx_system_minimal |
LOW | no | none | no | skip |
Start from a preset and override individual fields:
nsx_system_config_t cfg = nsx_system_development;
cfg.skip_bsp_init = true; // skip the 2-second BSP stabilization delay
cfg.debug.transport = NSX_DEBUG_UART; // use UART instead of SWO
nsx_system_init(&cfg);
What nsx_system_init() Does¶
The init function performs six steps in a fixed, safe order:
flowchart TD
A["1. ns_core_init()"] --> B["2. Hardware init"]
B --> C["3. Cache enable"]
C --> D["4. Performance mode"]
D --> E["5. SpotManager profile"]
E --> F["6. Debug output"]
B -- "skip_bsp_init = false" --> B1["am_bsp_low_power_init()"]
B -- "skip_bsp_init = true" --> B2["Minimal: CPDLP + FPU"]
Ordering matters — each step depends on the previous:
- Core runtime — gates all other NSX API calls
- Hardware init — enables cache power domain (CPDLP), SpotManager, FPU
- Cache — requires CPDLP from step 2 (silently fails without it on Apollo5)
- Performance mode — HP clock (burst mode on Apollo3, MCU mode select on Apollo4+)
- SpotManager profile — requires SpotManager init from step 2
- Debug output — must come after BSP init (which disables debug for low power)
Performance Modes¶
The nsx_perf_mode_e enum maps to SoC-specific clock configurations:
| Mode | Apollo3/3P | Apollo4/4P | Apollo510 | Apollo330P/510L |
|---|---|---|---|---|
NSX_PERF_LOW |
48 MHz | 96 MHz LP | 96 MHz LP | LP |
NSX_PERF_MEDIUM |
96 MHz burst | 192 MHz HP | 192 MHz HP | HP1 |
NSX_PERF_HIGH |
96 MHz burst | 192 MHz HP | 192 MHz HP | HP2 |
Debug Output¶
Two transports are supported:
| Transport | How it works |
|---|---|
NSX_DEBUG_ITM |
SWO/ITM over JLink. On Apollo510 this handles DCU enable, TPIU config, SWO pin, and printf backend automatically. On Apollo¾ uses the BSP helper. |
NSX_DEBUG_UART |
UART through BSP pins. Calls am_bsp_uart_printf_enable(). |
NSX_DEBUG_NONE |
No debug output (production). |
After init, use ns_printf() for output — it routes through whichever
backend was configured.
Fine-Grained Control¶
For full control, skip nsx_system_init() and call individual building
blocks in order:
#include "nsx_system.h"
int main(void) {
// 1. Core runtime (required first)
ns_core_config_t core_cfg = { .api = &ns_core_V1_0_0 };
ns_core_init(&core_cfg);
// 2. Hardware init
nsx_minimal_hw_init(); // fast: CPDLP + FPU, no 2s delay
// nsx_hw_init(); // full: am_bsp_low_power_init()
// 3. Cache (requires CPDLP from step 2)
nsx_cache_enable(); // from nsx_mem.h
// 4. Performance mode
nsx_set_perf_mode(NSX_PERF_HIGH);
// 5. Debug output
nsx_debug_config_t dbg = { .transport = NSX_DEBUG_ITM };
nsx_debug_init(&dbg);
// 6. Application code...
ns_printf("Ready\n");
}
nsx_hw_init() vs nsx_minimal_hw_init()¶
nsx_hw_init() |
nsx_minimal_hw_init() |
|
|---|---|---|
| Calls | am_bsp_low_power_init() |
Platform-specific subset |
| Startup delay | ~2 seconds (AP510) | None |
| SIMOBUCK | Configured | Not configured |
| Clock gates | Optimized | Not configured |
| Cache | Enabled (AP5) | Not enabled (AP5) |
| FPU | Yes | Yes |
| CPDLP | Yes (AP5) | Yes (AP5) |
| SpotManager | Initialized | Initialized (AP5) |
| Debug/trace | Disabled | Not touched |
Use nsx_minimal_hw_init() when you want fast startup during development
and don't need full power optimization. Use nsx_hw_init() for production
deployments where power efficiency matters.
Platform Backends¶
nsx_system is split into platform-independent sequencing (nsx_system.c)
and per-SoC backends that implement five functions:
| Backend | SoCs | Key differences |
|---|---|---|
apollo3p/ |
Apollo3, Apollo3P | Burst mode, unified cache, no DCU, GPIO 41 SWO |
apollo4p/ |
Apollo4P, Apollo4L | LP/HP mode, unified cache, BSP handles DCU |
apollo510/ |
Apollo510, 510B, 510L, 5A, 5B, 330P | Split I/D cache, CPDLP, SpotManager, manual DCU+ITM |
The correct backend is selected automatically by CMake via NSX_SOC_FAMILY.
Common Pitfalls¶
Cache silently not enabled (Apollo5)
On Apollo5 family, am_hal_cachectrl_icache_enable() checks
PWRMODCTL->CPDLPSTATE and returns failure silently if the cache
power domain is not active. Without caches, inference runs 3–4x slower
with no visible error. Always call nsx_hw_init() or
nsx_minimal_hw_init() before nsx_cache_enable().
BSP disables debug by default
am_bsp_low_power_init() calls am_hal_debug_trace_disable() for
minimum power. If you need ITM/SWO output, configure debug after
BSP init — which nsx_system_init() handles automatically.
SWO/ITM on Apollo510 requires manual setup
The BSP's am_bsp_itm_printf_enable() on Apollo510 fails silently
because the DCU isn't enabled at early init. nsx_debug_init() with
NSX_DEBUG_ITM handles the full DCU → TPIU → SWO → printf chain.
SpotManager is Apollo5-family only
The spot_mgr_profile config field is a no-op on Apollo3 and Apollo4.
It's safe to leave enabled in portable code.