Skip to main content

Firmware Engineer Quickstart

This guide takes a firmware engineer from "I have an E1M-X module on the bench" to a working application built against the SDK. It sits alongside the Quick Start walk-through; this page focuses on the choices and patterns that matter when you're targeting a specific SoM and writing real firmware.

Pick a target

If your hardware is...som.skuCarrier default
E1M-AEN family on the E1M EVKE1M-AEN701 (etc.)E1M-EVK
E1M-X V2N101 / V2N102 on E1M-X-EVKE1M-V2N101E1M-X-EVK
E1M-X V2N-M1 (V2M101 / V2M102)E1M-V2M101E1M-X-EVK
E1M-NX9101 (NXP i.MX 93)E1M-NX9101E1M-EVK

The per-SoM page covers what's populated, which examples target it, and the bring-up flow.

Workspace setup

If you haven't already, follow the Quick Start §1–2. That gets you a alp-workspace/ with alp-sdk/, zephyr/, and the standard modules.

Your first board.yaml

Example for a V2N101 application that exercises the on-module GD32 bridge:

schema_version: 2

som:
sku: E1M-V2N101

carrier:
name: E1M-X-EVK

cores:
m33_sm:
os: zephyr
app: ./src
peripherals: [spi, i2c]

chips:
- gd32g553

diagnostics:
log_level: info

west alp-build validates this, generates the build-time config, and delegates to west build. See the board.yaml reference.

Pick a starting example

The examples/ tree carries reference apps that double as tutorials. Comment density is ~50 % so the source teaches by itself.

Cross-family examples (work on any SoM)

ExampleWhat it shows
gpio-button-ledOpen a GPIO, set up input + output, basic patterns.
i2c-scannerWalk the I²C bus, report devices that ACK.
pwm-led-fadePWM channel open + duty sweep.
adc-voltmeterSample an ADC channel; convert to millivolts.
uart-echo / uart-rx-ringbufUART TX / RX, with optional byte-granular ring buffer.
rtc-clockSet + read the SoC RTC.
wdt-feedWatchdog open + feed cadence.

V2N / V2N-M1-specific examples

ExampleWhat it shows
v2n-gd32-bridge-pingPING + GET_VERSION round-trip on both SPI + I²C transports
v2n-board-id-readoutRead the SoM EEPROM manifest + assert SKU
v2n-ethernet-dualBring up both RTL8211FDI PHYs
v2n-pwm-fan-controlRamp a GD32-side PWM channel along a five-stop fan curve

Build any of them:

cd alp-workspace
west alp-build -b <board> alp-sdk/examples/<name>
west build -d build -t run # native_sim
# or:
west flash # real silicon

Idiomatic patterns

Open an I²C bus + talk to a chip

#include <alp/peripheral.h>
#include <alp/chips/tmp112.h>

alp_i2c_t *bus = alp_i2c_open(&(alp_i2c_config_t){
.bus_id = 0u,
.bitrate_hz = 400000u,
});
if (bus == NULL) {
printk("[i2c] open failed: err=%d\n", (int)alp_last_error());
return;
}

tmp112_t temp;
if (tmp112_init(&temp, bus, 0x40) != ALP_OK) {
printk("[tmp112] init failed\n");
}

Every on-module chip driver follows the same shape: <chip>_init(&ctx, bus, addr_or_handle) then per-feature getters / setters. Drivers under chips/<part>/<part>.c; public headers under <alp/chips/<part>.h>.

Use the GD32 bridge from V2N firmware

The V2N's GD32G553 supervisor MCU owns every E1M-standard analog + counter peripheral plus side-channel GPIOs: eight PWM channels, eight-channel ADC bank, both DAC outputs, four quadrature encoders, the Wi-Fi/BT REG_ON pins, the OPTIGA reset, and the cached PMIC status forwarder. Reach it over SPI (fast path) or I²C (management path):

alp_spi_t *spi = alp_spi_open(&(alp_spi_config_t){
.bus_id = 1u,
.freq_hz = 10000000u,
.mode = ALP_SPI_MODE_0,
.bits_per_word = 8u,
.cs_pin_id = 0u,
});
alp_i2c_t *brd_i2c = alp_i2c_open(&(alp_i2c_config_t){
.bus_id = 0u,
.bitrate_hz = 400000u,
});

gd32g553_t bridge;
gd32g553_init(&bridge, spi, brd_i2c, GD32G553_BRIDGE_DEFAULT_I2C_ADDR);

uint32_t period_ns = 1000000u; // 1 kHz
uint32_t duty_ns = 500000u; // 50 %
gd32g553_pwm_set(&bridge, /* channel */ 0u, period_ns, duty_ns);

Full wire spec: docs/gd32-bridge-protocol.md.

Monitor the PMIC fleet

On V2N + V2N-M1 the secondary PMIC's status reflects rail health. Idiomatic supervisor task:

da9292_t pmic;
da9292_init(&pmic, brd_i2c, DA9292_I2C_ADDR_V2N);

while (1) {
da9292_status_t s;
if (da9292_get_status(&pmic, &s) == ALP_OK) {
if (s.temp_warn || s.vin_uvlo || !s.ch1_pg) {
log_warning(&s);
}
}
k_msleep(1000);
}

Dual Ethernet on V2N

