Skip to main content

Quick Start

Build and run the gpio-button-led example end-to-end. By the end you'll have a working native_sim simulation and a path to real silicon.

What you need

  • The Alp SDK installed

  • The tan CLI (0.5.1) — the SDK's sole user-facing command. It ships from its own repo (alplabai/tan-cli) on its own version line, and it is a Python program released as a self-contained PyInstaller freeze: no Rust toolchain, no rustup, no host Python interpreter.

    curl -fsSL https://raw.githubusercontent.com/alplabai/tan-cli/main/install.sh | sh
    # Windows PowerShell: irm https://raw.githubusercontent.com/alplabai/tan-cli/main/install.ps1 | iex
  • A ZEPHYR_BASE environment variable pointing at the Zephyr checkout (set by bootstrap.sh on Linux/macOS/WSL2, bootstrap.ps1 on native Windows)

Hardware is not required for native_sim. To target real silicon, jump to step 4.

Step 1 — Look at the example

Open alp-sdk/examples/gpio-button-led. Every example carries:

gpio-button-led/
├── board.yaml # declarative project config
├── prj.conf # empty (the loader generates alp.conf)
├── CMakeLists.txt # invokes the orchestrator at configure time
├── src/main.c # the application
└── boards/ # per-board overlay files

The minimum-viable board.yaml:

som:
sku: E1M-AEN801 # your MPN — the SDK ships a preset
# at metadata/e1m_modules/<MPN>.yaml

preset: e1m-evk # stock board preset, or write the board out inline

cores:
m55_hp:
# os: omitted → SoM topology default (Cortex-M → zephyr).
app: ./src
peripherals: [gpio]

diagnostics:
log_level: info

That's the whole config. The orchestrator resolves som.sku to the right silicon, picks up the board preset, and generates the per-slice native config (Zephyr Kconfig fragment, CMake -D flags, or Yocto local.conf) per core declared under cores:. Cores omitted inherit the SoM preset's topology: defaults — see the board.yaml reference for the full schema and the heterogeneous builds walkthrough for dual-OS projects.

See the board.yaml reference for the full schema.

Step 2 — Build under native_sim

cd alp-workspace/alp-sdk/examples/peripheral-io/gpio-button-led
tan run

tan run is the quick single-image loop: it resolves the project from the current directory (walking up to the nearest board.yaml), builds it under native_sim, and then executes the produced binary. --board <board> builds for real hardware instead; add --flash to program it after the build.

Expected output:

*** Booting Zephyr OS build v4.4.1 ***
[gpio] init button=ALP_E1M_GPIO_IO0, led=ALP_E1M_GPIO_IO1
[gpio] led=0 status=0
[gpio] led=1 status=0
...
[gpio] is_pressed -> status=0 pressed=1
[gpio] done

status=0 means ALP_OK. pressed=1 is Zephyr's gpio_emul default "input is low" report.

What tan run did — and the commands around it

tan is the SDK's sole user-facing CLI. ADR-0020 Phase 4 (alp-sdk v0.12.0) retired the SDK-side build executor: no alp binary is installed anywhere any more, and the west alp-build / alp-image / alp-flash / alp-clean / alp-size / alp-renode extensions went with it. alp-sdk is plans-only for this surface — tan consumes alp_orchestrate --emit build-plan and --emit system-manifest, then runs west / bitbake / cmake per slice itself.

tan run is the quick single-image loop. The full multi-slice pipeline — every core board.yaml declares, in one command — is tan build:

CommandWhat it does
tan buildValidates board.yaml, fans out into per-core slices, seeds system-manifest.yaml.
tan imageConsumes the manifest, assembles a flashable bundle (build/image-bundle/).
tan flashWalks the manifest's boot_order: and programs each piece with the right backend.
tan cleanRemoves build outputs.
tan renodeBoots the image in Renode (headless smoke; --sim-mode for the studio simulator).
tan sizeReports per-slice flash/RAM footprint against the SoM budget (--fail-over-budget).
tan generateWrites the board-derived config files, no build. Nine targets are in the default (--all) set — zephyr-conf, dts-overlay, native-sim-overlay, cmake-args, yocto-conf, carrier-netlist, west-libraries, hw-info-h, os-topology — and three are explicit-only: zephyr-board (requires --core), composed-route-table, ipc-contract-h.

There is no tan emit verb. Reach for tan generate --target <target> when you want one artefact.

The scaffold / validate / inspect / host-tool verbs (tan init, tan new-som, tan validate, tan doctor, tan monitor, tan model, tan explain, tan faultdecode) ride the same program. tan does not forward any verb to python -m alp_cli — since v0.5.0-rc1 tan is itself Python, and model / monitor / faultdecode / new-som are native Python inside it. See the tan CLI reference.

Four west alp-* commands survive the move. These resolve only when alp-sdk is the workspace's manifest repo — see Installation:

CommandWhat it does
west alp-migrateVersions and migrates a project's board.yaml.
west alp-lockWrites or verifies alp.lock, the dependency lock.
west alp-qualityRuns the quality-task registry for a profile (JSON / JUnit / SARIF).
west alp-emitPrints one generated artefact from board.yaml, no build — the orchestrator subset of the catalogue (system-manifest, ipc-contract-h, dts-reservations, dts-partitions, storage-mounts-c, tfm-sysbuild-conf, build-plan).

