AkiraOS BSP Porting Guide

End-to-end instructions for bringing AkiraOS to new hardware in one week.


Table of Contents

  1. Prerequisites
  2. BSP Files
    1. Directory structure
    2. board.yml
    3. .yaml — board target
    4. Kconfig.<board-name>
    5. board.cmake
    6. <board-name>-pinctrl.dtsi
    7. <board-name>_<soc>_procpu.dts
    8. <board-name>_<soc>_procpu_defconfig
    9. First build smoke-test
  3. Boot and Shell
  4. WASM Runtime
  5. First WASM App
  6. Flash Partitions and OTA
    1. Flash sizing guide
    2. OTA
  7. Validation
    1. Platform HAL extension
    2. Custom driver registration
    3. PSRAM configuration
    4. WASM runtime tuning
  8. Go/No-Go Checklist
  9. Common Errors
  10. References

Prerequisites

Tool Minimum version Install
west 1.2.0 pip install west
Zephyr SDK 0.16.8 SDK releases
CMake 3.20 via system package manager
Python 3.10 via system package manager
AkiraSDK same minor as AkiraOS included as git submodule (AkiraSDK/)

Initialize the workspace once:

git clone https://github.com/your-org/AkiraOS.git
cd AkiraOS
west init -l .
cd ..
west update

BSP Files

Directory structure

Copy the template scaffold and rename every file, replacing template with your board identifier and FIXME_SOC with the Zephyr SoC name:

boards/
├── <board-name>/                         ← board definition directory
│   ├── board.yml
│   ├── <board-name>_<soc>_procpu.yaml
│   ├── Kconfig.<board-name>
│   ├── board.cmake
│   ├── <board-name>-pinctrl.dtsi
│   ├── <board-name>_<soc>_procpu.dts
│   └── <board-name>_<soc>_procpu_defconfig
└── <board-name>_<soc>_procpu.overlay     ← application overlay (flat, next to other boards)
    <board-name>_<soc>_procpu.conf        ← application conf  (flat)

board.yml

Defines the board identity for the Zephyr meta-tool layer. The vendor field must match an entry in zephyr/boards/vendor-prefixes.txt. If your company is not listed, add a line to the repo copy at the root of this workspace.

board:
  name: my_sensor_node        # lowercase, hyphens OK
  full_name: "MySensorNode (nRF54L15-QFAA-R7)"
  vendor: mycompany
  socs:
    - name: nrf54l15          # must match zephyr/soc/ subdirectory name

.yaml — board target

identifier: my_sensor_node/nrf54l15/cpuapp
name: MySensorNode CPUAPP
type: mcu
arch: arm                     # xtensa | arm | riscv
toolchain:
  - zephyr
supported:
  - gpio
  - uart
  - i2c
  - spi
  - watchdog
  - entropy
  - bluetooth                 # remove if absent
vendor: mycompany

Kconfig.<board-name>

config BOARD_MY_SENSOR_NODE
    select SOC_NRF54L15_CPUAPP

Browse zephyr/soc/ for the correct SOC_* symbol. For ESP32-S3 modules the symbol is SOC_ESP32S3_MINI_N8 regardless of flash/PSRAM variant (those are set via CONFIG_ESPTOOLPY_FLASHSIZE_* and CONFIG_ESP_SPIRAM_SIZE).

board.cmake

Uncomment the runner block matching your debug probe (OpenOCD / J-Link / esptool). For J-Link set --device to the exact string shown in J-Link Commander’s ShowDevices output. For esptool adjust --esp-flash-size and --esp-app-address to match your slot0_partition offset.

<board-name>-pinctrl.dtsi

Map every peripheral signal to a physical GPIO number. CS lines are not listed here — they go in cs-gpios inside the &spiN node.

Include the correct SoC pinctrl header:

SoC family Header
ESP32-S3 <dt-bindings/pinctrl/esp32s3-pinctrl.h>
nRF54L / nRF52 / nRF53 <zephyr/dt-bindings/pinctrl/nrf-pinctrl.h>
STM32 <zephyr/dt-bindings/pinctrl/stm32-pinctrl.h>

<board-name>_<soc>_procpu.dts

  1. #include "<your-soc>.dtsi" — provides the node skeleton.
  2. Optionally #include an MCUboot partition DTSI (ESP32 provides one in the Zephyr tree; other SoCs define partitions inline).
  3. Set model, compatible, chosen, aliases.
  4. Enable GPIO controllers.
  5. Wire UART/SPI/I2C with pinctrl references.
  6. Define buttons, LEDs, and any board-specific sensor nodes.
  7. Add the flash partition table (see Flash sizing guide).

