v0.6.0
Added — gd32-bridge v0.2.9 / protocol v0.7: the stale-reply kill + OTA version plumb (2026-06-06)
Wire protocol 0.6.0 → 0.7.0 (MINOR; the un-negotiated wire is
byte-identical to v0.6) and firmware 0.2.8 → 0.2.9.
CMD_LINK_FEATURES(0x81) + the negotiatedSTATUS_SEQreply
stamp — the architected kill for the transport's residual
stale-reply hazard, silicon-fingerprinted the day before
(byte-exactCOUNTER_READreplays whose rate swung 0↔100 % on
host timing phase). Once negotiated, every SPI reply carries a
4-bit slave-side sequence stamp in STATUS[7:4], advanced per
freshly-decoded request; the drain/rewind re-serves keep the same
stamp, so a CRC-valid reply whose stamp has not advanced tells the
host its request was never decoded — and since it was never
executed, the host driver's automatic single re-send is safe for
every opcode. Host telemetry inctx->seq_stale_count;gd32g553_init()negotiates automatically and degrades to legacy
framing against older firmware. I2C replies are never stamped
(STATUS_NO_PENDINGowns bit 7 there). Unit-pinned intests/unit/gd32_bridge_transport(stamp advance / rewind-keeps-
stamp / error-envelope stamping / mod-16 wrap / disable restores
byte-identical legacy framing) + new fuzz corpus seeds + §12
protocol vectors.OTA_BEGINcarries the incoming image's version (additive
3-byte triple): recorded into the A/B metadatafw_version[slot]
at COMMIT — the record had reserved the field ("0 = unknown")
since its v2 layout. Legacy 8-byte BEGIN still accepted;
pre-v0.7 firmware ignores the trailing bytes.gd32g553_ota_begin()gains a nullablefw_versionparameter
(no-legacy-compat: signature changed, callers updated, ABI
snapshot regenerated).- The HIL soak exports v0.7 link telemetry (
seq_forensics[]:
negotiated flag + stale-catch count) next to the existing
counter-row discriminator, so the bench can WATCH the kill work.
Fixed — gd32-bridge v0.2.8: ISR-safety + error-masking fixes from the delta review (2026-06-05)
Three behavior fixes found by an adversarial review of the
v0.2.3→v0.2.7 delta (one critical, two major). Bench-validated:
YES (2026-06-06) — v0.2.8 + the hal/gd32 TU split + the real-SHA
build-id smoked together on silicon: GET_BUILD_ID round-tripped0.2.8+d038f981186a20 (exact HEAD match); the 20-row HIL soak ran
253/253 clean on every row including the new adc_stream_guard
converter-ownership probe; the Tier-B loopback repeated its 5/6
(DAC raws {151,450,900,1350} mV vs commanded {150,450,900,1350};
capture 5.000 ms / 2.500 ms exact; qenc still blocked by the known
carrier-wiring item). A counter-row anomaly during the first soak
window was root-caused to the transport's documented stale-reply
residual hazard (byte-exact reply replays, phase-dependent; raw
back-to-back pairs read equal 0/277 once re-phased) — transport-level
and pre-existing, not a v0.2.8 defect; the soak now carries a
permanent discriminator row for it.
- CRITICAL — unbounded ADC-calibration spin reachable from the
CS-EXTI request handler (hal/bridge_hw_gd32.c). The vendor
SPL'sadc_calibration_enable()spins on RSTCLB/CLB with no
timeout, andadc_periph_init()routed through it from two
in-handler sites:STREAM_END's converter restore andADC_READ's
timeout self-heal. A converter wedged hard enough to need the
self-heal is exactly the one that can hold those bits forever — the
recovery for the wedged-ADC case could itself wedge the whole SPI
link (the same failure class the bounded EOC waits were added to
stop). Calibration is now a bounded reimplementation;STREAM_END
reportsSTATUS_IOif the restore calibration never completes (the
stream still tears down). - MAJOR — single-shot
ADC_READcould corrupt a live stream: two
logical channels share each ADC converter, and a read on the sibling
of a streaming channel re-pointed routine rank 0 out from under the
stream's DMA, injected an unpaced software trigger, and consumed the
EOC the DDM path depends on. Now refused (STATUS_IO) while the
stream owns the converter; retry afterSTREAM_END. - MAJOR — a never-ready analog reference was silently swallowed:
v0.2.6's bounded VREFRDY wait discarded its verdict, so a reference
buffer that never locks would let every ADC/DAC op answerSTATUS_OKwith garbage millivolts — the exact masking class the
VREF fix targeted, and unobservable on the wire (no GET_FAULT
opcode). The readiness verdict is now latched;ADC_READ,ADC_STREAM_BEGIN,DAC_SETandDAC_GETanswerSTATUS_IO
while the reference is dead, re-probing on each attempt so a
late-locking buffer self-promotes. - Documentation from the same review: loopback verdict-slot legend
corrected to the real{150, 450, 900, 1350}setpoints; "firmware-
averaged" ADC wording removed (4 independent samples); hostgd32g553_pwm_getdoc now states hardware-readback semantics
(shared-per-timer period, 65.536 ms / 0-duty boot default);
PWM-capture single-wrap validity bound documented (spans ≥ CAR+1
ticks alias undetected); TRNG fault-recover contract (one honestSTATUS_IO, next pull succeeds) added to the wire spec. firmware-version.txt0.2.7 → 0.2.8.
Fixed — gd32-bridge v0.2.7: PWM-capture wrap-aware deltas (2026-06-05)
- PWM input-capture read a wrapped-garbage period and a zero pulse
width (hal/bridge_hw_gd32.c).pwm_capture_drainsubtracted raw
capture counts (now - last_tick); on the capture timer's own
up-counter consecutive edges straddle the 0..CAR wrap, so the
subtraction underflowed. All edge deltas are now taken modulo the
counter period (CAR + 1). Most visible on the Tier-B PWM→PWM
loopback where stimulus and capture share TIMER0: the same-edge
"period" is now a clean ~0 (documented shared-timer degeneracy
instead of0xFFFB6C20garbage) and the adjacent-edge pulse width
is meaningful. The loopback example's capture test moves to a
200 Hz / 50 % stimulus polled in a tight loop — 50 % removes the
arm-phase ambiguity (high = low = period/2) and the slow rate lets
the host catch three consecutive edges (the old 1 kHz + 5 ms retry
ladder sampled non-consecutive edges, which is why it read 0).
Silicon-validated end-to-end through the carrier jumper. firmware-version.txt0.2.6 → 0.2.7.
Fixed — gd32-bridge v0.2.6: enable the internal VREF (the analog subsystem was dead) (2026-06-05)
- The GD32's entire ADC + DAC subsystem read garbage because the
analog reference was never driven (hal/bridge_hw_gd32.c). On
this module revision the converters' reference node depends on the
GD32's on-chip reference buffer (no external reference source); at
resetVREF_CS = 0x02(HIPM high-impedance) parks the buffer, so
every ADC channel + both DACs referenced an undriven node. It went
unnoticed for the bridge's whole life because the ADC self-tests
were ceiling-only (sample < 3400 mVpasses on a zero reading) andDAC_GETechoes the digital hold register, not the pad — the
jumpered Tier-B loopback is what finally caught it (DAC→ADC read 0
with a known driven input).bridge_hw_initnow enables the
on-chip VREF buffer (RCU_VREFclock +vref_enable()at the
2.048 V target, boundedVREFRDYwait) before any ADC/DAC
bring-up, so the converters self-calibrate against a live
reference. Bench-proven over SWD: with VREF up, a DAC→ADC copper
loopback tracks 1:1 (DAC 2730 → ADC 2730; DAC 600 → ADC 599). The
buffer's three targets all exceed the 1.8 V VDDA so it regulates at
the rail (~VDDA); correctness in a loopback is ratiometric and
independent of the exact value, and the absolute mV scale tracks
VDDA (ADC_VREF_MV = 1800). firmware-version.txt0.2.5 → 0.2.6.
Added — gd32-bridge Tier-B jumpered loopback example (2026-06-05)
New examples/v2n/v2n-gd32-bridge-loopback: a maintainer bench tool
that closes three GD32 bridge signal paths in copper on the X-EVK
carrier and value-asserts them end-to-end — DAC0→ADC0 (direct 1:1
after the VREF fix), PWM→PWM input-capture (pulse width), and
PWM→quadrature-encoder stimulus. Documents the exact jumper header
pins (the buffered DAC output path is inoperable on this carrier rev —
see the internal carrier errata; the loopback taps the raw DAC0 net
instead), and reads its verdict block over SWD. Also fixes the input-capture HAL to use the GD32G5 MCH
capture units (the E1M PWM pads are MCH, not the classic CHx input
the engine previously armed) and to restore the channel's output
stage on capture_end (a capture session previously left the PWM
channel output-dead until reboot). metadata/boards/e1m-x-evk.yaml:E1M_X_ADC0 corrected to the mikroBUS AN (XEVK_ADC_MIKROBUS_AN,
net CK_ANA) — the netlist routes only that to ANA_S0, not "Arduino
A0".
Fixed — gd32-bridge v0.2.4: ADC stream really streams (DDM + pacing timer) + the 216 MHz clock truth (2026-06-04)
- ADC streaming produced zero samples since it shipped
(hal/bridge_hw_gd32.c). Three stacked defects, root-caused by a
three-angle audit (firmware vs vendor SPL vs host) and the vendor's
ownADC0_routine_channel_with_DMAreference: (1)CTL1.DDM
(adc_dma_request_after_last_enable) was never set, so the ADC
stopped issuing DMA requests after one run — circular DMA without
DDM stalls by design; (2) continuous/DMA controls were programmed
onto an already-running converter — streaming now reconfigures with
ADCON clear in the vendor's order; (3) the stream path never enabled
theRCU_DMAMUXclock, working only because the SPI transport
happened to enable it first (an I2C-only build would stream
nothing). sample_rate_hzis now a real hardware contract. v0.2.3 and
earlier silently ignored it (free-run "aspirational hint"). Each
stream now owns a pacing timer (stream 0: TIMER5, stream 1: TIMER6)
whose update-event TRGO triggers exactly one conversion per period
via TRIGSEL: 1 Hz..100 kHz, tick-quantised,STATUS_OUT_OF_RANGE
above the cap. One stream per ADC converter (secondBEGINon a
shared converter answersSTATUS_INVAL);STREAM_ENDstops the
pacer and restores the converter's single-shot state. The HiL soak
row now PROVES pacing with a two-read assertion (a free-running
stream answers the 32-cap twice; a paced one leaves ~18 samples).- Every GD32 timer-clock constant was wrong: the part runs 216 MHz,
not 240 MHz. The SoM's SystemInit override is 216M-PLL-IRC8M with
APB at DIV1, and the GD32G5x3 has no separate timer PLL (GigaDevice's
own example states "TIMER0 frequency is fixed to 216MHz") — the
"240 MHz advanced-timer clock" inmetadata/chips/gd32g553.yamlwas
an invented value that propagated into the firmware. Consequence:
every PWM period ever generated was ~11 % long (a commanded
1 kHz physically ran ~900 Hz). Fixed:PWM_TIMER_PRESCALER240→216
(true 1 µs tick),pwm_routing.counter_clock_hz240 M→216 M, LSB4.16→4.63 ns and max single-counter period273→303 µs corrected
acrossmetadata/,include/alp/chips/gd32g553.h,include/alp/pwm.h,docs/gd32-bridge-protocol.md, and firmware comments. - Doc drift:
STREAM_BEGINon an active slot answersSTATUS_INVAL
(the doc claimedSTATUS_BUSY); host header's "~1.5 Msps cap"
replaced with the real 100 kHz pacing contract. firmware-version.txt0.2.3 → 0.2.4.
Added — --emit build-plan: machine-readable build plan for external front-ends (2026-06-04)
python3 scripts/alp_orchestrate.py --emit build-planemits the
resolved build plan as deterministic, write-free JSON: one slice per
non-offcore (build dir, exact tool command, env) plus every
generated artefact with its contents (sharedArtefacts+
per-sliceconfigArtefacts), so a consumer materialises files and
runs commands with zero planner logic of its own. This is the
agreed contract for thealpCLI / IDE extension (alp-sdk-vscode
"Wave C") — see ADR 0014
for the settlement: camelCase keys, independentschemaVersion
(bumped + flagged here on breaking shape changes), noinputHash/sequential(cache keys + parallelism belong to the consumer), and
command-less slices carried ascommand: null+ ano-command
warning. Consumers: pin to release tags; the per-slice command
shape is not frozen (it will grow--sysbuildflags when the
conf→build wiring lands).- The Orchestrator's materialise step and the plan emit now read the
same single sources (_shared_artefacts/_slice_config_artefact),
so the plan and the on-disk build cannot drift by construction.
This also fixes a latent gap:emit_sysbuild_confwas emit-only —
aboot:block now materialisesbuild/alp_sysbuild.confduringwest alp-buildtoo, matching its long-documented destination.
Fixed — gd32-bridge v0.2.3: honest PWM read-back + ISR-bounded ADC waits (2026-06-04)
PWM_GETreads the silicon, not a cache (hal/bridge_hw_gd32.c).bridge_hw_pwm_getanswered from a last-request software cache, so a
host could "verify" a PWM that never reached the pad — exactly what
happened on the bench: every PWM pass to date was the firmware echoing
the host's own request (maintainer's scope showed no signal ever).
The handler now reads the liveCAR/CHxCVregisters back and
converts ticks to ns, honouring the read-back contractdocs/gd32-bridge-protocol.md§3.8 always documented. Consequences
now stated in the doc +hal/bridge_hw.h: per-timer shared period is
visible in the read-back, and a never-set channel reports the boot
default (65.536 ms / 0) instead of zeros. The PWM output stage
itself was proven good by drivingTIMER7CAR/CH3CVover SWD
and watching PD0 toggle — the "dead PWM" was the cache echo masking
the fact that nothing on the bench was driving the channel.- Unbounded waits removed from the CS-EXTI handler path
(hal/bridge_hw_gd32.c).bridge_hw_adc_read's EOC poll could spin
forever inside the CS interrupt handler; one wedged conversion froze
the handler, SPI RX DMA never re-armed, and the whole link rotted
(caught live on SWD: DMA0 CH3CHEN=0, count frozen mid-frame). The
poll is now bounded (timeout → ADC re-init +BRIDGE_HW_ERR_IO);adc_stream_beginpre-clears stale EOC + re-inits the DMA param
struct,adc_stream_endadds a settle dwell + unconditional EOC
clear, andadc_periph_initgains a stabilization spin + explicit
calibration. Soak-validated: 18/18 active rows clean for 410+
cycles withadc_streamactive alongside (its own zero-sample
failure is still open, tracked separately). - HiL soak: every remaining quarantine row re-activated (
qencis
status-only — floating A/B inputs free-run;trngretries once per
the documented recovery cycle). firmware-version.txt0.2.1 → 0.2.3 (0.2.2 was consumed by the
OTA bench as the slot-B upgrade-test image version).
Added — full-bridge functional tier + math/TRNG silicon fixes (2026-06-04)
New examples/v2n/v2n-gd32-bridge-functional: single-pass, VALUE-asserting
validation of the bridge surfaces (the soak proves the link; this proves
the functions) — 18 TMU math probes against known-exact results (incl.
Q31), TRNG entropy/boundary pulls, PWM setpoint readback + configure
contract, ADC configure error-path + all-channel sweep, DSP-chain pool
lifecycle, identity — then a forever PWM7 duty staircase (the EVK LED
pad) as a live oscilloscope observable. 26/26 FUNCTIONAL-CLEAN on
silicon, after the suite itself caught and drove the fixes below:
- TMU (firmware): the vendor
tmu_two_*_write()issues its two
IDATA stores back-to-back; with a warm i-cache the TMU swallows the
second word and ENDF never sets (computed exactly once per power-up —
the cache-cold first call). Writes are now paced by a CS read-back.
Angle units fixed in BOTH directions: the CORDIC takes and returns
angles in units of pi, the wire contract is RADIANS (documented in
the host header) — sin/cos inputs are normalised, atan/atan2 outputs
scaled back. sin(0)-only probes could never see either bug. - TRNG (firmware): the unit takes intermittent SEED ERRORS and
parks with the LATCHED flags set (TRNG_STAT = 0x48= ERRSTA+SEIF
while current-status SECS reads clear) — the old CECS/SECS-only check
was blind to it and burned its whole DRDY budget on a dead unit.
Now: latched-fault detection first (vendortrng_ready_check
parity), incremental bring-up + lazy per-read rebuild (full re-seed),
and a whole-request DRDY budget that answers the newSTATUS_BUSY
(BRIDGE_HW_ERR_BUSY) instead of overrunning the reply window; the
host driver retries BUSY. Recovery silicon-validated. - Host driver: firmware ERROR replies carry no payload, so for any
payload-bearing opcode the fixed-width reply read CRC-failed on a
legitimate error and masked the real status asALP_ERR_IO— an
entire class of "-5 from cycle 1" HiL rows (pwm_capture's documented
NOSUPPORT among them) was this. The host now decodes the short
error envelope, and after any failed command sends one throwaway
PING so a stale staged reply can never be mis-attributed to the next
command; the firmware bounds drain rewinds (tar-pit breaker) on its
side. - HiL soak: pwm_capture / qenc / tmu / trng / ota_get_state
un-quarantined (their "-5 from cycle 1" was the transport bug + the
masked-status bug, not broken HAL bodies); qenc gets a floating-input
noise bound; trng one retry per the documented fault-recover cycle.adc_streamstays quarantined (destructive failure mode — its own
supervised pass is next).
Changed — 25 MHz link: SCI-B FIFO burst engine + reply re-read made real (2026-06-04)
The GD32↔CM33 SPI link's wire density and per-command latency were
rebuilt around silicon measurements (scope + CM33 bus/timer probes: one
SCI7 register access ≈ 341 ns; k_busy_wait(10) ≈ 15 µs measured):
- CM33 SCI-B driver (
zephyr/drivers/spi/spi_renesas_rz_sci_b.c):
the polled engine now runs the SCI's 32-deep FIFOs (CCR3.FM, armed
outside the FSP whose FIFO path is DMA-gated) with a credit-bound
burst loop sized off theFRSR.Rfill counter — at most 31 bytes in
flight, which provably bounds both FIFO occupancies, so there is no
per-byte flag poll at all. Inter-byte wire gaps drop from ~5 µs
(serialized one-in-flight walk) to wire-rate bursts, scope-confirmed
at 25 MHz. CS setup/hold windows laddered 60/30 → 3/2 µs and moved
offk_busy_waitonto a raw SysTick spin (the kernel'sk_cycle_get_32poll is µs-coarse, overshooting every wait by ~50%;
delta-capped so tickless LOAD rewrites can only lengthen a window);
the deadspi_contextgpio-CS path is skipped entirely under the
direct-latch shim (single CS owner).recover()is FIFO-aware
(flush + the FIFO-mode TEND-anomaly-safe TE clearing per the
vendor's own Close sequence). TheALP_V2N_SCI7_DMACDMA path was
re-baselined against the e2-studio FSP generator's SCI+DMAC pairing
(ackMASK_DACK_OUTPUT,NO_DETECTION, request directionSOURCE_MODULEboth ways, DREQ/DACK/TEND pins explicitly unused —
our sweep had REQD inverted on RX and the pin fields zero-initialised
to PIN0) and wired end-to-end (transceive()FSP branch, cfg gate
follows the same switch, RX arm moved off the rzvR_DMAC_B_Reset
stub ontoreconfigure()). Benched: the DMAC now streams
complete transactions (the old parks-after-one-beat diagnosis is
dead); remaining blocker is an intermittentCHSTAT.ERAXI fault on
TDR writes through the convert window — bus-master security lead,
seedocs/gd32-link-sci7-next-rev.md. Gate stays default-off; the
polled FIFO engine is the production path. - gd32-bridge firmware v0.2.1: a reply-drain transaction now
rewinds the staged-reply cursor before re-arming TX DMA, and an
EMPTY transaction (CS pulse whose bytes were lost to edge coalescing
mid-handler) does the same (src/transport_spi.c). Previously the
gd32 backend's stage-time drain left the cursor spent, so a host
reply read landing before a slow handler (ADC burst ≈ 18-20 µs per
sample) finished staging disarmed the reply permanently — caught
live on SWD as 255-of-256 failures with the correct reply intact in
the buffer and the TX DMA count frozen mid-prefill; the empty-path
variant turned one collision miss into a guaranteed double miss.
With the rewind, every drain re-stages the same reply and the host's
re-read schedule converges. Newtests/unit/gd32_bridge_transportpins the seam contract (6 cases,
linked against the production transport + dispatcher). - Host driver (
chips/gd32g553/gd32g553.c): replies are read
after an opcode-aware staging gap (35 µs base + 8 µs/sample forADC_READ— the measured optimum against the slave's ~18-20
µs/sample conversion cost) and re-read down a short-first backoff
ladder (25 µs → 1.6 ms, ~3.2 ms bound) instead of the flat 250 µs
schedule. V2N link consumers (bridge examples, quickstart snippet)
now passALP_SPI_NO_CS— the platform SPI driver owns the CS pad;
routing it through the generic gpio-CS path double-drove P97. docs/gd32-bridge-protocol.md§4.1 now specifies the re-read
schedule as the host contract (the fixed ≥ 100 µs pre-read wait
remains a valid but slower alternative). The link's transport is
SCI7 permanently (an RSPI reroute was rejected — pads committed
elsewhere);docs/gd32-link-sci7-next-rev.mdreplaces the RSPI
migration plan, and stale "RSPI master" wording was corrected across
the docs/headers.firmware/gd32-bridge/CMakeLists.txtnow re-runs
configure whenfirmware-version.txtchanges (incremental builds
used to bake a staleGET_BUILD_ID).
Measured on the bench (256-op averages, 25 MHz, errors 0/256 across
the board), before → after: ping 130 → 120 µs, get_version 151 →
133 µs, gpio_read 2680 µs at 255/256 FAILING → 153 µs/0 errors,
adc_read(4) 2789 µs at 254/256 failing → 196 µs/0, adc_read(8)
3428 µs at 256/256 failing → 261 µs/0. Raw transaction floor 49 →
27 µs; marginal wire cost ≈ 0.85 µs/byte (engine-bound; true wire
rate stays the DMAC path's job).
Changed — gd32-bridge protocol v0.6 + OTA Path-A real, silicon-validated (2026-06-04)
Wire MINOR bump PROTOCOL_VERSION 0.5.0 → 0.6.0 (firmware/gd32-bridge/ src/protocol.h, host mirror in <alp/chips/gd32g553.h> in lock-step):OTA_WRITE_CHUNK's request payload is now length-checked
(offset:u32 len:u8 data[len]), closing a silicon-caught wire hole —
a slave re-capture merged with the next transaction's zero filler still
passes the span CRC whenever the frame's own CRC-16/CCITT-FALSE is
byte-palindromic (self-consumption to 0x0000; ~1 chunk in 256), which
inflated the payload length and double-programmed the ECC flash. A
len/span mismatch now answers STATUS_INVAL without touching the
session; OTA_BEGIN's chunk_max drops 61 → 60. Pre-1.0 the host
and firmware must ship in lock-step including MINOR — the handshake
gates on MAJOR only.
The OTA 0xF0..0xF6 range also went from scaffold to real Path-A,
silicon-validated end-to-end (stream → verify → commit → boot slot B →
rollback → boot slot A, proven by wire build-id reads + the A/B metadata
generation history): RAM-resident dual-bank FMC backend
(hal/fmc_ota.c, OBCTL.DBS-aware paging + sticky-PGERR clearing),
struct-v2 per-slot metadata (rollback no longer bricks), WRITE/VERIFY
session gates, replay dedupe, PRIMASK bootloader-handoff fix, corrected
CRC-32 polynomial (0xEDB88320), real GET_BUILD_ID content
(<fw-version>+<sha-placeholder>), and host OTA state/slot enum values
aligned to the firmware wire (GD32G553_OTA_SLOT_A=0/B=1/NONE=0xFF;READY/BUSY/VERIFIED/ERROR). New tools/gen_ota_metadata.py factory
provisioning helper; new examples/v2n/v2n-gd32-bridge-hil-soak
full-command-set pass/fail soak (which caught five pre-existing HAL
defects on first silicon exercise — quarantined in its table with
notes). Protocol vectors regenerated (--check green).
Changed — DA9292_STATUS_FORWARD semantics re-spec (2026-06-03; corrected 2026-06-04)
Docs/comments re-spec of the DA9292_STATUS_FORWARD (opcode 0x40)
surface to match the wiring: the GD32 supervisor has no I2C path to
the DA9292 PMIC. 2026-06-04 schematic verification went further: on the
current SoM revision the DA9292 fault nets reach only the Renesas
(DA9292_INT → P37, DA9292_TW → P36) — the GD32 has no connection to
them at all, so the forwarded byte is always the 0xFF "no sample"
sentinel on this hardware; the bit0 = INT / bit1 = TW packing is
reserved for a future HW rev that mirrors the nets onto GD32 inputs.
Removed all "cached PMC_STATUS_00 / periodic I2C-master poll / ≤ 20 ms
cache age" language from the host header, firmware comments, protocol
spec, tutorials, and the bridge-ping example. The host observes the
fault pins directly via the new da9292_get_fault_pins() (same bit
packing) and reads register-level PMIC status over BRD_I2C viada9292_get_status() — both in the chips/da9292 driver.
Changed — hw_info: the EEPROM manifest is the sole SoM-rev source (2026-05-31)
The on-module EEPROM manifest (magic + schema_version + CRC32) is now
the single authoritative source of the SoM hardware revision; the
SoM-side BOARD_ID ADC cross-check path was removed outright
(no-legacy-compat). Breaking (pre-1.0 minor): the [ABI-STABLE]
struct alp_hw_info_t drops the som_board_id_mv field; ABI snapshot
regenerated. alp_hw_info_read() return-code contract sharpened:
blank manifest → ALP_ERR_NOT_PROVISIONED, corrupt manifest →ALP_ERR_IO, EEPROM unreachable → ALP_ERR_NOT_READY, no bus
configured → ALP_ERR_NOSUPPORT. Carrier-side board_id_mv /board_hw_rev stay (board-side BOARD_ID is a separate, carrier-owned
path).
Added — ALP_ERR_NOT_PROVISIONED status code (2026-05-31)
New alp_status_t enumerator ALP_ERR_NOT_PROVISIONED (= -15) in<alp/peripheral.h>. Returned when the on-module EEPROM manifest is blank
(all-0xFF or all-0x00) — i.e. the module has not yet been through the factory
provisioning tool. Distinct from ALP_ERR_IO (= -5), which covers a CRC
mismatch or corrupted manifest on an otherwise-reachable EEPROM. Callers that
previously conflated the two conditions can now present a clearer diagnostic
("unprogrammed" vs "corrupted").
Added — doc-drift CI gate (2026-05-27)
scripts/check_doc_drift.py + .github/workflows/pr-doc-drift.yml: an
objective gate that fails when (a) a customer doc references an ALP_* / alp_*
identifier that exists in no SDK source layer (public + internal headers,
Kconfig, CMake, generators, schemas, Yocto), or (b) a top-level docs/*.md is
not linked from the docs/README.md index. "Known" identifiers are harvested
from the real sources (not a hand-kept allowlist), so the gate stays
low-maintenance and free of build-identifier false positives. Runnable locally
(python scripts/check_doc_drift.py); wired into the local-CI cheat sheet.
Catches exactly the stale-reference class the .alpmodel / DEEPX_DX → DEEPX_DXM1 rename left behind.
Added — .alpmodel Stage 2 compile-config plumbing (2026-05-27)
Board.yaml models[].compile: block threads per-backend compile configuration
(DRP-AI spec path, DEEPX JSON config + calibration dir) from board.yaml intoalp model build. Backends that need a per-model config (drpai, deepx_dxm1)
record a coverage: skipped ("no compile config") entry when no block is
supplied — instead of silently skipping on toolchain-absent check alone. Thecompile: block is validated by metadata/schemas/board.schema.json
(additionalProperties: false; deepx_dxm1 requires both config: andcalibration:; drpai requires spec:; unknown backend keys are rejected).
All path values are resolved relative to the board.yaml file before being
passed to the adapter. No vendor tools required; fully testable on any host.
Real DeepxAdapter.compile() is now implemented: it shells outdxcom -m <onnx> -c <config.json> -o <dir> and returns the single <stem>.dxnn
the compile produces (blob_format: dxnn, raw bytes — matching the device-sideALP_INFERENCE_MODEL_DXNN). Confirmed against the licensed dx-com 2.3.0 wheel
by a real compile of both a tiny CNN and a real yolo11n object detector: the-o dir holds one <stem>.dxnn flatbuffer (compiler.log only with--gen_log); calibration is referenced from the JSON config, not a CLI flag;
dxcom needs >15 GiB host RAM. Covered by a mocked shell-out test, awhich("dxcom") version smoke, and skipif-gated end-to-end real-compile tests —
a hermetic tiny ONNX fixture (public) plus the real yolo11n (alp-sdk-internal).DrpaiAdapter.compile() (open DRP-AI TVM) and the Yocto dx_rt / DRP-AI runtime
backends remain Stage 2 (gated on the DRP-AI TVM build / licensed dx_rt SDK +
bench silicon; tracked by issues #58/#59).
Added — portable .alpmodel model pipeline (Stages 1a–1c, 2026-05-26..27)
End-to-end AI-model pipeline so one model is portable across NPU back-ends.
Host side: alp model build (scripts/alp_model/) compiles a source model
for every backend the SoM declares into a fat multi-backend .alpmodel
package (CBOR manifest + per-backend blobs + a capability requires envelope).
On-device: alp_inference_open_alpmodel() + a pure selection engine
(src/backends/inference/alp_model_select.*) picks the matching blob by
silicon-ref + SRAM-fit (ALP_SOC_NPU_ARENA_SRAM_KIB) + preferred_backend
tiebreak — ALP_ERR_NO_FIT / ALP_ERR_NO_BACKEND / ALP_ERR_NOT_FOUND
otherwise — then delegates to the existing backend registry. On-device reader
gated behind CONFIG_ALP_SDK_MODEL_READER. Renamed the backend enumALP_INFERENCE_BACKEND_DEEPX_DX → …DEEPX_DXM1. Real proprietary DRP-AI /
DEEPX compiles + Yocto runtime backends = Stage 2 (gated on licensed tools +
bench; tracked by issues #58/#59).
Added — per-bridge firmware release versions (2026-05-26)
The on-module GD32 and CC3501E bridge firmwares each gained an
independent firmware release version (firmware/<mcu>/firmware-version.txt,
semver), tracked separately from the wire-protocol version and the
build-id so a fielded device's firmware is trackable on its own. The
GD32 build embeds it (GD32_BRIDGE_FW_VERSION, surfaced via GET_BUILD_ID
as <ver>+<sha>); the CC3501E reports it as fw_version via GET_VERSION
and names its prebuilt blob from it. The three-axis model (firmware
release / wire protocol / build-id) is documented indocs/gd32-bridge.md + docs/cc3501e-bridge.md.
Changed — V2N Linux build + bridge docs reconciled to validated reality (2026-05-26)
The Renesas RZ/V2N Linux docs were reconciled to the WSL-validated build:
the Yocto path is the bitbake-layers flow in meta-alp-sdk/README.md
(kas retired, kas/e1m-v2n.yml removed); the version framing is AI SDK
platform 7.1 / BSP v6.30 (linux-renesas 6.1.141-cip43) throughout; and
the layer is meta-alp-sdk (the deleted yocto/meta-alp/ name was
scrubbed from live docs). The shipped-but-undocumented <alp/*> surfaces
(storage, dsp, tmu, power, rpc, gpu2d, backend,e1m_x_pinout, ext/<vendor>) are now reflected in the README stack
graph + Public API table, docs/architecture.md, anddocs/os-support-matrix.md. The pre-flash provisioning model (V2N
bootloader / CC3501E / GD32 — both MCU bridge firmwares open) is
documented, and login-gated vendor download links were removed from
public docs.
Changed — examples reorganised into category subdirectories (2026-05-24)
The 43 flat top-level example folders now live under category
subdirectories matching the examples/README.md functional index:peripheral-io/, audio/, camera-vision/, ai/, connectivity/,display/, power-timing/, multicore/ (the aen/ and v2n/
platform groups already used this layout). History is preserved viagit mv; every examples/<name> reference -- per-example west build
commands, the functional index, .vscode tasks, scripts/bootstrap.sh,
CI workflows, docs -- is updated to examples/<category>/<name>. No
source or build-system changes: twister discovers examples recursively,
so build invocations simply gain the category path segment. (Past
CHANGELOG entries keep their original flat paths -- they record the
state at the time they were written.)
Changed — E1M-X pinout header synced to the full x-v1.0 connector (2026-05-24)
<alp/e1m_x_pinout.h> was reconciled against the authoritativealplabai/e1m-spec pinout/x-v1.json (E1M-X x-v1.0), which already
enumerates the entire ASS6880 LGA496 module connector. The earlier
interim edit that added I2C2/I2C3 "pending upstream e1m-spec sync" is
superseded — x-v1.0 already defines those pads, so the caveat is gone.
No e1m-spec change was needed; the header was simply behind the spec.
- Peripheral instance IDs now cover the full connector and are
formatting-normalised:E1M_X_I2C0..3,E1M_X_SPI0..2,E1M_X_CAN0..1,E1M_X_CSI0..3,E1M_X_DSI0..1,E1M_X_USB0..2,E1M_X_PCIE0..1. - New parallel-RGB-LCD class
E1M_X_LCD0(padsLCD_B0..LCD_B23+LCD_HSYNC+LCD_VSYNC; the connector has no separate PCLK/DE pad),
with count macroE1M_X_LCD_COUNT(1). - GPIO-secondary indices appended at index >= 62 for the new
single-ended digital pads (I2C2/3, SPI2, CAN1, and the LCD0 block);E1M_X_GPIO_COUNTgrows 62 -> 99.
This extension is additive and ABI-safe — every pre-existing
instance ID and GPIO index keeps its value. Differential pairs
(CSI/DSI/PCIe/USB/ETH) are not GPIO-capable and are omitted from the
GPIO index space.
Added — Linker-section backend registry (Slices 0..7) (2026-05-23)
Replaces the per-class #if-ladder dispatch that lived insrc/zephyr/peripheral_<class>.c with a portable, linker-section
backend registry. Every supported peripheral class (adc, i2c,spi, uart, gpio, pwm, i2s, can, counter, qenc, rtc,wdt, usb, ble, wifi, mqtt, audio, mproc, rpc,security, dsp, tmu, storage, power, camera, inference,display, gpu2d) now dispatches through a class-specific section
walked by alp_backend_select() in src/backend.c.
- Class dispatchers live at
src/<class>_dispatch.cand own the
handle pool. They are OS-agnostic — no<zephyr/...>types in the
shared<class>_ops.hheaders per issue #34's cleanup. - Backends live at
src/backends/<class>/<vendor>.cand register
viaALP_BACKEND_REGISTER(<class>, <vendor>, { … }). Variants today:- Real Zephyr backends (
zephyr_drv.c/zephyr_video.c/zephyr_pm_policy.c/zephyr_flash.c/zephyr_littlefs.c) - SW fallbacks (
sw_fallback.c) registered atsilicon_ref="*"
priority 0 — universal floor. - Vendor-specific bridges (
gd32_bridge.cfor adc/counter/qenc
on V2N) registered atsilicon_ref="renesas:rzv2n:n44"priority
100. - NOT_IMPLEMENTED stubs for backends whose vendor pack hasn't
landed yet (DRP-AI3 → issue #58, DEEPX DX-M1 → issue #59).
- Real Zephyr backends (
- Selector tiebreaker (3 tiers, documented in
src/backend.c+<alp/backend.h>): (1) higher priority wins; (2) exactsilicon_ref
beats*wildcard at equal priority; (3) alphabetic vendor at
same priority + match-type. Test coverage intests/unit/backend_registry/src/test_registry.candtests/unit/backend_registry/src/test_bridge_selection.c. - Capability getters added:
alp_<class>_capabilities()for
every migrated class, returning the sharedalp_capabilities_talp_instance_cap_tflags populated by the backend'sops->probe()at open time.
- Vendor extensions (
<alp/ext/<vendor>/<class>.h>) for the
silicon-specific surfaces that don't fit the portable API:<alp/ext/alif/adc.h>(oversampling, trigger source)<alp/ext/alif/storage.h>(OSPI SecAES — body NOSUPPORT until
Alif HAL pack)<alp/ext/nxp/storage.h>(FlexSPI OTFAD — body NOSUPPORT until
NXP pack)<alp/ext/renesas/power.h>(GD32 supervisor mode set viaCMD_POWER_MODE_SETopcode 0x28)<alp/ext/renesas/camera.h>(V2N N44 ISP fine-grained knobs)<alp/ext/alif/camera.h>(Mali-C55 — body NOSUPPORT until
Alif HAL Mali-C55 pack)<alp/ext/renesas/inference.h>(DRP-AI3 pipeline-stage knobs)<alp/ext/deepx/inference.h>(DX-M1 slot + tile management)
- Inference Kconfig ladder retired.
CONFIG_ALP_SDK_INFERENCE_TFLM
→_BACKEND_TFLM;_DRPAI→_BACKEND_DRPAI_V2N;_ETHOS_U→_BACKEND_ETHOS_U_AEN/_ETHOS_U_N93;_ETHOS_U_U55→_ETHOS_U_VARIANT_U55etc.;_TFLM_NEON/HELIUM/REF→_TFLM_KERNEL_NEON/HELIUM/REF. Customer-facingALP_INFERENCE_BACKEND_AUTO/CPU/ETHOS_U/DRPAI/DEEPX_DXenum
unchanged. - CI gates (
scripts/check_stub_issues.py,_sw_fallback_tags.py,_vendor_ext_tags.py) enforce per-backend documentation
conventions (issue trackers on stubs,@par Cost/Performanceon
SW fallbacks,@par Supported siliconon vendor extensions). - Yocto-side migration deferred to tracking issue #33.
ADR / spec: docs/architecture/backend-registry.md +docs/superpowers/specs/2026-05-21-backend-registry-design.md.
Added — OTA Zephyr-client provider-driven dispatch (ADR 0009 resolved) (2026-05-20)
Lands the v0.6 follow-on to ADR 0009: ota.provider: is now a
provider-driven dispatch with real Zephyr-side emit for every
recognised provider, not just Yocto-side Mender.
- Schema enum widened:
ota.provider: hawkbitjoinsmender/mcumgr/none(metadata/schemas/board.schema.json). _slice_alp_conf()emits per-provider Kconfig on every Zephyr
slice whenota:is declared:mender→CONFIG_MENDER_MCU_CLIENT=y+ server URL / tenant
token / artifact name / poll interval (Mender-MCU-client,
out-of-tree BSD-3).hawkbit→CONFIG_HAWKBIT=y+CONFIG_HAWKBIT_SHELL=y+HAWKBIT_SERVER+HAWKBIT_POLL_INTERVAL(Zephyr upstream).mcumgr→CONFIG_MCUMGR=y+CONFIG_MCUMGR_GRP_IMG=y+CONFIG_MCUMGR_GRP_OS=y. Transport (UART / BLE / UDP) stays
the app's call.
- Yocto-side dispatch unchanged:
provider: menderkeeps the
existingMENDER_*weak-assignments inlocal.conf. - west.yml fragment emit (
scripts/alp_project.py_emit_west_libraries)
auto-adds amender-mcu-clientname-allowlist:entry whenota.provider: menderis declared. Hawkbit and MCUmgr are
Zephyr-upstream so no west.yml change is needed. - Validator rule 1 (P2.3) relaxed for the new dispatch:
provider: menderaccepts EITHER a Yocto OR a Zephyr core
(was Yocto-only).provider: hawkbitrequires at least one Zephyr core.provider: mcumgrrequires at least one Zephyr core.
Errors point at the offending rule with the resolved-dispatch
hint.
- Tests: 6 new cases under
tests/scripts/test_alp_orchestrate.py
(mender-on-zephyr ok, mender-with-no-target rejected, hawkbit
requires zephyr, hawkbit Kconfig emit shape, mcumgr requires
zephyr, mcumgr SMP Kconfig emit). Pre-existingmender_without_yocto_rejectedtest rewritten to assert the
new "ok" behaviour. - Docs:
docs/board-config.md§ "OTA" rewritten with the
per-provider emit matrix + validator rule listing.
Added — per-library HW-backend profile coverage (25 profiles) (2026-05-20)
Priority 2.2 of the v0.6 milestone lands as a regression guard.
All 25 libraries enumerated in cores.<id>.libraries: inmetadata/schemas/board.schema.json already ship ametadata/library-profiles/<libname>/hw-backends.yaml table
declaring their per-class accelerator binding (crypto, gpu_2d, dma,
simd, cordic, fft, ml_npu_primary, ...) against the SoM
preset's capabilities: matrix. Audit revealed full coverage; the
gap was test-side -- no regression test enforced that the schema
enum and the on-disk profile set stay in lock-step.
-
New
tests/scripts/test_library_profiles.py(77 parametrised
cases) enforces four invariants:- Coverage — every library in the schema enum has a matching
hw-backends.yaml; every shipped profile directory maps back
to an enum entry (no orphans). The singlecmsis_dsp→cmsis-dspdirectory rename is accommodated explicitly,
mirroring_LIBRARY_WEST_MODULESinscripts/alp_project.py. - Shape — each profile carries the required top-level fields
(schema_version,library,class,accelerators,sw_fallback,verification) and thelibrary:slug matches
the directory's normalised name. - Binding axis — each profile surfaces at least one of an
accelerators[]entry, asw_fallback.kconfig:knob, or averification:block. Empty profiles are rejected. - Kconfig well-formedness — every emitted
kconfig:line is
a real-lookingCONFIG_<NAME>=<value>token (y / n / m /
quoted string / integer / hex) OR a comment-only sentinel
(# foo: ...) for header-only libraries. We intentionally do
NOT verify that each symbol exists in Zephyr's Kconfig tree
— that's a build-time concern that depends on the pinned
Zephyr version.
- Coverage — every library in the schema enum has a matching
-
docs/recommended-libraries.mdgrows a "HW-backend profiles
(per-library accelerator binding)" subsection summarising the
coverage matrix (crypto / ML / DSP / FS / graphics / sensor-fusion
/ industrial / IoT / audio / header-only / test) and pointing at
the new regression test.
The 18 libraries carrying at least one requires_cap:-gated
accelerator entry today (every SoM-relevant library): bearssl,cmsis_dsp, coremqtt_sn, gfx_compat, libcoap, libhelix,libwebsockets, littlefs, lvgl, madgwick_ahrs, mbedtls,minimp3, modbus, opus, pid, tflite_micro, tinygsm,u8g2. The remaining 7 (etl, fmt, nlohmann_json, doctest,catch2, jsmn, nanopb) declare an empty accelerators: list —
their value lives in the pure-SW path with no accelerator class
to bind.
No source / loader / data changes outside the test + docs +
CHANGELOG. Existing 402-test suite still green (now 479 with the
77 new parametrised cases).
Added — HiL coverage for boot: / memory: / power: / diagnostics.modules: (2026-05-20)
- Four new portable HiL specs under
tests/hil/_common/, one per
declarative board.yaml block landed at schema level in PR #3.
Each spec asserts the orchestrator's CONFIG_* emit actually reaches
real silicon (MCUboot is the first boot stage; CONFIG_MAIN_STACK_SIZE
shows up in the runtime trace; PM subsystem suspend/resume cycle
fires from a declared wakeup source; per-module log levels filter):boot_mcuboot.yaml— coversboot:memory_stacks.yaml— coverscores.<id>.memory:power_sleep_wake.yaml— coverscores.<id>.power:
(flagspending_hardware_support: deep-sleep-current-draw— the
AEN HiL rig doesn't carry an inline ammeter yet; the spec falls
back to serial-trace assertions)diagnostics_modules.yaml— coversdiagnostics.modules:
- Host-side cross-check at
tests/scripts/test_hil_blocks_coverage.py
(23 tests) validates each spec parses + the matching emit code
produces the CONFIG_* lines the spec claims to observe. A schema
field the emit silently drops fails CI on a normal machine, before
the HiL runner ever sees it. .github/workflows/nightly-aen-hil.ymlnow invokestests/hil/run_smoke.pyagainsttests/hil/aen701-evk/after the
existing ztest build, picking up the new specs automatically via
the_common/discovery flow.tests/hil/README.mddocuments the block-coverage convention and
thepending_hardware_support:flag.
Added — storage: block: deterministic flash-partition allocator + DTS/Kconfig emit (2026-05-20)
Closes the first v0.6 schema-only gap: storage: lands its real
emit pipeline so the schema-authoritative partitions become
build-system artefacts.
- New resolver
resolve_storage_partitions()inscripts/alp_orchestrate.pyallocates physical offsets for everystorage[]entry, name-sorted and page-aligned to 4 KiB within
eachflash_device:. Mirrors the IPC carve-out pattern: blocked
entries (TBD capacity, unknown device, page-misaligned offset,
sibling overlap) land insystem-manifest.yamlwithstatus: blocked+reason:so reviewers see the gap. Byte-stable
allocation across rebuilds (per resolved design Q on storage
address determinism — "pin in orchestrator"). - Schema additive: new optional
storage[].offset_kib:(integer,
4 KiB-aligned) — explicit offset override for partitions that need
to coexist with bootloader-managed slots or migrate a legacy
layout. When supplied, the allocator does NOT shift its
high-water mark, so the bump-allocated siblings stay byte-stable.
Also new optionalmemory_region.dt_label:on the SoM preset
schema for regions whose Zephyr DT label differs from the SDK
name (defaults to the regionname). - New emitters:
emit_dts_partitions(project)→dts-partitions.dtsi(a
DTS overlay decorating&<dt_label>with apartitions { compatible = "fixed-partitions"; ... }child node carryinglabel = "<name>";andreg = <offset size>;per partition).
Apps reach partitions via Zephyr'sFIXED_PARTITION_ID(<name>_partition).emit_storage_mounts_c(project)→ optional staticfs_mount_t alp_storage_mounts[]table for boot-time iteration.
Per-fs declarations (FS_LITTLEFS_DECLARE_DEFAULT_CONFIG,FATFS,FS_EXT2) emitted under/* clang-format off */.- Per-fs Kconfig in
_slice_alp_conf():CONFIG_FILE_SYSTEM=y
plus the matchingCONFIG_FILE_SYSTEM_LITTLEFS=y/CONFIG_FAT_FILESYSTEM_ELM=y/CONFIG_FILE_SYSTEM_EXT2=y- per-littlefs partition
CONFIG_FS_LITTLEFS_PARTITION_<NAME>=y.
- per-littlefs partition
- CLI:
python3 scripts/alp_orchestrate.py --emit dts-partitions | storage-mounts-c— two new emit modes for inspecting the
resolved layout.Orchestrator._materialise_shared()now writesbuild/generated/dts-partitions.dtsialongside the existingdts-reservations.dtsi. - Cross-field validation:
load_board_yaml()rejects typoedflash_device:references at parse time with the list of known
devices for the project's SoM (memory_map regions + ospi keys);
duplicate partition names withinstorage:error eagerly. - System manifest:
storage:round-trips throughbuild/system-manifest.yamlcarrying every resolved partition'soffset_kib,size_kib,dt_label,mount, and (when blocked)reason:. - Tests: 14 new cases under
tests/scripts/test_alp_orchestrate.pycovering: happy-path
allocation, unknown / duplicate / page-misaligned / overflow /
overlap blocking, byte-stable determinism, explicitoffset_kib:
override, DTS shape, Kconfig fragment, C mount table, manifest
round-trip, and AEN301 OSPI TBD-capacity blocking. Total
orchestrator suite: 28 → 42 cases. - Docs:
docs/board-config.mdstorage section rewritten with
the full v0.6 contract (allocator semantics, emit artefacts,
inspection commands). Tutorial 09 (board.yaml deep dive) gains
astorage:block walkthrough with a worked allocation table.
Template atmetadata/templates/board.yamlcarries an annotated
storage example.
Added — security.psa: TF-M sysbuild integration + ADR 0013 (2026-05-20)
Pulls the security.psa: block from "schema authoritative, emit
no-op" to "real build-system artefacts". Scoped to the v0.6
TF-M cross-core trust-boundary land.
scripts/alp_orchestrate.pygainsemit_tfm_sysbuild_conf(project).
Whensecurity.psa.tfm: trueit returns aSB_CONFIG_TFM=y+SB_CONFIG_TFM_BUILD_TYPE=<Release|Debug|MinSizeRel>+CONFIG_PSA_CRYPTO_PERSISTENT_SLOT_COUNT=<n>+CONFIG_PSA_CRYPTO_{ITS,PS}_BACKING_STORE="<name>"overlay.attestation_root: optiga_trust_maddsCONFIG_ALP_SDK_PSA_ATTESTATION_OPTIGA=y+ a comment pointing at
the PSA <-> OPTIGA bridge driver. Returns "" when the block is
absent ortfm: false(PSA Crypto then runs non-secure-only).Orchestrator._materialise_shared()writes the overlay tobuild/sysbuild/tfm/tfm.confwhen non-empty; no directory is
created otherwise.- New CLI mode:
python3 scripts/alp_orchestrate.py --emit tfm-sysbuild-conf(alongside the existingsystem-manifest/ipc-contract-h/dts-reservations
emitters). load_board_yaml()gains three cross-field checks:security.psa.its_storage:andps_storage:must resolve to astorage[].nameOR a SoMmemory_map:region name; andattestation_root: optiga_trust_mis rejected when the SoM
preset doesn't ship OPTIGA Trust M (on-module or viacapabilities:). Errors point at the offending YAML path.- New
boot.build_type:enum (Release|Debug|MinSizeRel,
defaultRelease). Propagates to both the MCUboot and TF-M
sysbuild child images so they ship the same flavour. - New ADR:
docs/adr/0013-tfm-boundary-m55-hp-trustzone.md
-- captures the locked-in cross-core trust-boundary decision
(TrustZone-M on M55-HP, not a dedicated M55-HE). Refines ADR
0010. M55-HE stays available for compute / inference offload. - Schema:
security.psa:description refreshed (the "pre-v0.6 ...
emit path is a no-op" note is gone);boot.build_type:
documented. Templatemetadata/templates/board.yamlgrows a
commentedsecurity.psa:example. - Docs:
docs/board-config.md§PSA Crypto + TF-M now describes
the v0.6 emit contract;docs/security-audit-plan.mdgains a
short TF-M trust boundary section pointing at ADR 0013. - Tests: 11 new cases in
tests/scripts/test_alp_orchestrate.pycovering happy-path
emit, schema field round-trip, ITS/PS backing-store reference
validation (happy + rejection), attestation-root OPTIGA
cross-check, absence-emits-nothing, materialise round-trip, and
build-type inheritance. Full suite: 413 passed / 5 skipped (was
402 / 5).
Added — extra_libraries: escape hatch for non-curated libraries (2026-05-20)
cores.<id>.extra_libraries: joins libraries: (the closed,
25-entry curated enum) with an open-set escape hatch for libraries
the SDK doesn't curate -- one-off vendor SDKs, research-only deps,
or libraries on their way into the curated set. Each entry MUST
declare exactly one of:
kconfig:-- inline Kconfig fragment lines emitted verbatim
into the slice'salp.conf. Fast path for one-off entries.profile:-- path to ahw-backends.yaml-style profile file.
The loader walks the file with the same silicon / soc_family /
requires_cap matcher used by curated libraries; first match perclass:wins,sw_fallback:always emits.
The "exactly-one" rule is enforced by the new_validate_consistency() pass (see below), along with global
uniqueness of name: across cores and a check thatprofile: paths resolve to a real file. Names that collide with
the curated libraries: enum are rejected -- the curated path is
the right way to wire curated libraries.
Schema lives in metadata/schemas/board.schema.json undercores.<id>.extra_libraries; reference doc atdocs/board-config.md § extra_libraries: and tutorial coverage
at docs/tutorials/09-board-yaml-deep-dive.md § extra_libraries.
Added — cross-field validator pass with 5 rules (2026-05-20)
scripts/alp_orchestrate.py:_validate_consistency() runs after
the JSON Schema pass and the per-core loader rules. Five rules,
two warnings:
- (ERROR)
ota.provider: menderrequires at least onecores.<id>.os: yoctoslice. Mender server-mode is a
Yocto-only flow today; the Zephyr-side dispatch
(Mender-MCU-client) lands separately per ADR 0009. - (ERROR)
boot.signing.algorithm:must be supported by the SoM
family. Per-family allow-lists: Alif Ensemble (with OPTIGA
Trust M attestation root)ecdsa_p256/ed25519; Renesas
RZ/V2N + NXP i.MX 9ecdsa_p256/rsa2048/rsa3072.
Unknown families fall through (no capability-block enforcement). - (ERROR)
cores.<id>.iot.tls: truerequiresmbedtlsorbearsslinlibraries:(curated) orextra_libraries:
(open-set). - (WARN)
cores.<id>.inference.default_arena_kib > cores.<id>.memory.heap_kib-- inference may OOM. Build
continues; stderrWARN: ...line emitted. - (WARN)
cores.<id>.power.sleep_mode != disabledwith nowakeup_sources:declared -- device will sleep but cannot
wake.
Reference doc: docs/board-config.md § Cross-field validation.
Two in-repo examples (iot-fleet-ota, iot-dashboard,production-deployment) updated to satisfy rule 3 by declaringmbedtls in libraries:.
Added — examples adopting v0.6 declarative blocks (iot-fleet-ota promotion + production-deployment + power-managed-sensor) (2026-05-20)
examples/iot-fleet-ota/board.yamlpromoted from prose-only OTA
narration to declarativeboot:+ota:blocks (MCUboot +
ECDSA-P256 + Mender HTTPS-poll with${MENDER_TENANT_TOKEN}
placeholder). README rewritten with the "What lands
declaratively in v0.6" walkthrough.examples/production-deployment/board.yamlrefactored into the
SDK's declarative-stack flagship: every v0.6 block applied at
production stance (boot:/ota:/security.psa:/storage:/cores.<id>.memory:/cores.<id>.power:/diagnostics.modules:)
on AEN701 with TF-M + OPTIGA-rooted attestation. README gains
a full per-block walkthrough.examples/power-managed-sensor/(new): reference for the v0.6cores.<id>.power:block. AEN301 + M55-HE deep sleep withwakeup_sources: [uart, gpio_int, rtc]covering the periodic
sample / motion-event / console-debug duty cycle. Memory tuned
for the short-lived per-wake task (4 KiB stack, 16 KiB heap).
Changed — board.yaml flatten + carrier→board rename + 7 declarative blocks (2026-05-20)
Breaking schema changes (no migration script — every in-repoboard.yaml rewritten in the same change).
board.yamlschema flattened: dropped thecarrier:wrapper.name,description,hw_rev,populated,e1m_routes,pins,presetare now top-level fields. Two modes: inline
(customer path) orpreset:(SDK-internal shortcut, used by
the ~40 EVK demos underexamples/).schema_versionfield removed entirely. One live schema atmetadata/schemas/board.schema.json.- "Carrier" noun retired in favour of "board" everywhere: file
paths (metadata/carriers/→metadata/boards/,scripts/gen_carrier_header.py→scripts/gen_board_header.py,metadata/schemas/board-config-v2.schema.json→metadata/schemas/board.schema.json, newmetadata/schemas/board-preset.schema.jsonfor the shared
YAMLs); SoM presets'default_carrier:→default_board:; C
APIalp_hw_info_t.carrier_*→board_*fields andALP_HW_BUILD_CARRIER_*→ALP_HW_BUILD_BOARD_*macros.
Schema additions (additive; existing board.yaml files validate):
e1m_routes:grows 5 sections beyond the original
gpio/buses/pwm:adc,dac,i2s,can,qenc(E1M_ENC
pads). Per-section pad-class validation: misclassified pads
(e.g.E1M_I2C0underadc:) error at validate time.e1m_routes:entry shape gains optionalpull:(up|down|none)
anddebounce_ms:(board-static electrical facts).routes_via:removed (SoM concern; moved to SoM preset'spad_routes.dispatch:).pins:entries can be bare strings OR{e1m, macro?, doc?}
rich form. Validator cross-checks the macro against the
resolved board.cores.<id>.memory: { stack_kib, heap_kib, isr_stack_kib }
→ emitsCONFIG_MAIN_STACK_SIZE/CONFIG_HEAP_MEM_POOL_SIZE
/CONFIG_ISR_STACK_SIZE.cores.<id>.power: { sleep_mode, wakeup_sources }→ emitsCONFIG_PM+CONFIG_PM_DEVICE_WAKE_<SUBSYS>.diagnostics.modules: { <name>: <level> }→ per-moduleCONFIG_<MODULE>_LOG_LEVEL=<n>(supportsoff).- New top-level
boot:block (MCUboot configuration). Loader's
newemit_sysbuild_conf()produces aSB_CONFIG_*overlay
consumed viawest build --sysbuild-config build/alp_sysbuild.conf. - New top-level
ota:block (Mender / MCUmgr). Loader appendsMENDER_*weak-assignments (?=) +INHERIT += "mender-full"
to the Yocto slice'slocal.conf. - New top-level
storage:block (filesystem partitions).
Schema authoritative; DTS-overlay emit lands in v0.6 alongside
the deterministic flash-allocator. - New top-level
security.psa:block (TF-M + PSA Crypto).
Schema authoritative; TF-M sysbuild child-image plumbing lands
in v0.6.
EVK preset seeded: metadata/boards/e1m-evk.yaml now declares
the full canonical EVK wiring across all 8 sections — ADC0..ADC7
(board-id, Arduino A1..A5, mikroBUS AN, VBAT sense), DAC0/DAC1,
I2S0/I2S1, CAN0, ENC0 (PEC12R rotary). Generated routes header
grows 79 → 125 lines.
Migration delta: 41 example board.yaml files migrated to the
flat form with annotated pins: arrays where applicable; 9
test files in tests/scripts/ updated; ~200 source files swept
for prose-level carrier→board rename. Full docs sweep across
README, architecture, board-config, getting-started,
firmware-quickstart, heterogeneous-builds, portability,
porting-new-som, secure-boot, ota, and tutorials 09/10/11/12/16.
ABI snapshot at docs/abi/v0.5-snapshot.json regenerated to
match the renamed alp_hw_info_t fields. All tests green:
402 passed / 5 skipped.
Added — Intra-family portability proof + Phase B/C audit cleanups (2026-05-18)
Portability is now empirically proven. Phase A swap-test
matrix: 21/21 E1M cells green (i2c-scanner / gpio-button-led /
pwm-led-fade across all 7 E1M SKUs) + 12/12 E1M-X cells green
(adc-voltmeter / pwm-led-fade / v2n-pwm-fan-control across all 4
E1M-X SKUs). Within the AEN sub-family, generated alp.conf is
byte-identical across all 6 SKUs after stripping the SoC-enable
line. Customer-facing matrix atdocs/portability-matrix.md (new).
Phase B gap fixes (all 5 surfaced gaps resolved):
- A2-1
metadata/e1m_modules/E1M-V2M102.yamlpad_routes:useE1M_X_*namespace (wasE1M_*— E1M form factor leaked into
an E1M-X SoM). Apps consuming<alp/e1m_x_pinout.h>now resolve
on V2M102 like the other 3 E1M-X SoMs. - A2-2 V2M101 + V2M102 gain the 8
E1M_X_GPIO_IO27..IO35
extension routes V2N already had (maintainer confirmed GD32
routing is identical on V2M). - G-1 Per-variant Ethos-U Kconfig: orchestrator walks SoM
inference.npu_population[]and emitsCONFIG_ALP_SDK_INFERENCE_ETHOS_U_U55=y/_U65=y/_U85=y
per variant present. AEN401/601/801 now emit BOTH_U55and_U85; previously the U85's TensorOptimized kernels were
invisible to the build. Driver dispatch insrc/zephyr/inference_tflm.cppselects per-variant kernel pack
at compile time;alp_inference_tflm_npu_variant_name()exposes
the active variant for HiL operators. - G-2 Per-CPU-class TFLM kernel selector: orchestrator emits
CONFIG_ALP_SDK_INFERENCE_TFLM_NEON=y(A-cluster) /_HELIUM=y(M55) /_REF=y(baseline Cortex-M) per slice
from SoC-JSONcores[<core_id>].vector_extension. - G-4
cores.<key>rename diagnostic: hard-fails with "did
you mean one of: [...]" hint when nocores:key intersects
the preset'stopology:keys. Soft-warns per dropped key on
partial matches.
Phase C cleanups (bundled — audit-deferred items):
- C.1
button_led+pdm_micrelocated fromchips/toblocks/(alp_*-prefixed helpers are SDK abstractions, not
chip drivers, per[[chip-driver-naming]]). History-preservinggit mv. KconfigCONFIG_ALP_SDK_CHIP_BUTTON_LED→_BLOCK_BUTTON_LED+_BLOCK_PDM_MIC; orchestrator dispatches
per slug. Updated 25+ consumers; newblocks/README.md. - C.2 Four Yocto NOSUPPORT stubs added
(src/yocto/peripheral_{can,i2s,rtc,wdt}.c) — Yocto link line
now provides every<alp/*>symbol the public headers declare. - C.3
_Static_assertALP↔GD32 PWM align wire-encoding parity
insrc/zephyr/peripheral_pwm.c; cast now fails to compile if
either enum is reordered. - C.4 Comment density boost on
examples/rpmsg-imx93/m33/src/main.c
(21 % → 67 %) andexamples/drone-autopilot/src/main.c
(30 % → 60 %); both clear the ~50 % examples-are-documentation target. - C.5
[PAPER-CORRECT-STUB]@par Verification statusblocks
added toact8760.h/da9292.h/ov5640.hpublic headers so
API consumers see which surfaces returnALP_ERR_NOSUPPORT. - C.6
metadata/socs/nxp/imx9/imx93.jsonflagged withpending_reference_manual_ingestion: true(no invented peripheral
counts); schema +validate_metadata.pyextended to accept + WARN
on the new field.
Verification: pytest tests/scripts/ 367 passed (357 baseline + 10
new G-1/G-2/G-4 tests, 0 regressions); validate_metadata.py 0
failures; check_example_portability.py 47/0.
Added — Phase D documentation push (2026-05-18)
Six-pack of documentation work anchoring the just-proven intra-
family portability promise:
- D.1
docs/portability.md(NEW, 814 lines) — customer-facing
portability cookbook with 6 sections: swap-and-run scope, the
swap-test recipe (two worked examples), dual-namespace decision
tree, intentional gaps (NPU model artefacts, form-factor symbol
errors, heterogeneous-OS topology, carrier-specific HW),
capability validation viaalp_last_error()+ALP_ERR_NOSUPPORT- the runtime fallback ladder, link to the empirical matrix.
- D.2
docs/porting-new-som.mdrewritten as a 30-minute
walkthrough of adding a hypothetical 7th AEN SKU (E1M-AEN901). - D.3
docs/architecture.mdrepository-layout tree refreshed
to the post-slice-3a/3b state; four new sub-sections under
"Build orchestration" (per-core slice fan-out, sparse capabilities
flow, on_module: auto-enable, generators inventory). - D.4
docs/v1.0-readiness.mdgains Pillar 3f "Intra-family
portability proven" with checkboxes for the matrix, cookbook,
ADR 0011, and the 5 Phase B gap closures. - D.5 All 16
docs/tutorials/*.mdcross-checked. Tutorial-04
rewritten around the intra-family promise (old three-rings
cross-family model superseded). Tutorial-09 + tutorial-16
light-edited to fix board.yaml + inference API drift + add G-1/G-2
variant-selector pointers. Other 13 got a "Last verified:
2026-05-18" header line. - D.6
docs/adr/0011-intra-family-portability.md(NEW, 191
lines) — Architecture Decision Record ratifying the load-bearing
intra-family portability scope.
Plus docs/README.md (NEW) — top-level doc navigation hub linking
all the new and existing docs into topic groupings.
Added — Cross-platform developer host first-class (2026-05-18)
Codify cross-platform Win + Mac + Linux developer support as a
load-bearing SDK principle so customers never feel "I need Linux
to use the alp-sdk." Yocto remains Linux-only by upstream
constraint; the Zephyr-on-M-class workflow is first-class on every
host.
docs/adr/0012-cross-platform-developer-host.md(NEW) — ADR
codifying the principle, alternatives rejected (Linux-first via
WSL2, Linux-only, per-OS forks), consequences (CI cost rises
but adoption uplift justifies it).docs/cross-platform-setup.md(NEW, 720 lines) — 8-section
per-OS quickstart (Linux Debian/Ubuntu/Fedora, macOS Homebrew- Apple Silicon, Windows native PowerShell + winget + Arm GNU
MSI + setx, Windows + WSL2 for Yocto), verification walkthrough,
known gotchas (MAX_PATH, AV, CRLF, Gatekeeper, symlinks, serial
device naming), what's-Linux-only-and-why scoping.
- Apple Silicon, Windows native PowerShell + winget + Arm GNU
scripts/check_cross_platform.py(NEW, 618 lines) — soft-warn
lint for Linux-only idioms (hard-coded/dev/paths,~/.bashrcmentions, bash-only shebangs,makein
tutorial-grade docs, forward-slash absolute paths). Two
suppression mechanisms:INTENTIONALLY_DISCUSSES_OS_PATHS
allowlist (collapses N findings to one summary line) and inline<!-- cross-platform-lint:ignore -->skip markers. CLI flags--fail-on-warning,--quiet,--json. 37 pytest cases attests/scripts/test_check_cross_platform.py(NEW)..github/workflows/cross-platform-zephyr.yml(NEW) — CI matrix
scaffolding. Ubuntu strict; macOS + Windowscontinue-on-error: trueper ADR 0012 (surface drift, don't
block while runners prove out).- Lint cleanup of 28 → 0 findings on the existing tree (placeholder
serial device paths in example READMEs;<your-shell-rc>
placeholder indocs/local-ci.md; cross-platform header notes
onscripts/bootstrap.sh+scripts/test-all.sh).
Added — 8 vendor-SDK-style peripheral tutorial examples (2026-05-18)
Vendor-SDK-style canonical "first program" + per-peripheral
tutorial set. Each example follows the standard six-file layout
(board.yaml, prj.conf, CMakeLists.txt, README.md, src/main.c,
testcase.yaml) plus native_sim overlays where needed; comment
density on main.c targets ~50 % per [[examples-are-documentation]].
examples/hello-world— zero-peripheral printf heartbeat viaalp_log_*. The canonical first build (74 % comment density).examples/uart-hello-world— producer-only "printf via UART"
walkthrough (companion to bidirectional uart-echo).examples/i2c-master— read TMP112 temperature sensor; contrasts
withi2c-scanner(discovery vs known-address read).examples/i2c-slave— slave-mode SHAPE + explicit SDK gap notice
(<alp/peripheral.h>is master-only today; local NOSUPPORT shim
templates the proposedalp_i2c_slave_*surface for v0.7).examples/spi-master— discrete master demonstrating write /
transceive / read patterns.examples/spi-slave— slave-mode SHAPE + SDK gap notice (same
class as i2c-slave).examples/dac-waveform— 100 Hz sine onE1M_X_DAC0via the
V2N GD32 supervisor bridge (E1M-X targeted).examples/timer-periodic-interrupt— re-arming periodic alarm
viaalp_counter_*+ ISR-safe coordination pattern.
examples/README.md index updated. check_example_portability.py:
55 examples (was 47), 0 errors.
Schema tightening — silicon-determined fields removed from board.yaml (2026-05-16)
Customer-facing knobs in board.yaml v2 are now restricted to
project-level choices. Anything dictated by the SoM SKU's silicon
(NPU presence, on-module component populations, memory capacities,
per-core natural runtime) is read from the SoM preset undermetadata/e1m_modules/<MPN>.yaml and is no longer overridable at
the project level.
Schema changes (breaking — board.yaml v2):
cores.<id>.inference.backendremoved. The build now compiles
in every dispatcher the SoM preset'scapabilities:block
declares (TFLM CPU always, plus Ethos-U / DRP-AI3 / DEEPX DX-M1
per the SoM caps). Apps pick which to use per-handle at runtime
viaalp_inference_open(.backend = …). This unblocks concurrent
multi-NPU dispatch on V2M101 (DRP-AI3 + DEEPX DX-M1 running
independent models simultaneously) which the old "pick one
backend" wiring silently broke.cores.<id>.osis now optional. Every core has a natural
runtime baked into the SoM preset'stopology:block (Cortex-M
→ Zephyr, Cortex-A → Yocto Linux); customers writeos:only to
override (os: offto skip a core,os: baremetalfor hand-
written firmware on a core that normally runs Zephyr).som.overridesremoved. For a custom SoM variant (e.g. an
AEN without the OPTIGA Trust M), create a new MPN preset undermetadata/e1m_modules/rather than overriding here.som.memoryremoved. Same reasoning — memory capacities are
silicon-determined. Custom memory variants get their own MPN
preset.
Loader changes:
scripts/alp_orchestrate.py:_slice_alp_confnow emitsCONFIG_ALP_SDK_INFERENCE_*from the SoMcapabilities:matrix
(was: emitted nothing — examples carried hand-writtenCONFIG_ALP_SDK_INFERENCE_TFLM=yinprj.conf).scripts/alp_orchestrate.py:_slice_cmake_argsnow emits-DALP_SDK_USE_DRPAI=ON/-DALP_SDK_USE_DEEPX_DXM1=ONper
the SoM caps; V2M101 baremetal/Yocto builds get both.
Migration:
cores:
m55_hp:
- os: zephyr # delete -- topology default
app: ./src
inference:
- backend: ethos_u # delete -- silicon-determined
default_arena_kib: 256 som:
sku: E1M-AEN701
- overrides: # delete -- create new MPN preset instead
- secure_element: none
- memory: # delete -- create new MPN preset instead
- flash_mbit: 131072Tests:
tests/scripts/test_alp_project.pyaddsTestInferenceFromSomCaps
covering: SoM-caps-driven CONFIG emission per family, schema-level
rejection ofinference.backend, V2M101 cmake-args emitting both
DRPAI + DEEPX_DXM1 flags.
Principle: silicon-determined facts live inmetadata/e1m_modules/<MPN>.yaml; board.yaml carries only
project-level choices. Seedocs/board-config.md "Silicon-determined
fields never appear in board.yaml".
(Tracks metadata/sdk_version.yaml's declared version. PerVERSIONS.md, every point release ships the surface first
and accumulates runtime implementations in subsequent point
releases -- entries below collect every Added / Changed item
that lands before the v0.6.0 tag.)
Verification status. Entries below describe what's been
coded and merged onmain; passingpr-plain-cmake/pr-twister/pr-static-analysis/pr-alp-buildis
necessary but not sufficient to call an item "GA". Real-hardware
verification is tracked separately indocs/test-plan.md-- a release does not
tag until every row gating it flips to ✅.
v0.6.0 — Heterogeneous OS orchestration (2026-05-15)
The v0.6 redesign drops the framing that os: is a single
SoM-wide choice and turns Zephyr / Yocto / bare-metal into
peers that coexist on the same SoM, declared per-core from oneboard.yaml. Full design atdocs/superpowers/specs/2026-05-15-heterogeneous-os-orchestration-design.md;
decision recorded indocs/adr/0010-heterogeneous-os-orchestration.md.
[UNTESTED] across the board -- AEN + iMX93 hardware-fact
fields carry TBD strings pending the maintainer's hand-written
HW config per the project's "never invent values" convention.
Added
- Heterogeneous OS orchestration. Per-core
cores:block inboard.yamlv2 lets one project run Yocto on a Cortex-A cluster,
Zephyr on a Cortex-M peer, and bare-metal on a third core -- all
from one declarative config. Each on-die programmable core takes
its ownos:/app:/peripherals:/libraries:/inference:/iot:block. <alp/rpc.h>framed RPC layer on top of OpenAMP / RPMsg.
Zephyr backend (full) + Linux backend (full per Wave 5A); apps
never type endpoint IDs or carve-out addresses by hand.- Five west extension commands replacing the single
west alp-buildfrom v0.5:west alp-build-- fan board.yaml out into per-core slices,
emitsystem-manifest.yaml.west alp-image-- consume the manifest, assemble a flashable
bundle (build/image-bundle/).west alp-flash-- walk the manifest'sboot_order:and
program each piece with the right backend tool.west alp-clean-- tear down per-slice build dirs idempotently.west alp-renode-- boot the dual-OS image in Renode and
drive the RPMsg handshake smoke test.
- Generated artefacts emitted by
scripts/alp_orchestrate.py:build/system-manifest.yaml-- per-slice status + log paths +
artefact paths + boot order, byte-stable across rebuilds.build/generated/dts-reservations.dtsi-- shared-memory
carve-outs as Linux + Zephyr DT reservations.build/generated/alp/system_ipc.h-- name + address + endpoint
ID + mailbox channel macros that both halves#includevia<alp/system_ipc.h>. Carries an#errordirective for any
blocked channel so the slice build trips when the SoM metadata
isn't ready yet (see "Blocked carve-outs" below).
- 3 flagship heterogeneous examples plus an offload demo:
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 an FFT
computation to the M peer over RPMsg.
- 14 Zephyr DT overlays covering every SoM × M-class core combo.
- Yocto recipes under
meta-alp-sdk/recipes-alp/:alp-remoteproc_0.6.bb-- userspace remoteproc helper.alp-dts-reservations_0.6.bb-- generatedreserved-memory:
fragment shipped into the kernel DT.alp-chips_0.6.bb-- absorbed from the deletedyocto/meta-alp/layer.alp-edgeai_0.6.bb-- path-rebased to track the renamedexamples/aen/edgeai-vision-aen/source tree.
- Per-SoM
topology:,memory_map:,mailbox:,helper_firmware:blocks inmetadata/e1m_modules/E1M-*.yaml
drive the orchestrator. The topology key set mirrors the SoC'scores[].idset exactly (cross-checked bypr-metadata-validate.yml). - ADR 0010 +
docs/heterogeneous-builds.md
walkthrough + glossary terms (system manifest, slice, carve-out,
helper-MCU firmware, topology key set). - 3 new CI workflows:
.github/workflows/pr-alp-build.yml-- orchestrator gate
across SoM × scenario matrix, asserts the system-manifest is
byte-stable across rebuilds..github/workflows/pr-bitbake.yml-- self-hosted runner gate
that buildsalp-image-edgeper A-cluster MACHINE..github/workflows/pr-renode-dual-os.yml-- Renode dual-OS
smoke test (advisory until the self-hosted Renode runner
ships in v0.6.1).
- Real flash backends under
scripts/flash_backends/(Wave 5B):
vendor flasher for the SoC, openocd-via-SWD for the GD32 helper,
USB-CDC bootloader for CC3501E.west alp-flashwalks the
manifest and dispatches to the right backend per artefact -- no
developer-side tool-selection.
Changed
board.yamlschema bumped to v2 -- top-levelos:field
removed;peripherals:/libraries:/inference:/iot:
moved per-core undercores.<id>.carrier.populated:+chips:anddiagnostics:stay top-level (they describe
physical assembly + project-wide diagnostics). No migration
script -- no shipping customers yet; every in-repoboard.yaml
is rewritten in the same redesign PR (32 files).examples/mproc-dual-os-yocto-zephyr/→examples/rpmsg-v2n/(renamed + sub-tree restructured;m33/→m33_sm/to match the SoM topology key).metadata/e1m_modules/E1M-*.yamlgainedtopology:+memory_map:+mailbox:+helper_firmware:blocks. V2N
preset is fully authored from the maintainer-confirmed pinmap;
AEN + iMX93 carryTBDstrings on hardware-fact fields
(memory_map.base,mailbox.controller, AENcc3501e_otp
firmware path).metadata/socs/.../*.jsoncores[]-- every entry now
carries anid:field used as the topology key.docs/os-support-matrix.mdrestructured from per-(SoM, OS)
columns to per-(SoM, core, OS) columns; split into Cortex-A and
Cortex-M tables.- README "30-second quick start" rewritten with a v2 per-core
example; "Status" section updated to v0.6 ramp. meta-alp-sdk/conf/machine/MACHINEs renamed frome1m-v2n101.conftoe1m-v2n101-a55.conf(per-cluster
naming -- the M33-SM is no longer implied to be part of the same
MACHINE).pr-bitbake.ymlmatrix updated accordingly.- AEN + iMX93 SoM presets carry
TBDstrings on hardware-fact
fields pending the maintainer's hand-written HW config. Per the
project's "never invent values" convention these stayTBD
rather than guessed defaults; the AEN audit atdocs/aen-feature-audit-2026-05.mdand the iMX93 reference
manual sections to cross-check are linked from each preset.
Removed
metadata/schemas/board-config-v1.schema.json-- v2 fully
replaces; no dual-schema fallback in the loader.yocto/meta-alp/(entire tree) -- content absorbed intometa-alp-sdk/; the duplicate layer is deleted. Customers
consuming the old layer name should re-point atmeta-alp-sdk.scripts/west_commands/alp.py-- split into 5 focused
command modules (alp_build.py,alp_image.py,alp_flash.py,alp_clean.py,alp_renode.py) under the same directory. Thewest alp-buildentry point keeps its CLI surface; the v0.5
monolithic file is gone.
Fixed
- The 13-line workaround comment at the top of the old
examples/mproc-dual-os-yocto-zephyr/board.yamlapologising
that the two halves could not share one declaration -- removed.
Both halves now drive from one v2board.yaml, the example
shape the schema expects to be used. resolve_carve_outs()emitsstatus: blockedinstead of
raising on TBD SoM metadata (mailbox controller, memory_map
base / size). The manifest stays emit-able when the preset
isn't fully HW-mapped yet — CI's manifest-shape + determinism
gates pass while the actual slice build is what trips (via the
generated<alp/system_ipc.h>#errordirective). Required
for the AEN + iMX93 examples to flow throughpr-alp-buildwhile
the preset's hardware-fact fields are still TBD.system-manifest.yamlis byte-stable across rebuilds.
Dropped the wall-clockduration_sfield fromSlice.to_manifest_entry()— the metric stays on the runtime
Slice dataclass forwest alp-buildlogging but never lands in
the declarative manifest. Satisfies spec §6.1's determinism
clause:west alp-clean && rebuild && diffis now a no-op.
Enforced bypr-alp-build.yml's "Determinism check" step.<alp/system_ipc.h>path canonical atgenerated/alp/
(wasgenerated/alp_system_ipc.h) — matches the#include <alp/system_ipc.h>consumer pattern documented ininclude/alp/rpc.h. Slice CMakeLists drop${CMAKE_BINARY_DIR}/generatedontozephyr_include_directories
and the include resolves with no munging.- v2
zephyr-confemit now carries chip drivers + subsystem deps._slice_alp_confwas only emitting baseline + silicon +
per-core peripherals + libraries; it dropped thecarrier.populated:
chip-driver block that the v1 emit had under_emit_zephyr.
Apps that depend on a populated chip (e.g.iot-connected-camera'sssd1306+button_led) lostCONFIG_ALP_SDK_CHIP_*under v2 so
twister's native_sim link hitundefined reference to ssd1306_init.
v2 path now merges the SoM/carrier preset'spopulated:block with
the board.yaml override and emits both the chip-driver Kconfigs and
the matching subsystem enables (CONFIG_GPIO=y/CONFIG_I2C=y/
...) soGPIO_EMUL/I2C_EMULdeps are satisfied. examples/rpmsg-v2n/m33_sm/testcase.yaml(moved from project
root). The old top-level location made twister try to configure
the multi-slice project root as a Zephyr app — there's noCMakeLists.txtfindingZephyrat that level, so configure
crashed and aborted the whole run withFileNotFoundError: zephyr/.config. Move puts the testcase next
to its realCMakeLists.txt+ addsextra_args: CONFIG_ALP_SDK_RPC=yso the producer's<alp/rpc.h>symbols link.- Pre-existing chip header gaps surfaced once twister stopped
aborting mid-run.a4988.h/drv8825.h/drv8833.hnow#include "alp/pwm.h"(they declarealp_pwm_tfields but only
pulled inperipheral.h).tests/zephyr/chips/prj.confnow
enables every chip the suite calls*_init()on (the v0.5
§D.AI / §D.industrial / §D.iot / §D.audio batches were on by-include
but off by-Kconfig, so 80+ chip _init calls hitundefined reference). tests/zephyr/library_knobs/src/main.cstopped usingdefined(CONFIG_##x)as a runtime expression (the C preprocessor
operator only works in#ifdirectives — Zephyr providesIS_ENABLED()for the C-expression form). Dropped theCONFIG_FILE_SYSTEM_LITTLEFS=ypin and the mbedtls header
include — Zephyr v4.4'ssubsys/fs/littlefs_fs.c+ssl_misc.h
trip -Werror on this profile and the knob smoke doesn't need them.
Changed (CI)
pr-twister.ymldrops theghcr.io/zephyrproject-rtos/ci:v0.29.1
Docker container (~17 GB on disk; the public ubuntu-latest
runners only ship ~14 GB free, so the image pull intermittently
failed withno space left on device). Replaced with a native
ubuntu-latest job that pip-installswest+ the Zephyr Python
requirements and usesZEPHYR_TOOLCHAIN_VARIANT=hostsonative_sim/native/64builds use the runner's stock gcc. Saves
~5 minutes per run; eliminates the disk-pressure failure mode.
References
- ADR:
docs/adr/0010-heterogeneous-os-orchestration.md - Design spec:
docs/superpowers/specs/2026-05-15-heterogeneous-os-orchestration-design.md - App-developer walkthrough:
docs/heterogeneous-builds.md
Decided (hardware-design decisions captured 2026-05-12)
- All E1M PWM channels are GD32-driven; Renesas drives no PWMs.
The "either GD32 or Renesas, picked SoM-wide via resistor strap"
cross-source design is collapsed to a single GD32-only path.
RemovedGPT13_GTIOC13A(P64) /GPT13_GTIOC13B(P65) /GPT4_GTIOC4B(P75) rows frommetadata/e1m_modules/v2n/renesas-peripheral-map.{tsv,csv}.
GD32-side mapping unchanged:E1M PWM0..PWM7on GD32PA11 / PB1 / PB14 / PC5 / PC10 / PC11 / PC12 / PD0. The
resistor-strap selection is no longer applicable -- there's
nothing to switch between. - GD32 in-field reflash uses SWD-from-host, not factory-ISP / BOOT0.
The earlier "BOOT0 -> RenesasP75" plan is dropped in favour of a
software SWD bit-bang from the Renesas host -- SWD works regardless
of GD32 firmware state, where factory-ISP depends on the GD32 boot
ROM staying intact and would have required a third pad (a USART
line) on the V2N side. Net pad assignments (maintainer-confirmed):GD32_SWDIO-> RenesasP70(wasGPT0_GTIOC0A).GD32_SWCLK-> RenesasP71(wasGPT0_GTIOC0B).P75becomes unassigned on the Renesas side (BOOT0 dropped,
PWM5 moved entirely to GD32).
See [memoryproject_gd32_boot0_to_v2n_planned.md] for the design
rationale.
- GD32_NRST -> Renesas
P74(was E1M PWM4 / GPT4_GTIOC4A). PWM4
becomes GD32-only. Line is shared with the primary PMIC reset
out -- host pad MUST be configured open-drain (drive low to
assert reset; HiZ to release). An external pull-up returns the
line to its released state. - DEEPX
M1_RESETpolarity -> active-LOW. Thechips/deepx_dxm1/driver default flipped fromACTIVE_HIGH
(placeholder pending the schematic check) toACTIVE_LOW
(confirmed).deepx_dxm1_set_reset_polarity()still lets
carrier code override. - Murata
BT_DEV_WAKEintentionally not routed on V2N. Thechips/murata_lbee5hy2fy/driver already supported the NULL-
pin-handle case; metadata + header doc updated to make the
"not-routed" status explicit. - 5L35023B I2C address -> 7-bit
0x68(8-bit write0xD0) per
the Renesas 5L35023 public datasheet.
Fixed (2026-05-14 -- DA9292 OTP-variant bring-up correction)
da9292_v2n_m1_enable_deepx_railno longer over-volts DEEPX
to 1.50 V. The DA9292-AROVx OTP variant on V2N boots withCH2_VSTEP=1(PMC_CTRL_01 = 0x80, doubled-range encoding).
The previous bring-up wrote byte0x96toVOUT_CH2_VSEL_LO
expecting it to decode as 0.75 V (the VSTEP=0 mapping), but
silicon interpreted it as2 x 750 = 1500 mV. Fix: clearCH2_VSTEP+CH2_ENtogether in a singlePMC_CTRL_01
write before programming the voltage byte. Datasheet
constraint:CHx_VSTEPis only writable whileCHx_EN=0, so the EN clear must precede. Seechips/da9292/da9292.c::da9292_v2n_m1_enable_deepx_railand
the@warningblock ininclude/alp/chips/da9292.h.DA9292_I2C_ADDR_V2Ncorrected from0x1Cuto0x1Eu.
The macro had carried the wrong 7-bit address since the driver
landed; the AROVx OTP variant'sPMC_CFG_0Adefaults to 8-bit0x3C-> 7-bit0x1E. Affects nobody at runtime today (the
V2N firmware module that callsda9292_inithasn't landed yet)
but the macro is exposed ininclude/alp/chips/da9292.hso it
needed correcting before downstream consumers caught the bad
value.docs/abi/v0.5-snapshot.jsonregenerated.
Changed (2026-05-14 -- Zephyr v3.7.0 LTS → v4.4.0 stable bump)
The SDK's west.yml Zephyr pin moves from v3.7.0 LTS to v4.4.0
stable. Mainline feature access (LVGL v9, upstream Alif Ensemble
board files, the I2S _CONTROLLER naming, mbedtls 3.6) at the
cost of LTS support window. Customers shipping product with a
24-month support requirement should re-pin to v3.7.x in their own
manifest -- the SDK's <alp/*> surface stays binary-compatible.
Knock-on changes:
.github/workflows/pr-twister.yml+nightly-aen-hil.yml----mr v3.7.0→--mr v4.4.0; cache key bumped.- All
examples/*/testcase.yaml+README.mdentries that named
the v3.x boardalif_e7_dk_rtss_hp/_rtss_heretargeted to
the v4.4 upstream Alif boardensemble_e8_dk/ae402fa0e5597le0/rtss_hp
(closest available -- AEN-specific boards land later in
Alif's ownzephyr_aliffork). - LVGL Kconfig knob renames (LVGL v8 → v9):
CONFIG_LV_DISP_DEF_REFR_PERIOD→CONFIG_LV_DEF_REFR_PERIOD.CONFIG_LV_INDEV_DEF_READ_PERIOD-- removed in v9; runtimelv_indev_set_read_timer_period()instead.
- LVGL demo source sets (
lv_demo_widgets.c,lv_demo_benchmark.c,lv_demo_music*.c) are no longer compiled by the Zephyr lvgl
module's CMakeLists; demo examples add them to their owntarget_sources()explicitly. src/zephyr/peripheral_i2s.c--I2S_OPT_FRAME_CLK_MASTER/I2S_OPT_BIT_CLK_MASTERare deprecated in v4.4; renamed to_CONTROLLERper Zephyr's inclusive-language pass.docs/zephyr-version-policy.md,getting-started.md,troubleshooting.md,glossary.mdupdated.- New
docs/local-ci.md-- Windows-native + WSL2 paths for
running twister locally so contributors don't bounce off CI for
every iteration.
Added (2026-05-14 -- 7 demo source-level fixes + 6 new flagship demos)
Real bugs the v4.4 bump surfaced + new demo apps for the website
gallery. All marked [UNTESTED] -- they build on native_sim
but haven't been HIL-validated.
Source fixes (real API drift in v0.5 demos):
drone-autopilot/src/{main,autopilot,mavlink}.c+board.yaml
-- chip API mismatches (lsm6dso_axes_t, ina236 signature, UART
field namebaudrate, INA236 default I²C addr literal, PWM
header include, missing<stdio.h>, float/double promotion in
the GPS pack, MAVLink UART moved off the non-existent
E1M_UART2). Board.yaml gains acarrier.populated:override
forbmp390+ublox_neo_m9nso the loader emits their chip
knobs (the loader doesn't yet honour a top-levelchips:block).drone-hud/src/sensors.c-- same class of fixes.ai-camera-viewer/src/inference_loop.c--alp_camera_config_t
andalp_inference_config_treconciled with the real header
field names.iot-dashboard/src/main.c--bme280_compensatesignature
rewrite (it returns a struct, not three out-params),<stdio.h>
forsnprintf,CONFIG_LV_FONT_MONTSERRAT_28=yadded to prj.conf.production-deployment/prj.conf--CONFIG_MBEDTLS=non
native_sim to dodge Zephyr 4.4's PSA-crypto wiring (real fix in
v0.6 via tf-psa-crypto).- All 15
examples/*-*/testcase.yamlfiles that an earlier
auto-edit had left withharness: consoleindented inside thetags:list re-shaped to the correct flat layout. - 7 new demo
CMakeLists.txtfiles --find_package(Python3 REQUIRED COMPONENTS Interpreter)moved BEFOREfind_package(Zephyr)so${Python3_EXECUTABLE}is defined
when the alp_project loader runs.
New flagship demos (paper-correct stubs, ~50 % comment ratio):
examples/ai-object-detection-realtime/-- YOLOv8-tiny on
V2N-M1 (DEEPX 29 TOPS) + V2H-M1 (DEEPX 113 TOPS). Camera →
inference → bounding-box overlay → FPS counter.examples/ai-anomaly-detection-vibration/-- accelerometer →
1D-CNN → anomaly score for predictive maintenance. AEN
always-on Ethos-U + V2N.examples/iot-fleet-ota/-- secure OTA + rollback signed by
the OPTIGA Trust M secure element. All E1M-X SoMs.examples/audio-noise-suppression/-- DSP + AI pipeline,
~10 ms latency. V2N + V2H DSP cores.examples/audio-wake-word/-- always-on keyword spotting on
AEN's Ethos-U at sub-mW. E1M-AEN.examples/mproc-dual-os-yocto-zephyr/-- Yocto/A55 + Zephyr/M33
shared-memory IPC, dual-firmware shape, dual-update lifecycle.
V2N + V2H.
Added (2026-05-14 -- meta-alp-sdk Yocto layer + drone-autopilot MAVLink GCS link)
[UNTESTED] -- both pieces are paper-correct v0.5 scaffolding.
meta-alp-sdk/-- top-level Yocto layer that wires the SDK into
ROS 2 Humble + DEEPX-on-Linux images for V2N + V2N-M1 Linux
targets. Layer compatibility:kirkstone scarthgap. Ships:conf/layer.conf+conf/machine/e1m-v2n101.conf+conf/machine/e1m-v2m101.conf(V2N base vs V2N + DEEPX SoM).recipes-core/alp-sdk/alp-sdk_0.5.bb-- builds + installslibalp_sdk.so+ the<alp/*>headers.recipes-ros/alp-perception/alp-perception_0.5.bb-- builds
the v2n-m1-ros-perception ROS 2 node fromexamples/v2n/.recipes-deepx/dx-rt/dx-rt_2.4.bb-- pins DEEPX runtime +
kernel module to v2.4.0; V2N base machines get a stub.recipes-images/alp-image-edge.bb-- reference edge AI
image bundling alp-sdk + dx-rt + ROS 2 + the perception node.
examples/drone-autopilot/src/mavlink.{c,h}-- minimal MAVLink
v2 stack (no upstreamc_library_v2dependency). Pack/parse
for HEARTBEAT / ATTITUDE / GPS_RAW_INT / GLOBAL_POSITION_INT /
BATTERY_STATUS / RC_CHANNELS outbound; HEARTBEAT + COMMAND_LONG
(arm/disarm + mode set) inbound. Wired intomain.cas two
threads (mav_tx@ 10 Hz,mav_rxbyte-driven, both priority
5). Customers drop in the upstream c_library_v2 when they need
the full message dialect -- symbol prefixes don't collide
(alp_mavlink_*vsmavlink_*). CRC-X.25 + per-message CRC
extras hard-coded for the 7 message types we touch.
Added (2026-05-14 -- twister scenarios for the 6 LVGL + application demos)
Each of the new demo examples got a testcase.yaml registering
it with twister + matching tags so the demos build on every push:
lvgl-widgets-demo,lvgl-benchmark,lvgl-music-player--
tagslvgl demo example(+benchmark performance/audio codecper demo).drone-hud-- tagslvgl demo example marketing showcase drone uav.iot-dashboard-- tagslvgl iot mqtt tls demo example.ai-camera-viewer-- tagslvgl ai inference demo example marketing showcase.
Two scenarios per demo:
*.native_sim--platform_allow: native_sim/native/64,build_only: true(LVGL needs an SDL2 host runtime; twister
build-only is enough for v0.5).*.aen--platform_allow: alif_e7_dk_rtss_hp,build_only: true(no EVK runner online; v0.6 HiL fills in
the flash-and-run path).
LVGL upstream demos/widgets/ + demos/benchmark/ + demos/music/
sources are already pulled in via the existingname-allowlist: - lvgl line in west.yml -- no west.yml change
needed.
Added (2026-05-14 -- §D.lib.loader: extras-tier1 CI pin-check workflow + baseline SW-fallback emission)
Two follow-ups so the §D.lib batch is fully self-validating:
-
.github/workflows/nightly-extras-tier1-pins.yml(new) --
nightly + PR-on-touch + manual workflow that runswest update --group-filter +extras-tier1and asserts each
pinned library directory undermodules/lib/ends up populated.- 9 stable pins (u8g2, libcoap, tinygsm, libwebsockets, jsmn,
opus, Catch2, libmodbus, coreMQTT-SN) -- pin breakage FAILS
the workflow. - 4 TBD pins (minimp3, libhelix, bearssl, madgwick_ahrs) --
warn-only until the maintainer locks specific SHAs.
Audit artefact uploaded with the first line of each fetched
library's README so reviewers can eyeball "did this land the
right repo?".
- 9 stable pins (u8g2, libcoap, tinygsm, libwebsockets, jsmn,
-
Baseline library SW-fallback emission -- the 4 pre-existing
Tier 1 libraries with HW bindings (lvgl / mbedtls / cmsis_dsp /
littlefs) now emit their matchingCONFIG_ALP_<LIB>_<FALLBACK>=y
line inalp.confalongside the upstream Zephyr-module knob:lvgl→CONFIG_LVGL=y+CONFIG_ALP_LVGL_SW_BLIT=ymbedtls→CONFIG_MBEDTLS=y+CONFIG_MBEDTLS_BUILTIN=y+CONFIG_ALP_MBEDTLS_PURE_C=ycmsis_dsp→CONFIG_CMSIS_DSP=y+CONFIG_ALP_CMSIS_DSP_SCALAR=ylittlefs→CONFIG_FILE_SYSTEM_LITTLEFS=y+CONFIG_FILE_SYSTEM=y+CONFIG_ALP_LITTLEFS_SYNC_IO=y
Redundant withKconfig.alp-libraries'default yon those
symbols, but documents the fallback choice next to the
library-enable line in the emitted alp.conf.
TestHwBackendsLoader.test_sw_fallback_always_emitted extended
from 8 to 12 assertions to lock the four new emissions in.
Added (2026-05-14 -- §D.lib.loader: native_sim twister scenario for library knobs)
tests/zephyr/library_knobs/ -- new twister test scenario that
exercises the alp.conf → Kconfig → Zephyr build chain end-to-end
for the §D.lib library set on native_sim/native/64. Three
on-purpose checks:
- mbedtls links -- includes
mbedtls/version.h+ assertsMBEDTLS_VERSION_NUMBER != 0andmbedtls_version_get_string
resolves. CatchesCONFIG_MBEDTLS=yemission breakage that
the existing alp_project.py Python tests can't see (those
only check the emitted CONFIG_*=y lines, not whether they
produce a buildable Zephyr image). - cmsis_dsp links -- includes
arm_math.h+ callsarm_copy_f32(...). Confirms CMSIS-DSP's symbol surface
resolves at link time. - §D.lib SW-fallback knobs reachable from Kconfig -- compile-
time check counts 21CONFIG_ALP_<LIB>_<FALLBACK>=yknobs
declared inzephyr/Kconfig.alp-librariesand asserts each
one is defined. Catches a brokenrsource "Kconfig.alp-libraries"
line inzephyr/Kconfig(the most likely v0.6 regression).
Test registers with twister under tag library_knobs.smoke;
runs on every push that touches metadata/library-profiles/,zephyr/Kconfig.alp-libraries, or scripts/alp_project.py.
extras-tier1-only libraries (u8g2, opus, libcoap, libwebsockets,
...) are NOT exercised here because their west pin is disabled
by default; a follow-up workflow that flips--group-filter +extras-tier1 will cover them once those pins
stabilise from # TBD: pin SHA to specific revisions.
Added (2026-05-14 -- §D.lib.loader: unit tests + west.yml extras-tier1 group)
Two follow-ups so the §D.lib batch + loader stay regression-safe
and the libraries we don't currently ship under Zephyr's tree
have a pinned consumption path.
Loader unit tests -- new TestHwBackendsLoader class intests/scripts/test_alp_project.py (9 tests). For each SoM SKU
(AEN301, AEN401, AEN601, AEN801, V2N101, V2M101, NX9101) +
12 libraries, asserts the expected CONFIG_ALP_*=y emission set.
Locks in the per-SKU wiring -- any future metadata change (new
SoM cap, silicon family, library) that drops or duplicates a
binding fails CI at the per-priority-match level, not at twister.
Cases covered:
- E3 emits U55 only, never U85.
- E4 emits BOTH U85 (primary) + U55 (secondary) driver shims.
- E6 emits LVGL_GPU2D + GFX_COMPAT_GPU2D (gpu2d cap present).
- E8 routes LITTLEFS_XSPI_DMA through the hexspi_dma cap path.
- V2N101 emits DRP_AI + NEON + CAU + EMMC_DMA; nothing AEN-specific.
- NX9101 emits ETHOS_U65 + N93 driver shim.
- OPTIGA cross-family: fires on NX9101 where no higher-priority
crypto wins, suppressed on AEN401 by CryptoCell. - Unconditional DMA fallbacks (TFLM_DMA_COPY, MINIMP3_I2S_DMA)
always emit. - SW-fallback knobs for §D.lib libraries always emit.
extras-tier1 west.yml group -- 13 upstream pins for the
Tier 1 libraries that aren't already in Zephyr's modules tree:
u8g2 (v2.36.5), libcoap (v4.3.5), TinyGSM (v0.11.7),
libwebsockets (v4.3.4), jsmn (v1.1.0), opus (v1.5.2),
Catch2 (v3.7.1), libmodbus (v3.1.10), coreMQTT-SN (v1.0.1).
Pinned to main/master with # TBD: pin SHA after maintainer audit for upstreams that have no semver releases (minimp3,
libhelix) or are tarball-only (bearssl uses the community
mirror at github.com/bearsslmirror/BearSSL; madgwick_ahrs
uses x-io Technologies' Fusion successor library).
gfx_compat is maintainer-written and ships in-tree -- no west
pin needed. tflite-micro and nanopb already live in Zephyr's
own west.yml; allowlisted in our import filter.
The extras-tier1 group is disabled by default
(-extras-tier1 in group-filter:), so v0.5 workspaces stay
light. Customers flip via west update --group-filter +extras-tier1 when their board.yaml libraries: lists any
of these libraries.
Added (2026-05-14 -- §D.lib.loader: requires_cap matcher + capability-keyed bindings audit)
Phase 2b's loader grew a requires_cap: matcher so library
priority entries can key off the per-SoM capabilities: block
directly, rather than the family-coarse soc_family: token.
Three concrete wins:
- Cross-family bindings collapse to one entry.
optiga_trust_m
is populated on AEN + V2N + NX9101 SKUs. Old form needed
three priority entries (one per family); new form is onerequires_cap: optiga_trust_m. - Sub-family bindings stop over-firing.
gpu2dis on E6 /
E7 / E8 but not E3 / E4 / E5.soc_family: alif_ensemblefired
on every Ensemble SKU;requires_cap: gpu2donly fires where
the silicon actually carries it. - NPU population gets surgical. Numeric caps
(ethos_u55_count,ethos_u85_count,ethos_u65_count) are
treated as truthy when > 0 --requires_cap: ethos_u85_count
handles "this SKU has at least one U85" directly.
Loader (scripts/alp_project.py::_emit_library_hw_backends) now
parses the SKU's capabilities: block (line-driven, no PyYAML
dep) and exposes a _cap_truthy() helper that handles booleans +
numeric counts. Per-priority match: all specified keys
(silicon: / soc_family: / requires_cap:) must match; any
omitted key is wildcarded.
Library hw-backends.yaml rewrite (capability-keyed where it beats
soc_family): tflite_micro / lvgl / mbedtls / cmsis_dsp / littlefs /
bearssl / madgwick_ahrs / u8g2 / gfx_compat / minimp3 / opus.
Notable: tflite_micro grew an ethos_u65_count entry so NX9101
emits CONFIG_ALP_TFLM_ETHOS_U65=y; littlefs now resolves E8's
HexSPI separately from E3..E7's OctalSPI (both share theCONFIG_ALP_LITTLEFS_XSPI_DMA=y driver shim).
New Kconfig knob: ALP_TFLM_ETHOS_U65 (depends on
ALP_SOC_NXP_IMX9_IMX93). The legacy preferred_backend: ethos_u
code path in scripts/alp_project.py also emits it alongsideCONFIG_ALP_SDK_INFERENCE_ETHOS_U_N93=y for the N93 driver shim.
include/alp/inference.h ALP_INFERENCE_BACKEND_ETHOS_U enum doc
enumerates all three U55 / U65 / U85 variants explicitly.
Cross-SKU smoke-test (driver dump per SKU):
- AEN401 (E4): U85 primary + U55 secondary + HELIUM + DMA_COPY +
LVGL_DMA2D + MBEDTLS_CRYPTOCELL + LITTLEFS_XSPI_DMA +
BEARSSL_CRYPTOCELL. - AEN601 (E6): same + LVGL_GPU2D + MADGWICK_FPU + MINIMP3_HELIUM +
OPUS_HELIUM. - AEN801 (E8): same as AEN601 but HexSPI resolves the
LITTLEFS_XSPI_DMA gate. - V2N101: DRP_AI + NEON; LVGL_TMU; MBEDTLS_CAU; LITTLEFS_EMMC_DMA.
- NX9101: ETHOS_U65 + NEON; MBEDTLS_OPTIGA; LITTLEFS_EMMC_DMA.
Added (2026-05-14 -- §D.lib.loader: per-SoM capabilities blocks + baseline hw-backends + ml_npu split)
Three audit follow-ups in one batch, after the user pointed out
that E4 / E6 / E8 actually carry TWO Ethos-U55s alongside the
single Ethos-U85 -- the NPU population is U55-HE (paired with
M55-HE) + U55-HP (paired with M55-HP) + U85-HG (Hyper-Generative,
Transformer-capable):
-
tflite_micro/hw-backends.yamlml_npu split -- singleml_npuclass restructured intoml_npu_primary+ml_npu_secondary. On E4 / E6 / E8 the primary emitsCONFIG_ALP_TFLM_ETHOS_U85=yand the secondary emitsCONFIG_ALP_TFLM_ETHOS_U55=y, so BOTH driver shims now
link. On E3 / E5 / E7 only the primary fires (U55-only). -
Baseline-library hw-backends.yaml fill-in -- the
pre-existing 4 libraries with HW bindings (lvgl, mbedtls,
cmsis_dsp, littlefs) gained their own hw-backends.yaml. Now
every Tier 1 library either ships a profile or has a
documented "pure-SW only" status. Matching Kconfig knobs
added toKconfig.alp-libraries:ALP_LVGL_GPU2D/_DAVE2D/_TMU/_DMA2D/_SW_BLITALP_MBEDTLS_CRYPTOCELL/_INLINE_AES/_CAU/_OPTIGA
/_PURE_CALP_CMSIS_DSP_HELIUM/_NEON/_TMU_CORDIC/_TMU_FFT
/_ADC_DMA/_SCALARALP_LITTLEFS_XSPI_DMA/_EMMC_DMA/_QSPI_DMA/_SYNC_IO
-
Per-SoM
capabilities:blocks -- new top-level section
in everymetadata/e1m_modules/E1M-*.yamldeclares the
accelerator population per SKU. Field shape:ethos_u55_count: <int>/ethos_u85_count: <int>/ethos_u65_count: <int>for NPU counts; booleans for the
remaining accelerators (drp_ai / deepx_dx / helium_mve /
neon / gpu2d / dave2d / cryptocell / inline_aes / cau /
optiga_trust_m / xspi_dma / emmc_dma / quadspi_dma / dma2d /
tmu_cordic / tmu_fft / tmu_fac).
Populated for AEN301 / AEN401 / AEN501 / AEN601 / AEN701 /
AEN801 / V2N101 / V2N102 / V2M101 / V2M102 / NX9101 -- every
SoM SKU in the registry. Per the "Pending exact HW
configurations" rule, items not yet datasheet-verified (E3
GPU2D presence, E4 DAVE2D presence) are explicitly markedfalse+# TBD.in a trailing comment so the maintainer
can flip them once the SoM BOM finalises. -
npu_population:lists -- alongsideethos_u_variants:,
each AEN SKU now declares the full NPU population as a list
of named instances withrole:+paired_with:tags
(NPU-HE / M55-HE, NPU-HP / M55-HP, NPU-HG / HG-subsystem).
Matches the Alif Ensemble block diagram in the datasheet.
The loader (scripts/alp_project.py) still picks matches viasilicon: / soc_family: -- the new capabilities: block is
declarative now, available for a future requires_cap: key in
hw-backends.yaml.
Fixed (2026-05-14 -- §D.lib.loader follow-up: Ethos-U85 propagated through every consumer)
Phase 2b's per-NPU split landed in the new tflite_micro library-
profile loader but didn't propagate to the existing inference
dispatcher path or the SoM-preset metadata. This commit closes
those gaps so every layer reflects the U85 / U55 / U65 split:
-
scripts/alp_project.py: the legacypreferred_backend: ethos_u
path now emits the per-NPU driver Kconfigs alongside the legacy
dispatcher gate. Siliconalif:ensemble:e4 | e6 | e8
→CONFIG_ALP_TFLM_ETHOS_U85=y+CONFIG_ALP_TFLM_ETHOS_U55=y.
Other Alif Ensemble SKUs (E3 / E5 / E7) →CONFIG_ALP_TFLM_ETHOS_U55=y
only.nxp:imx9:imx93→CONFIG_ALP_SDK_INFERENCE_ETHOS_U_N93=y
(unchanged).CONFIG_ALP_SDK_INFERENCE_ETHOS_U=ystays as the
customer-facing dispatcher gate. -
metadata/e1m_modules/E1M-AEN*.yaml: newethos_u_variants:
list captures the full NPU population per SKU. AEN401 / AEN601 /
AEN801 now declare[u85, u55]; the others stay[u55]. The
singularethos_u_variant:field promotes to the primary
(U85 on the U85-bearing SKUs). -
include/alp/inference.h:ALP_INFERENCE_BACKEND_ETHOS_Uenum
doc enumerates the three variants the token covers (U85 / U65 /
U55) + the per-SKU loader behaviour. Public ABI stays generic. -
src/zephyr/inference_tflm.cpp: file-header comment generalised
from "U55 + U65" to "U55 + U65 + U85" with the per-Kconfig matrix. -
README.mdinference-dispatcher row: notes the U55 / U85 / U65
coverage.
Fixed (2026-05-14 -- §D.lib.loader: Ethos-U85 vs U55 differentiation for tflite_micro)
§D.lib batch collapsed both Alif NPUs (Ethos-U55 + Ethos-U85) under
a single ethos_u backend. In silicon they are two different IPs:
- Ethos-U55: on every Ensemble SKU (E3, E4, E5, E6, E7, E8) -- two
instances per SoC. - Ethos-U85: on E4, E6, E8 only -- one instance per SoC, Transformer-
capable, the Generative-AI forward path.
The loader and the tflite_micro hw-backends.yaml now distinguish
the two:
scripts/alp_project.py::_emit_library_hw_backendslearns asilicon:matcher (in addition tosoc_family:). When a
priority entry setssilicon: alif:ensemble:e4, the loader only
emits it on the SKU whosesilicon:field inmetadata/e1m_modules/<sku>.yamlmatches exactly.metadata/library-profiles/tflite_micro/hw-backends.yamlnow
declares three U85 entries (E4 / E6 / E8) as priority 1, then a
family-wide U55 entry for the remaining SKUs. Result on an
AEN401 / AEN601 / AEN801 board:CONFIG_ALP_TFLM_ETHOS_U85=y
emitted. On AEN301 / AEN501 / AEN701:CONFIG_ALP_TFLM_ETHOS_U55=y.zephyr/Kconfig.alp-librariessplits the oldALP_TFLM_ETHOS_U
symbol intoALP_TFLM_ETHOS_U85(depends on E4 || E6 || E8) +ALP_TFLM_ETHOS_U55(depends on any E* SoC).
Other libraries (cmsis_dsp / minimp3 / opus) only bind to Helium
MVE on the M55 cores, which every E SoC ships -- no per-silicon
split needed there.
Changed (2026-05-14 -- §D.closeout: v1.0-readiness + README + test-coverage closeout)
Phase 5 (closeout) of the chip-and-library ecosystem expansion per
docs/superpowers/specs/2026-05-14-chip-and-library-ecosystem-design.md.
docs/v1.0-readiness.md: new Pillar 4-bis section declaring the
three-tier ecosystem in operation (Tier 1 = 80 chips + 25 libs;
Tier 2 inalp-sdk-community= skeleton + 10 seed chips;
Tier 3 = customer / private repos via pattern-only support).README.md: chip-count bump 20+ → 80 + Tier 2 pointer.docs/test-coverage-audit.md: chips/ row file count 108 → 254,
driver count 21 → 80; notes the [UNTESTED] badge convention.
Total v0.5 §D-batch delivery:
- 49 new Tier 1 chip drivers (§D.AI 18, §D.industrial 18, §D.iot 9,
§D.audio 6) - 17 new Tier 1 library knobs + per-library hw-backends.yaml
- §D.lib.loader cross-library HW-backend loader + Kconfig.alp-libraries
- alp-sdk-community public repo + skeleton + 10 seed contributions
Added (2026-05-14 -- §D.community: Tier 2 contribution surfaces in alp-sdk)
Phase 3 of the chip-and-library ecosystem expansion per
docs/superpowers/specs/2026-05-14-chip-and-library-ecosystem-design.md.
alp-sdk-side artefacts that pair with the new alplabai/alp-sdk-
community repo (created separately):
metadata/schemas/contribution-v1.schema.json(new) -- JSON Schema
that every Tier 2 contribution'smetadata.yamlvalidates against
on PR. Permits Apache-2.0 / MIT / BSD only (GPL rejected bypr-lint); enforcesname:matches the parent directory; pins
thefamily:enum (sensor / display / camera / motor / encoder /
audio / power / cellular / lora / wifi / ble / gnss / crypto /
memory / io_expander / serdes / switch / graphics / ml / control /
iot / networking / parsing / serialization / testing / other);
pinsinterfaces:enum (i2c / spi / uart / i2s / pwm / gpio /
can / adc / dac / rtc / watchdog / usb / ethernet / mipi_csi2 /
dvp / fpd_link / gmsl / pcie / gpio_bitbang / gpio_pwm).docs/contributing-tier-2.md(new) -- customer-facing
walkthrough of the three-tier model + per-contribution
checklist + the three integration patterns (pull-everything /
per-contribution selection / search-then-clone) + the
"Verified" → Tier-1 promotion path.
The alplabai/alp-sdk-community repo + its skeleton (registry.yaml,
west.yml, templates/, .github/workflows/, CODEOWNERS) lives in a
separate commit on that repo's main branch.
Added (2026-05-14 -- §D.lib.loader: cross-library HW-backend loader hook)
Phase 2b of the chip-and-library ecosystem expansion. Adds the
loader hook that picks the highest-priority HW backend per
(library × accelerator class) from each enabled library'smetadata/library-profiles/<name>/hw-backends.yaml, cross-
referencing the active SoM family.
scripts/alp_project.pygrows_emit_library_hw_backends()
(~70 LoC) — runs after the SW-fallback emission and walks each
library's priority list, emitting the first matching backend per
accelerator class asCONFIG_*=y.zephyr/Kconfig.alp-libraries(~200 LoC, new file) declares every
per-library + per-backend Kconfig symbol the loader can emit.
Sourced fromzephyr/Kconfigviarsourceunder theALP_SDK
if-block. SW-fallback symbols defaulty; HW-acceleration
symbols default off and turn on only when the loader writes them.
NOT in this commit (deferred per the design spec): capabilities:
blocks in metadata/e1m_modules/E1M-*.yaml. Loader currently maps
SoM family directly from SKU; finer-grained per-SoM capability
flags (has_ethos_u: true, has_dave2d: true, ...) belong to the
maintainer per the "Pending exact HW configurations" rule.
Added (2026-05-14 -- §D.lib: 17 library knobs + per-library hw-backends)
Phase 2 of the chip-and-library ecosystem expansion per
docs/superpowers/specs/2026-05-14-chip-and-library-ecosystem-design.md.
17 new libraries available via board.yaml's libraries: enum
(was 8, now 25 -- on the v1.0 target). Each library ships:
- One
metadata/library-profiles/<name>/hw-backends.yamldeclaring
which accelerator classes (NPU / GPU / SIMD / DMA / crypto /
cordic / timing) it binds to per SoM family, with priority order- matching
CONFIG_*symbol. Pure-SW fallback required + always
available.
- matching
- An entry in
scripts/alp_project.py's_LIBRARY_KCONFIGtable
that emits the SW-fallbackCONFIG_*unconditionally. The
cross-library loader hook (§D.lib.loader, next commit) layers
the HW-backendCONFIG_*on top by cross-referencinghw-backends.yamlagainst the active SoM'scapabilities:
block inmetadata/soms/*.yaml. - An entry in
metadata/schemas/board-config-v1.schema.json'slibraries:enum so the schema validator accepts the new names.
Libraries by domain (§D.lib. tag):
- §D.lib.ai (3):
tflite_micro,u8g2,gfx_compat - §D.lib.industrial (3):
madgwick_ahrs,pid,modbus - §D.lib.iot (7):
coremqtt_sn,libcoap,tinygsm,nanopb,libwebsockets,jsmn,bearssl - §D.lib.audio (3):
minimp3,opus,libhelix - §D.lib.test (1):
catch2
Verification: every hw-backends.yaml carries verification: hil_silicon: untested / smoke_tests: build_only -- the wiring is
schema-validated but no per-(library × SoM-family) HiL bring-up
has been run yet.
west.yml pins for the libraries NOT already in Zephyr's modules
tree (u8g2, libcoap, tinygsm, libwebsockets, jsmn, bearssl,
minimp3, opus, libhelix, catch2, libmodbus, madgwick_ahrs,
coremqtt_sn, gfx_compat) are NOT in this commit -- they land in
a follow-up feat(west): extras-tier1 group once the maintainer
picks the per-library tagged revisions. Tier 1 libraries that
ARE already in Zephyr's west.yml (tflite_micro, nanopb)
flow through the existing name-allowlist filter.
Added (2026-05-14 -- §D.audio: 6 audio chip drivers)
Tier 1 ecosystem expansion -- Phase 1 §D.audio batch. All headers
carry the [ABI-EXPERIMENTAL] + [UNTESTED] badges.
ics_43434-- InvenSense ICS-43434 omnidirectional
MEMS mic (I2S, channel-binding helper).inmp441-- InvenSense INMP441 low-cost MEMS mic.wm8960-- Cirrus / Wolfson WM8960 stereo codec
(I2C config + I2S data; packed 9-bit register write).tlv320aic3204-- TI TLV320AIC3204 premium codec w/
miniDSP (page-paged I2C control surface).max98357a-- ADI MAX98357A 3 W mono class-D amp
(shutdown / mode-select pin control).es8388-- Everest Semi ES8388 stereo codec
(China-domestic; same shape as WM8960).
Audio sample path on these chips goes through the portable<alp/i2s.h> peripheral surface; the drivers above only own the
I2C control / GPIO power-rail surfaces and channel-binding helpers.
Fixed (2026-05-14 -- §D.iot ZTEST tests follow-up)
§D.iot ZTESTs were added in this commit as a follow-up — the
prior §D.iot commit (6fbb14a) landed the chip drivers +
Kconfig/CMake glue but the NULL-arg-guard ZTEST entries didn't
make it in due to an Edit-mismatch on the test file. Captured
here so the audit trail stays clean.
Added (2026-05-14 -- §D.iot: 9 IoT / connectivity chip drivers)
Tier 1 ecosystem expansion -- Phase 1 §D.iot batch. Every public
header in this batch carries the [ABI-EXPERIMENTAL] + [UNTESTED]
badges. The chip headers added in this batch + the prior §D.AI +
§D.industrial batches are all tagged [UNTESTED] -- the verification
badge captures the v0.5 truth: drivers compile + pass the NULL-arg
ZTESTs but have no HiL silicon bring-up yet, so customers should
treat all timing / register-value / lifecycle sequencing as paper-
correct only until the v1.0 verification sweep lands.
quectel_bg95-- Quectel LTE-M / NB-IoT / EGPRS module
(UART AT shell + PWRKEY pulse).quectel_bg77-- Quectel LTE-M / NB-IoT module with
integrated GNSS.ublox_sara_r5-- u-blox LTE-M carrier-certified module
(1500 ms PWR_ON pulse).semtech_sx1262-- Semtech SX1262 LoRa / FSK transceiver
(opcode shell + BUSY-wait + GetStatus probe).semtech_sx1276-- Semtech SX1276 legacy LoRa transceiver
(register R/W + REG_VERSION probe).ublox_neo_m9n-- u-blox NEO-M9N multi-constellation GNSS
(UART NMEA line read).ublox_max_m10s-- u-blox MAX-M10S small-footprint GNSS.atgm336h-- AllyStar ATGM336H cost-optimised GNSS.atecc608b-- Microchip ATECC608B EC P-256 + AES
secure element (wake / idle / sleep shell; ATCA crypto pending
CryptoAuthLib import).
Changed (2026-05-14 -- §D.AI + §D.industrial: [UNTESTED] verification badges)
Retro-fit @par Verification status: [UNTESTED] Doxygen tag onto
every chip header added in the §D.AI + §D.industrial batches earlier
in this run, plus a matching verification: { hil_silicon: untested, smoke_tests: null_arg_guard } block in each chip's metadata YAML.
Customer-visible signal that the v0.5 drivers compile + pass the
NULL-arg ZTEST surface but have not yet seen HiL silicon bring-up.
Added (2026-05-14 -- §D.industrial: 18 industrial sensing / control chip drivers)
Tier 1 ecosystem expansion -- chip-and-library-ecosystem-design.md
Phase 1 §D.industrial batch. Drivers ship with Doxygen-clean public
headers in include/alp/chips/<name>.h, implementations underchips/<name>/, metadata YAML, Kconfig / CMakeLists / alp_project.py
hooks, and per-chip NULL-arg-guard ZTESTs.
bmp390-- Bosch BMP390 high-precision pressure sensor (I2C).ms5611-- TE MS5611 drone-grade barometer (I2C; PROM
read at init).lps22hb-- ST LPS22HB MEMS barometer (I2C).vl53l1x-- ST VL53L1X single-zone ToF ranger (I2C).vl53l5cx-- ST VL53L5CX 8x8 multi-zone ToF ranger (I2C).a02yyuw-- DFRobot A02YYUW waterproof ultrasonic ranger
(UART; checksum-validated 4-byte distance frame).drv8833-- TI DRV8833 dual H-bridge brushed-DC driver
(PWM; signed pulse-width per channel, sleep gate).drv8825-- TI DRV8825 bipolar stepper (PWM step + GPIO
dir / microstep / nEnable).tmc2209-- Trinamic TMC2209 silent stepper driver
(UART register read / write with CRC-8/ATM).a4988-- Allegro A4988 stepper driver (PWM step + GPIO
dir / microstep / nEnable).as5048a_b-- ams AS5048B 14-bit magnetic encoder (I2C).mt6701-- MagnTek MT6701 14-bit magnetic encoder (I2C).hx711-- Avia Semi HX711 24-bit load-cell ADC
(bit-banged 2-wire, 128 / 64 / 32 gain).max31855-- ADI MAX31855 K-type thermocouple-to-digital
(SPI; signed milli-C decode + fault flags).max31865-- ADI MAX31865 PT100 / PT1000 RTD-to-digital
(SPI; 15-bit ratio + fault bit).tsl2591-- ams TSL2591 wide-dynamic-range light sensor
(I2C; visible + IR channels).qmc5883l-- QST QMC5883L 3-axis compass (I2C; continuous
mode at 200 Hz / 2 G / OSR 512).veml7700-- Vishay VEML7700 ALS (I2C; 16-bit count read).
Validators clean before push:
- scripts/validate_metadata.py
- scripts/check_example_portability.py
- scripts/check_pin_conflicts.py
- scripts/abi_snapshot.py --diff docs/abi/v0.5-snapshot.json
Added (2026-05-14 -- §D.AI: 18 vision / display / accelerator chip drivers)
Tier 1 ecosystem expansion -- chip-and-library-ecosystem-design.md
Phase 1 §D.AI batch. All drivers ship with a Doxygen-clean public
header in include/alp/chips/<name>.h, implementation underchips/<name>/<name>.c, metadata at metadata/chips/<name>.yaml,
Zephyr Kconfig + CMakeLists glue, and a NULL-arg-guard ZTEST undertests/zephyr/chips/src/main.c. Driver bodies follow the[stub-impl] pattern: chip-ID + soft-reset + lifecycle is real;
vendor-specific register tables (camera resolution / pixel format
profiles, e-paper waveform LUTs) land in follow-up commits once the
maintainer adds the reference init scripts to the internal design
archive. All public symbols are tagged [ABI-EXPERIMENTAL] until
the first SoM verification.
ov2640-- OmniVision 2 MP UXGA DVP camera (ESP32-CAM default).ov5645-- OmniVision 5 MP MIPI CSI-2 camera.ov7670-- OmniVision VGA DVP camera (reference classic).ov9281-- OmniVision 1 MP global-shutter mono MIPI CSI-2
(AR/VR / ALPR / industrial tracking).ar0234-- onsemi 1080p global-shutter colour MIPI CSI-2.imx219-- Sony 8 MP MIPI CSI-2 (RPi Cam v2 standard).imx477-- Sony 12.3 MP MIPI CSI-2 (RPi HQ Camera).gc2145-- GalaxyCore 2 MP cost-sensitive DVP camera.ti_ds90ub953_954-- TI FPD-Link III camera SerDes pair
(long-cable industrial machine vision).maxim_max9295_9296-- ADI (Maxim) GMSL2 6 Gbps automotive
camera SerDes pair.st7789-- Sitronix ST7789V 240x240 / 240x320 IPS TFT
(init + window + write-pixels).ili9341-- Ilitek ILI9341 240x320 SPI TFT.ili9488-- Ilitek ILI9488 320x480 SPI TFT.ra8875-- RAiO RA8875 5-7" LCD controller + resistive
touch (SPI; register-level access + soft reset).sh1106-- Sino Wealth SH1106 128x64 monochrome OLED (I2C;
drop-in alternative to SSD1306, accounts for 132-column RAM
offset). Driver runs full lifecycle including frame push.il3820-- Solomon IL3820 4.2" tri-colour e-paper (SPI;
init + busy-wait + soft reset; waveform LUT pending).gdew0154t8-- GoodDisplay GDEW0154T8 1.54" monochrome
e-paper (SPI; same lifecycle shape asil3820).hailo_8l-- Hailo-8L 13 TOPS NPU host-side bring-up
driver for the M.2 PCIe form factor (host RESETB sequence +
WAKE# read; PCIe enumeration + HailoRT runtime live on the
Linux side).
Validators that ran clean on this batch (each before push):validate_metadata.py / check_example_portability.py /check_pin_conflicts.py / abi_snapshot.py --diff docs/abi/v0.5-snapshot.json.
Added (2026-05-14 -- V2N DEEPX rail GPIO map)
DEEPX_PWR_EN_REQ(P65) +DEEPX_CORE_0P75_EN(P64) added
tometadata/e1m_modules/v2n/renesas-peripheral-map.{tsv,csv}.
P65 is the rising-edge "DEEPX should come up now" signal from
the primary PMIC into V2N; P64 is V2N's drive to the DA9292
EN2 pin (and other shared-rail consumers) that physically
enables the 0.75 V DEEPX rail. Sequence captured in
[memoryproject_v2n_da9292_core_0p75_control.md]. V2N
firmware module (src/zephyr/v2n_power_mgmt.c) wiring lands
next.
Changed (2026-05-14 -- top-level UX simplification cont.)
docs/ota-device-contract.mdcross-ref tonotes/morning-handoff-2026-05-13.mdremoved. Thenotes/
directory is gitignored (maintainer handoff drafts that are
not part of the public SDK); a doc line that referenced a
non-tracked file was dead-link bait for anyone cloning the
public repo. Removed; the "Open questions" stand on their
own.tools/program_eeprom.pymoved toscripts/program_eeprom.py.
Thetools/directory only held one script (the EEPROM
manifest packer);scripts/already hosts 13 similar Python
utilities (abi_snapshot.py,validate_metadata.py,validate_board_yaml.py,check_pin_conflicts.py, etc.).
Folding the single-file directory intoscripts/removes one
top-level entry and makes the "Alp SDK has one place for
helper scripts" rule unambiguous. Files touched:README.md,docs/board-id.md,docs/bring-up-v2n.md,docs/getting-started.md,docs/test-plan.md,docs/troubleshooting.md,examples/v2n/v2n-board-id-readout/README.md,examples/v2n/v2n-eeprom-manifest-dump/README.md,include/alp/hw_info.h,src/zephyr/hw_info_zephyr.c,tests/fuzz/eeprom_manifest_fuzz.c,tests/scripts/test_program_eeprom.py, plus the script's own
self-reference docstring. Staletools/__pycache__/
directory (the only remaining content after the move, and
untracked) deleted to fully remove the top-level entry.
Historicaltools/mentions in thisCHANGELOG.mdleft
untouched.dts/bindings/moved tozephyr/dts/bindings/. Zephyr
devicetree bindings are Zephyr-only artefacts and belong under
thezephyr/module subtree alongsidezephyr/Kconfig/zephyr/CMakeLists.txt/zephyr/module.yml. Folding them
in removes the top-leveldts/directory.zephyr/module.ymlupdated withdts_root: zephyrso
Zephyr's binding scanner finds them at the new location (the
default<module-root>/dts/bindings/no longer applies).
Two binding files moved verbatim:alp,pin-array.yaml,vendor-prefixes.txt. Comment update
insrc/zephyr/peripheral_gpio.c. Top-leveldts/
directory deleted.sysbuild/aen/moved tozephyr/sysbuild/aen/. Sysbuild
configs are Zephyr-only artefacts (MCUboot + ECDSA-P256
secure-boot profile for AEN-Zephyr applications); folding them
under the Zephyr module subtree means the top-level repo only
shows directories that are OS-agnostic or OS-router
(chips/,examples/,src/, etc.) -- Zephyr-specific
artefacts cluster underzephyr/. Files touched:VERSIONS.md,docs/adr/0006-secure-boot-secure-ota.md,docs/secure-boot.md,docs/test-plan.md,keys/README.md,keys/generate_dev_key.sh, plus the moved README +
sysbuild.conf internal self-refs. Top-levelsysbuild/
directory deleted (no longer holds any siblings).examples/README.mdaudit. After the §A.6 SoM-subfolder
refactor (examples/v2n/v2n-*andexamples/aen/*), the
cross-family table still listededgeai-vision-aenas if it
lived at the top level, and the V2N-specific table used bare
directory names (v2n-gd32-bridge-ping) instead of thev2n/v2n-gd32-bridge-pingpaths that actually exist on disk.
Split into three sections (cross-family / AEN-specific /
V2N-M1-specific) with correct relative paths for every row.
Added (2026-05-14 -- peripheral thin-spot test fills §C.22)
Closes the §1c "thin-spot fills" carry-forward from the
readiness doc.