static int my_mdio_read(uint8_t phy_addr, uint8_t reg, uint16_t *val, void *user) {
return zephyr_mdio_read(user, phy_addr, reg, val);
}
static int my_mdio_write(uint8_t phy_addr, uint8_t reg, uint16_t val, void *user) {
return zephyr_mdio_write(user, phy_addr, reg, val);
}

rtl8211fdi_t phy0;
rtl8211fdi_init(&phy0, /* phy_addr */ 0,
my_mdio_read, my_mdio_write, mdio_dev);
rtl8211fdi_soft_reset(&phy0, 500000);
rtl8211fdi_restart_autoneg(&phy0);

V2N-M1: bring DEEPX up before opening PCIe

Three extra steps beyond V2N base:

  1. da9292_v2n_m1_enable_deepx_rail(&pmic, 50000) — the 0.75 V DEEPX rail on the secondary PMIC's CH2.
  2. ACK-probe the three DEEPX TPS628640 instances at 0x44 / 0x48 / 0x4F to confirm population.
  3. deepx_dxm1_bring_up(&dxm1, DEEPX_DXM1_DEFAULT_BOOT_US) — the PCIe muxes + M1_RESET sequencer.

Full sequence with code: docs/bring-up-v2n-m1.md.

V2N: share one BRD_I2C handle across the on-module fleet

The V2N's board-management I²C bus (BRD_I2C) hosts both PMICs, the RTC, OPTIGA Trust M, TMP112, the clock generator, and the EEPROM. Open the bus once at boot and pass the same alp_i2c_t * handle into every chip driver — every chips/<part>/ API accepts a borrowed bus pointer; none take ownership.

alp_i2c_t *brd_i2c = alp_i2c_open(&(alp_i2c_config_t){
.bus_id = 0u, /* BRD_I2C — board-management */
.bitrate_hz = 400000u,
});

act8760_t pmic_primary;
da9292_t pmic_secondary;
optiga_t secure_element;
rv3028c7_t rtc;

act8760_init(&pmic_primary, brd_i2c, ACT8760_I2C_ADDR_V2N);
da9292_init(&pmic_secondary, brd_i2c, DA9292_I2C_ADDR_V2N);
optiga_init(&secure_element, brd_i2c, OPTIGA_TRUST_M_I2C_ADDR);
rv3028c7_init(&rtc, brd_i2c);

For V2N-M1, the secondary PMIC's DEEPX-rail management (CH2 voltage step + 0.75 V enable) follows the same pattern — da9292_v2n_m1_enable_deepx_rail() takes the shared handle and gates on a single PMIC instance. See docs/bring-up-v2n-m1.md for the sequencing.

Chip driver opt-in

Every chip driver is gated on CONFIG_ALP_SDK_CHIP_<NAME>=y so unused chips don't cost code size. Two ways to flip the flag:

  • Declarative (recommended) — list the chip under chips: in board.yaml. The loader sets the Kconfig automatically.
  • Manual — add CONFIG_ALP_SDK_CHIP_GD32G553=y etc. to your prj.conf.

The full chip catalogue is at metadata/chips/. See the chip page for the in-tree summary.

Build for real silicon

west alp-build figures out the cross-compile target from the SoM's silicon: field. Common boards:

# AEN (Alif Ensemble)
west alp-build -b alp_e1m_evk_aen alp-sdk/examples/gpio-button-led
west flash

# V2N (RZ/V2N)
west alp-build -b alp_e1m_evk_v2n alp-sdk/examples/v2n/v2n-gd32-bridge-ping
west flash

The exact <board> argument depends on whether you're using the upstream Zephyr board file or the alplabai/alp-zephyr-modules overlay.

Per-SoM bring-up references

The SDK ships detailed bring-up walk-throughs for each SoM family:

FamilyBring-up doc
E1M-AENdocs/bring-up-aen.md
E1M-X V2Ndocs/bring-up-v2n.md
E1M-X V2N-M1docs/bring-up-v2n-m1.md
E1M-N93docs/bring-up-imx93.md

Deep tutorials

For longer end-to-end walk-throughs (the examples teach a single peripheral; tutorials teach a flow), see docs/tutorials/ in the SDK repo:

#TutorialScope
01first-buildHello-world on native_sim
02i2c-scanI²C scanner + populated-chip reasoning
03pwm-fadePWM channel basics
04cross-family-portabilityOne app, AEN + V2N + i.MX 93
05supervisor-mcu-bridgeV2N's GD32 bridge — protocol + transports
06secure-element-signOPTIGA Trust M ECDSA
07recovering-a-bricked-bridgeHost-driven SWD bit-bang reflash
08runtime-board-detectionEEPROM manifest + BOARD_ID ADC
09board-yaml-deep-diveEvery block, every override
10secure-boot-signingMCUboot signing on AEN
11mqtt-tls-publish<alp/iot.h> + <alp/security.h>
12mender-otaYocto OTA (V2N + V2N-M1)
13eeprom-provisioningProduction-line manifest programming
14audio-loopbackPDM in → I²S out with DSP chain
15mproc-mailboxMulti-proc IPC end-to-end
16inference-mobilenetTFLite-Micro on Ethos-U / DRP-AI / DEEPX

Getting help

  • File issues at github.com/alplabai/alp-sdk/issues. Include the output of west alp-build --version, your board.yaml, and the full west build log.
  • For chip-driver bugs: include the chip's metadata/chips/<part>.yaml driver status (stub chips return ALP_ERR_NOSUPPORT by design).
  • Community: the Alp Lab Forum.

Where next

Questions about this page? Discuss in Community Forum