<board-name>_<soc>_procpu_defconfig

Only put symbols here that are unconditionally required regardless of application config. Keep this minimal:

CONFIG_CONSOLE=y
CONFIG_SERIAL=y
CONFIG_UART_CONSOLE=y
CONFIG_GPIO=y
CONFIG_CLOCK_CONTROL=y

First build smoke-test

cd ..
unset ZEPHYR_BASE
west build --pristine -b my_sensor_node/nrf54l15/cpuapp AkiraOS \
  -d build -- -DMODULE_EXT_ROOT=AkiraOS

Expected: CMake configure succeeds and build/zephyr/zephyr.elf is produced. If Kconfig reports SOC_FIXME undefined, your Kconfig.<board> select is wrong.


Boot and Shell

Enable UART in the overlay and confirm UART0 pinctrl matches your schematic:

&uart0 { status = "okay"; current-speed = <115200>; };

Flash and connect a serial terminal at 115200 8N1. Expected banner:

*** Booting Zephyr OS build v4.3.0 ***
AkiraOS v1.5.4 — Hardened Runtime
AkiraOS:~$

If the banner doesn’t appear:

  • Check TX/RX are not swapped (uart0_default in pinctrl DTSI).
  • Verify CONFIG_UART_CONSOLE=y and CONFIG_SHELL_UART_BACKEND=y in your conf.
  • Try reducing baud to 9600 and increasing with current-speed.

WASM Runtime

Minimum conf to enable the WASM runtime:

CONFIG_AKIRA_WASM_RUNTIME=y
CONFIG_WAMR_HEAP_SIZE=131072          # 128 KB starting point
CONFIG_AKIRA_WASM_APP_STACK_SIZE=8192 # 8 KB per app thread
CONFIG_MAX_CONTAINERS=2

Verify the runtime initializes:

AkiraOS:~$ akira runtime status
WAMR runtime: ready
Heap:   128 KB available
Slots:  0/2 running

If you see a stack overflow: increase CONFIG_AKIRA_WASM_APP_STACK_SIZE.
If the system crashes at boot with heap exhausted: reduce CONFIG_WAMR_HEAP_SIZE or add PSRAM (see PSRAM configuration).


First WASM App

Build the hello-world app from AkiraSDK:

# From the AkiraSDK directory
cd AkiraOS/AkiraSDK
wasi-sdk/bin/clang --target=wasm32-wasi \
  -nostdlib -Wl,--no-entry -Wl,--export-all \
  -I include \
  wasm_apps/hello/main.c -o hello.wasm

Copy hello.wasm to the LittleFS filesystem via USB mass-storage or the akira fs shell commands, then run:

AkiraOS:~$ akira app install /lfs/hello.wasm
AkiraOS:~$ akira app run hello
Hello from WASM!

Flash Partitions and OTA

Flash sizing guide

Calculate your partition layout from the bottom up:

Partition Minimum Recommended Notes
MCUboot (boot) 64 KB 128 KB Must be read-only
App (slot0) 256 KB 1 MB Depends on feature set enabled
OTA staging (slot1) = slot0 = slot0 Must equal slot0 for swap-based OTA
NVS settings 32 KB (2 erase blocks) 32 KB BT bonds, Wi-Fi credentials
LittleFS 256 KB 512 KB WASM app storage

Minimum viable total: 512 KB (no OTA, no LittleFS, minimal app).
Standard: 4 MB (OTA + 512 KB data).
Full: 8–16 MB (multiple large WASM apps on SD or LittleFS).

In your overlay:

&flash0 {
    partitions {
        compatible = "fixed-partitions";
        #address-cells = <1>;
        #size-cells    = <1>;

        // Offsets MUST match boot_partition end + slot0_partition end.
        akira_settings_nvs_partition: partition@220000 {
            label = "akira_settings_nvs";
            reg   = <0x00220000 DT_SIZE_K(32)>;
        };
        lfs1_partition: partition@228000 {
            label = "lfs_storage";
            reg   = <0x00228000 DT_SIZE_K(256)>;
        };
    };
};

Verify offsets with:

AkiraOS:~$ akira storage list

OTA

CONFIG_MCUBOOT=y
CONFIG_AKIRA_OTA=y
CONFIG_BOOTLOADER_MCUBOOT=y

Run a loopback OTA test:

AkiraOS:~$ akira ota status
slot0: active  (0x020000 – 0x11FFFF)
slot1: empty   (0x120000 – 0x21FFFF)

Validation

Platform HAL extension

If your SoC is not in the existing list, add a detection block to src/drivers/platform_hal.h:

#elif defined(CONFIG_SOC_MY_SOC)
#define AKIRA_PLATFORM_NATIVE_SIM 0
#define AKIRA_PLATFORM_ESP32      0
#define AKIRA_PLATFORM_ESP32S3    0
#define AKIRA_PLATFORM_ESP32C6    0
#define AKIRA_PLATFORM_ESP32H2    0
#define AKIRA_PLATFORM_STM32      0
#define AKIRA_PLATFORM_NORDIC     0
#define AKIRA_PLATFORM_MY_BOARD   1   // add this flag

Then update platform_hal.c to handle AKIRA_PLATFORM_MY_BOARD for any platform-specific initialization it performs (clock setup, power domains, etc.).

Custom driver registration

Register hardware-specific drivers at init time using the driver registry:

#include "drivers/driver_registry.h"

static const driver_ops_t my_imu_ops = {
    .init  = my_imu_init,
    .read  = my_imu_read,
    .ioctl = my_imu_ioctl,
};

// Called from your board init or SYS_INIT:
driver_registry_register("my_imu", DRIVER_TYPE_SENSOR_IMU, &my_imu_ops);

WASM apps retrieve the driver by name via akira_sensor_read() in AkiraSDK.

PSRAM configuration

PSRAM is required to run more than 2 WASM apps concurrently (see min-hw-requirements.md).

ESP32-S3 with OPI PSRAM (N8R8 / N16R8 module):

CONFIG_ESP_SPIRAM=y
CONFIG_ESP_SPIRAM_SIZE=8388608          # 8 MB
CONFIG_ESP_SPIRAM_HEAP_SIZE=4194304     # 4 MB for WAMR heap
CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_SPEED_80M=y
CONFIG_MEMC=y
CONFIG_SHARED_MULTI_HEAP=y
CONFIG_WAMR_HEAP_SIZE=1048576          # 1 MB — draws from PSRAM heap

In the DTS overlay:

&psram0 {
    size   = <DT_SIZE_M(8)>;
    status = "okay";
};

WASM runtime tuning

Symbol Default Description
CONFIG_WAMR_HEAP_SIZE 262144 Soft quota hint for WAMR allocator (bytes)
CONFIG_AKIRA_WASM_APP_STACK_SIZE 8192 Stack per WASM app thread (bytes)
CONFIG_AKIRA_WASM_APP_PRIORITY 14 Zephyr thread priority for WASM threads
CONFIG_MAX_CONTAINERS 8 Maximum simultaneous running WASM apps
CONFIG_WAMR_AOT_SUPPORT n Enable AOT compilation (requires toolchain)

Enable AOT for production to eliminate interpreter overhead: CONFIG_WAMR_AOT_SUPPORT=y (ESP32-S3 and native_sim only in current release).


Go/No-Go Checklist

# Test Command / Action Pass criteria
1 Build west build -b <board> Zero errors
2 Boot Power cycle Shell prompt within 3 s
3 Watchdog akira wdt test Board resets and recovers
4 UART Terminal at 115200 Characters echo correctly
5 Flash akira storage list Correct offsets reported
6 LittleFS akira fs ls /lfs Lists directory without error
7 NVS akira settings set test_key hello then reboot Value persists
8 WASM runtime akira runtime status ready
9 WASM app install akira app install /lfs/hello.wasm No error
10 WASM app run akira app run hello Expected output printed
11 Display (if fitted) akira display clear 0xF800 Screen turns red
12 OTA (if enabled) akira ota status Correct slot addresses
13 BLE (if enabled) akira ble scan RSSI readings appear
14 Sanitizer west build -b native_sim All 54 ztests pass

Common Errors

Error message Likely cause Fix
__device_dts_ord_N undeclared cs-gpios phandle points to disabled node Redirect CS GPIO to a direct GPIO pin; see boards/akiraconsole_prod_esp32s3_procpu.overlay comments
SOC_FIXME undefined Kconfig symbol not found Check Kconfig.<board> select value against zephyr/soc/ tree
heap exhausted at boot WAMR heap > available SRAM Reduce CONFIG_WAMR_HEAP_SIZE or add PSRAM
pinmux <FIXME> does not compile SoC pinctrl header not included Add correct #include in pinctrl DTSI
Stack overflow in app thread AKIRA_WASM_APP_STACK_SIZE too small Increase by 4 KB increments until stable
Display stays black Wrong DC/RST GPIO or wrong polarity Compare dc-gpios / reset-gpios against schematic

References


Copyright © 2025-2026 AkiraOS Project. Licensed under GNU GPL v3.