Under the hood tan build runs four steps:

  1. Validates the app's board.yaml (JSON Schema + SoM SKU preset + board preset + hw_rev / SDK-version compatibility + per-slice peripherals: vs SoC caps + cores: keys against the SoM preset's topology: + cross-field validator rules).
  2. Fans out into per-core slice build directories (build/<core>-zephyr/, build/<core>-yocto/, etc.) and materialises per-slice Kconfig fragments + Yocto local.conf snippets.
  3. Emits cross-slice artefactsbuild/system-manifest.yaml, build/generated/alp/system_ipc.h, build/generated/dts-reservations.dtsi — byte-stable across rebuilds.
  4. Delegates to west / bitbake / cmake per slice, whichever backend that slice needs.

Step 3 — Read the source

Open examples/gpio-button-led/src/main.c. Every example is annotated as teaching material:

#include <alp/peripheral.h>
#include <alp/e1m_pinout.h>

int main(void) {
alp_gpio_t *led = alp_gpio_open(&(alp_gpio_config_t){
.pin_id = ALP_E1M_GPIO_IO1,
.direction = ALP_GPIO_DIR_OUTPUT,
});
if (led == NULL) {
printk("[gpio] led open failed: err=%d\n", (int)alp_last_error());
return -1;
}

alp_gpio_t *button = alp_gpio_open(&(alp_gpio_config_t){
.pin_id = ALP_E1M_GPIO_IO0,
.direction = ALP_GPIO_DIR_INPUT,
.pull = ALP_GPIO_PULL_UP,
});

for (int i = 0; i < 4; i++) {
alp_gpio_write(led, i & 1);
k_msleep(500);
}

bool pressed;
alp_gpio_read(button, &pressed);
printk("[gpio] is_pressed pressed=%d\n", pressed);

alp_gpio_close(led);
alp_gpio_close(button);
return 0;
}

Key points:

  • Handles (alp_gpio_t *) are opaque and obtained from alp_*_open().
  • Failures stamp alp_last_error() (thread-local) — check it whenever a handle is NULL.
  • Instance IDs (ALP_E1M_GPIO_IO1) are E1M-portable: this code works on every conformant SoM.
  • alp_*_close() releases the handle — observe it for clean shutdown.

See the <alp/peripheral.h> reference.

Step 4 — Target real silicon

There is no -b / --board selector: the target comes from the project's own board.yaml (som.sku + preset), which tan build resolves to the qualified Zephyr board string for you.

For the E1M EVK populated with an AEN SoM (single-OS, Zephyr):

cd alp-workspace/alp-sdk/examples/peripheral-io/gpio-button-led
tan build
tan flash

For the E1M-X EVK populated with a V2N SoM (heterogeneous, A55 Yocto + M33 Zephyr):

cd alp-workspace/alp-sdk/examples/multicore/rpmsg-v2n
tan build # fans out per-core
tan image # assemble the bundle
tan flash # boot_order-aware programming

tan flash walks system-manifest.yaml's boot_order: and dispatches each artefact to the right backend — vendor flasher for the SoC, openocd-via-SWD for the GD32 helper MCU, USB-CDC bootloader for the CC3501E. No developer-side tool-selection.

Each example's boards/ directory carries an overlay that maps the application's alp,pin-array slots to specific EVK pins. The overlay applies automatically when you build for the matching board.

For SoMs without a published EVK board file yet, write your own board file under alplabai/alp-zephyr-modules or a private board layer. See docs/porting-new-som.md.

Step 5 — Explore more examples

Every wrapped peripheral has a corresponding minimal example:

cd alp-workspace
for ex in peripheral-io/pwm-led-fade peripheral-io/adc-voltmeter \
peripheral-io/i2c-scanner peripheral-io/spi-loopback \
peripheral-io/uart-echo peripheral-io/uart-rx-ringbuf \
peripheral-io/can-loopback peripheral-io/qenc-readout \
power-timing/counter-alarm power-timing/rtc-clock \
power-timing/wdt-feed audio/i2s-tone; do
(cd alp-sdk/examples/$ex && tan run)
done

On native_sim most peripherals don't have emul controllers (only I²C / SPI / GPIO / UART do). Examples that target unwrapped peripherals exit after printing the alp_last_error() diagnostic — that's expected and proves the wrapper plumbing compiles and links cleanly.

End-to-end reference apps:

Heterogeneous flagships (one board.yaml drives both halves):

Troubleshooting

SymptomCause / fix
tan: command not foundtan ships separately from the SDK; install it with curl -fsSL https://raw.githubusercontent.com/alplabai/tan-cli/main/install.sh | sh (Windows PowerShell: irm https://raw.githubusercontent.com/alplabai/tan-cli/main/install.ps1 | iex). No Rust toolchain and no host Python interpreter are involved.
alp: command not found, or west: unknown command "alp-build"Retired in alp-sdk v0.12.0 (ADR-0020 Phase 4). The alp binary and the west alp-{build,image,flash,clean,size,renode} extensions are gone — use tan instead. west alp-migrate / alp-lock / alp-quality / alp-emit still need a bootstrapped workspace (west init -m https://github.com/alplabai/alp-sdk).
validate_board_yaml.py exit 2som.sku doesn't match any preset under metadata/e1m_modules/, or cross-field validator rule failed. Check spelling and the rule hint.
validate_board_yaml.py exit 3hw_rev incompatible with this SDK version. Update SDK or pick a compatible rev.
Handle is NULL and alp_last_error() == ALP_ERR_NOSUPPORTPeripheral wrapper not implemented for this OS/SoM yet. Check the test plan.
Handle is NULL and alp_last_error() == ALP_ERR_OUT_OF_RANGERequested config exceeds the SoC's documented caps (e.g. 16-bit ADC on a 12-bit SoC).

Full troubleshooting index: docs/troubleshooting.md.

What next?

Questions about this page? Discuss in Community Forum