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
- A
ZEPHYR_BASEenvironment variable pointing at the Zephyr checkout (set bybootstrap.sh)
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 alp_orchestrate.py at configure time
├── src/main.c # the application
└── boards/ # per-board overlay files
The minimum-viable board.yaml (schema v2):
schema_version: 2
som:
sku: E1M-AEN701 # your MPN — the SDK ships a preset
# at metadata/e1m_modules/<MPN>.yaml
carrier:
name: E1M-EVK # or your own custom carrier name
cores:
m55_hp:
os: zephyr # zephyr | yocto | baremetal | off
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 carrier 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
west alp-build -b native_sim/native/64 alp-sdk/examples/gpio-button-led
west build -d build -t run
Expected output:
*** Booting Zephyr OS build v4.4.0 ***
[gpio] init button=E1M_GPIO_IO0, led=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 west alp-build did
west alp-build is one of five west alp-* commands the SDK ships (v0.6 split the old monolithic command into focused tools):
| Command | What it does |
|---|---|
west alp-build | Validates board.yaml, fans out into per-core slices, emits system-manifest.yaml. |
west alp-image | Consumes the manifest, assembles a flashable bundle (build/image-bundle/). |
west alp-flash | Walks the manifest's boot_order: and programs each piece with the right backend. |
west alp-clean | Tears down per-slice build dirs idempotently. |
west alp-renode | Boots the dual-OS image in Renode and drives the RPMsg handshake smoke test. |
Under the hood west alp-build runs four steps:
- Validates the app's
board.yaml(schema v2 + SoM SKU preset + carrier preset +hw_rev/ SDK-version compatibility + per-sliceperipherals:vs SoC caps +cores:keys against the SoM preset'stopology:). - Fans out into per-core slice build directories (
build/<core>-zephyr/,build/<core>-yocto/, etc.) and emits per-slice Kconfig fragments + Yoctolocal.confsnippets. - Emits cross-slice artefacts —
build/system-manifest.yaml,build/generated/alp/system_ipc.h,build/generated/dts-reservations.dtsi— byte-stable across rebuilds. - Delegates to
west buildper slice. Any flags after the recognised ones pass through verbatim.
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 = 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 = 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 fromalp_*_open(). - Failures stamp
alp_last_error()(thread-local) — check it whenever a handle isNULL. - Instance IDs (
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
For the E1M EVK populated with an AEN SoM (single-OS, Zephyr):
west alp-build -b alp_e1m_evk_aen alp-sdk/examples/gpio-button-led
west alp-flash
For the E1M-X EVK populated with a V2N SoM (heterogeneous, A55 Yocto + M33 Zephyr):
west alp-build alp-sdk/examples/rpmsg-v2n # fans out per-core
west alp-image # assemble the bundle
west alp-flash # boot_order-aware programming
west alp-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:
for ex in pwm-led-fade adc-voltmeter i2c-scanner spi-loopback \
uart-echo uart-rx-ringbuf counter-alarm rtc-clock wdt-feed \
can-loopback i2s-tone qenc-readout; do
west build -b native_sim/native/64 alp-sdk/examples/$ex -d build/$ex
west build -d build/$ex -t 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:
examples/aen/edgeai-vision-aen/— camera → Ethos-U inference → display overlayexamples/iot-connected-camera/— camera → DRP-AI → MQTT publish
Heterogeneous flagships (one board.yaml drives both halves):
examples/rpmsg-v2n/— V2N101 A55 (Yocto) ↔ M33-SM (Zephyr) over RPMsg.examples/rpmsg-aen/— AEN701 A32 (Yocto) ↔ M55-HP (Zephyr).examples/rpmsg-imx93/— iMX93 A55 (Yocto) ↔ M33 (Zephyr).examples/heterogeneous-offload/— A-cluster delegates FFT to the M peer over RPMsg.
Troubleshooting
| Symptom | Cause / fix |
|---|---|
west alp-build: command not found | Workspace not bootstrapped; run west init -m https://github.com/alplabai/alp-sdk first. |
validate_board_yaml.py exit 2 | som.sku doesn't match any preset under metadata/e1m_modules/. Check spelling. |
validate_board_yaml.py exit 3 | hw_rev incompatible with this SDK version. Update SDK or pick a compatible rev. |
Handle is NULL and alp_last_error() == ALP_ERR_NOSUPPORT | Peripheral wrapper not implemented for this OS/SoM yet. Check the test plan. |
Handle is NULL and alp_last_error() == ALP_ERR_OUT_OF_RANGE | Requested 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?
board.yamlreference — the full schema (v2)- Heterogeneous builds — dual-OS project walkthrough
- Firmware quickstart — per-SoM patterns
- API reference — including
<alp/rpc.h>for cross-core RPC - Examples catalogue