Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
---
title: Deploy Silero VAD on Alif Ensemble E8 with ExecuTorch
description: Export a stateful Silero voice activity detector, build its Zephyr firmware for the Alif E8, and compare recorded-audio probabilities with a host reference.
minutes_to_complete: 120
draft: true
cascade:
draft: true
who_is_this_for: This Learning Path is for embedded ML developers porting streaming audio inference to the Cortex-M55 HP core and Ethos-U85-256 on an Alif Ensemble E8.
learning_objectives:
- Explain the waveform context and recurrent state retained between Silero VAD invocations
- Export a quantized Ethos-U85 program and matching speech-probability reference using released Python packages
- Build E8 Zephyr firmware with the model, recorded audio, and required CPU operators
- Program the E8 and compare all 79 frame probabilities with the host reference
prerequisites:
- An [Alif Ensemble E8 Development Kit](https://alifsemi.com/support/kits/ensemble-e8devkit/) and a data-capable USB cable
- An Apple silicon Mac with Python 3.12, Git, CMake, Ninja, ripgrep, and a C++ build toolchain
- Access to the E8 application UART4 console through PRG USB and the board’s SW4 selector; no separate USB-to-UART adapter is required
- Zephyr SDK 0.17.0, Alif Security Toolkit for your silicon revision, and SEGGER J-Link
- Experience with PyTorch model export, C++, and Zephyr builds
author: Usamah Zaheer
generate_summary_faq: false
rerun_summary: false
rerun_faqs: false
skilllevels: Advanced
subjects: ML
armips:
- Ethos-U
tools_software_languages:
- ExecuTorch
- PyTorch
- Zephyr
- Python
- CMake
operatingsystems:
- macOS
- RTOS
further_reading:
- resource:
title: Deploy Silero VAD on Arm Ethos-U with ExecuTorch
link: /learning-paths/embedded-and-microcontrollers/silero-vad-ethos-u/
type: documentation
- resource:
title: Set up the Alif Ensemble E8 board
link: /learning-paths/embedded-and-microcontrollers/alif-image-classification/board-setup/
type: documentation
- resource:
title: Alif Ensemble E8 DevKit support
link: https://alifsemi.com/support/kits/ensemble-e8devkit/
type: website
- resource:
title: ExecuTorch Silero VAD export and runtime source
link: https://github.com/pytorch/executorch/tree/12dac4aa042b66a7229e8d7d3af2bdde8c9f262f/examples/arm/silero_vad_example_ethos_u
type: repository
- resource:
title: Silero VAD project
link: https://github.com/snakers4/silero-vad
type: repository

### FIXED, DO NOT MODIFY
# ================================================================================
weight: 1
layout: learningpathall
learning_path_main_page: "yes"
---
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
# ================================================================================
# FIXED, DO NOT MODIFY THIS FILE
# ================================================================================
weight: 21 # The weight controls the order of the pages. _index.md always has weight 1.
title: "Next Steps" # Always the same, html page title.
layout: "learningpathall" # All files under learning paths have this same wrapper for Hugo processing.
---
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---
title: Build the E8 Zephyr firmware
description: Embed the exported model and recording, link the CPU operators and Ethos-U delegate, and inspect the HP firmware memory use.
weight: 5
layout: learningpathall
---

## Inspect the application configuration

The application in `zephyr/samples/silero-vad-ethosu` runs once over the embedded recording. It loads `forward` once and preserves that method's recurrent state for every window. Resetting the board starts an independent stream.

The board-specific files select the HP Ethos-U85-256, enable its clock, and assign application SRAM beginning at `0x020C0000` with size `0x740000` bytes. This is a 7.25 MiB application region for the pinned E8 memory map. It is not portable to another board or a concurrently running application that owns the same SRAM.

The starting allocation capacities are:

| Allocation | Capacity or source |
| --- | --- |
| Method and planned buffers | 2 MiB static allocator pool |
| Temporary delegate allocations | 1 MiB static allocator pool |
| PTE copy | Exported PTE size, aligned to 16 bytes in SRAM |
| C/C++ heap | 64 KiB |
| Main stack | 16 KiB |
| Audio | Up to 40,000 normalized float32 samples generated from the PCM16 WAV |

These are configured capacities, not measurements of model demand. The generated audio array occupies 160,000 bytes for this clip. The PTE and audio begin in the firmware image; startup copies the PTE once to SRAM for NPU access. The linker report checks the static allocation footprint. A completed board run is still needed to verify allocator demand and NPU access.

## Build for the HP core

Keep the released Python environment active. Build with absolute paths to the exact PTE and WAV from the previous lesson:

```bash
cd "$EXECUTORCH_ROOT"
west build \
-b alif_e8_dk/ae822fa0e5597xx0/rtss_hp \
zephyr/samples/silero-vad-ethosu \
-d "$SILERO_BUILD" -- \
-DZEPHYR_EXTRA_MODULES="$EXECUTORCH_ROOT;$SDK_ALIF" \
-DPython3_EXECUTABLE="$(command -v python)" \
-DET_PTE_FILE_PATH="$SILERO_OUTPUT/silero_vad_ethos_u.pte" \
-DAUDIO_PATH="$SILERO_OUTPUT/validation.wav"
```

The CMake application generates the model/audio headers and selects portable CPU operators from the PTE. It links those registrations, the quantized kernels, and the Ethos-U backend into the firmware. The app also rejects inputs that do not match the single float32 `[1,576]` audio tensor and single float32 probability output.

If you change the board, PTE, WAV, or allocation configuration, rebuild in a new directory or use `west build -p always` with the complete command. This avoids keeping headers or operator selections from an earlier model.

## Check the firmware and memory placement

Require the ELF and binary, then inspect the generated target and allocator configuration:

```bash
test -s "$SILERO_BUILD/zephyr/zephyr.elf"
test -s "$SILERO_BUILD/zephyr/zephyr.bin"
rg 'CONFIG_(RTSS_HP|ARM_ETHOS_U85_256|EXECUTORCH_.*ALLOCATOR_POOL_SIZE)=' \
"$SILERO_BUILD/zephyr/.config"
rg -n 'app_sram|020c0000|20c0000|ethosu' \
"$SILERO_BUILD/zephyr/zephyr.dts"
"$ZEPHYR_SDK_INSTALL_DIR/arm-zephyr-eabi/bin/arm-zephyr-eabi-size" \
"$SILERO_BUILD/zephyr/zephyr.elf"
```

Require the HP target and `CONFIG_ARM_ETHOS_U85_256=y`. Keep the memory-usage report printed by the linker and inspect `zephyr.map` if a region is close to its limit. The `.bss` includes allocator capacities and the PTE copy; unused space inside a pool is still reserved in the linked firmware.

Successful linking proves that the firmware fits the configured static regions. It does not prove that `load_method()` or the largest delegate allocation fits at runtime. The application prints its planned buffer sizes during startup and reports allocation or execution failures; retain those messages during validation.

The local cross-build with the pinned source, vendor modules, Zephyr SDK 0.17.0, and released Python environment passed. Its linker report is:

| Region | Used | Available | Utilization |
| --- | --- | --- | --- |
| Flash application partition | 830,084 bytes | 3,584 KiB | 22.62% |
| Application RAM | 3,597,440 bytes | 7,424 KiB | 47.32% |

The binary is linked at `0x80200000`, including the vendor flash load offset. These are cross-build results, not measurements from a running E8. Physical execution and probability agreement remain to be checked.

Record the firmware identity alongside the model inputs:

```bash
shasum -a 256 "$SILERO_BUILD/zephyr/zephyr.elf" \
"$SILERO_BUILD/zephyr/zephyr.bin" \
> "$SILERO_OUTPUT/firmware.sha256"
```

## What you've accomplished

You have built one firmware image containing the recorded clip, exported program, CPU kernels, and U85 delegate, and checked its configured memory placement. Next, program this matching image onto the E8 HP core.
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
---
title: Export the streaming VAD model
description: Quantize Silero VAD for Ethos-U85 and generate the recorded-audio reference used to check the E8 output.
weight: 4
layout: learningpathall
---

## Download the model and calibration audio

Use the model and recording from one pinned Silero VAD revision. Keep the upstream project's license with any redistributed model or audio. The application archive contains neither file.

Download both inputs into your output directory:

```bash
cd "$EXECUTORCH_ROOT"
curl --fail --location \
--output "$SILERO_OUTPUT/silero_vad.jit" \
https://raw.githubusercontent.com/snakers4/silero-vad/dbacf536adadf42210f37ae50fbaf75f6235b3cf/src/silero_vad/data/silero_vad.jit
curl --fail --location \
--output "$SILERO_OUTPUT/test.wav" \
https://raw.githubusercontent.com/snakers4/silero-vad/dbacf536adadf42210f37ae50fbaf75f6235b3cf/tests/data/test.wav
shasum -a 256 "$SILERO_OUTPUT/silero_vad.jit" "$SILERO_OUTPUT/test.wav"
```

The expected hashes are:

| File | SHA256 |
| --- | --- |
| `silero_vad.jit` | `e1122837f4154c511485fe0b9c64455f7b929c96fbb8d79fbdb336383ebd3720` |
| `test.wav` | `89f17d9c94c4b31eb320f424628bcbc920abaddbee6e2760fd868bfb1d9a2e47` |

Trim the first 2.5 seconds for a short firmware validation workload:

```bash
python examples/arm/silero_vad_example_ethos_u/model_export/generate_smoke_audio.py \
--source-wav "$SILERO_OUTPUT/test.wav" \
--output "$SILERO_OUTPUT/validation.wav"
```

This produces 40,000 samples. The file remains mono 16-bit PCM at 16 kHz. Using a real speech recording exercises speech and silence probabilities; the helper's optional synthetic tone is a different workload.

## Export the quantized program and reference

The exporter calibrates int8 activations and weights, estimates the hidden/cell state quantization parameters, and serializes initialized recurrent state. It lowers supported computation to Ethos-U85-256 while retaining CPU operators needed for state updates and tensor conversion.

Use `test.wav` as the calibration source and the trimmed clip for validation. The exporter caps calibration at 256 windows by default and processes all 79 validation windows. Enable pipeline failure propagation so an export error remains visible even when saving the log:

```bash
set -o pipefail
python examples/arm/silero_vad_example_ethos_u/model_export/export_silero_vad_ethos_u.py \
--jit-model "$SILERO_OUTPUT/silero_vad.jit" \
--calibration-audio "$SILERO_OUTPUT/test.wav" \
--validation-audio "$SILERO_OUTPUT/validation.wav" \
--output-path "$SILERO_OUTPUT/silero_vad_ethos_u.pte" \
--expected-output-path "$SILERO_OUTPUT/expected_probs.bin" \
2>&1 | tee "$SILERO_OUTPUT/export.log"
```

The compile specification in this pinned example selects `ethos-u85-256`, `Shared_Sram`, and the default `Ethos_U85_SYS_DRAM_Mid` system configuration. The latter is a compiler performance model, not a claim that the E8 has the FVP memory system. The application copies the PTE into aligned SRAM and supplies SRAM for delegated scratch. Keep the exported memory mode and firmware placement together when changing either.

The export generates two artifacts that must stay paired:

| Artifact | Purpose |
| --- | --- |
| `silero_vad_ethos_u.pte` | Quantized program, delegated command streams, weights, and initial recurrent state |
| `expected_probs.bin` | Host quantized-graph probabilities for the 79 windows in `validation.wav` |

The host reference checks agreement with the quantized model. It is not the floating-point model's accuracy against labeled speech. Calibration and validation overlap in this example; use separate labeled recordings for an accuracy study.

The pinned source and released environment were checked together: export produced a 363,392-byte PTE and 316-byte reference. Both matched the retained FVP-tested release artifacts byte for byte. This checks host export reproducibility; it does not establish physical E8 execution.

## Inspect the exported operators

Require both nonempty artifacts, then generate the CPU operator selection that the firmware build will use:

```bash
test -s "$SILERO_OUTPUT/silero_vad_ethos_u.pte"
test -s "$SILERO_OUTPUT/expected_probs.bin"
python codegen/tools/gen_oplist.py \
--model_file_path "$SILERO_OUTPUT/silero_vad_ethos_u.pte" \
--output_path "$SILERO_OUTPUT/selected_operators.yaml"
cat "$SILERO_OUTPUT/selected_operators.yaml"
```

CPU operators are expected. A Vela subgraph's zero CPU-operator count describes that compiled subgraph, not the entire ExecuTorch program. Do not apply a fully delegated MobileSAM check to this stateful model.

Record hashes so you can identify the exact firmware inputs later:

```bash
shasum -a 256 \
"$SILERO_OUTPUT/silero_vad_ethos_u.pte" \
"$SILERO_OUTPUT/expected_probs.bin" \
"$SILERO_OUTPUT/validation.wav" \
> "$SILERO_OUTPUT/model-inputs.sha256"
```

## What you've accomplished

You have exported the U85 program, preserved its initialized recurrent state, and generated a 79-window host reference from the same audio. Next, embed the program and recording in E8 firmware with the required CPU and NPU components.
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
---
title: Prepare ExecuTorch and the E8 tools
description: Pin the source and vendor SDKs, install released export dependencies, and prepare the board connection.
weight: 3
layout: learningpathall
---

## Select the host and workspace

Use an Apple silicon Mac with Python 3.12, CMake, Ninja, Git, and ripgrep installed. Install [Zephyr SDK 0.17.0](https://github.com/zephyrproject-rtos/sdk-ng/releases/tag/v0.17.0) for macOS on Arm, including the Arm toolchain. Set its location below.

The upstream Silero example supplies the exporter and audio helpers. The downloadable application adds the E8 Zephyr target. It is a local port, so use the exact source and vendor revisions in this lesson when reproducing it.

Choose a new workspace and define the paths used throughout this Learning Path:

```bash
export ALIF_WORK="$HOME/silero-alif-e8"
export EXECUTORCH_ROOT="$ALIF_WORK/executorch"
export ZEPHYR_BASE="$ALIF_WORK/zephyr_alif"
export SDK_ALIF="$ALIF_WORK/sdk-alif"
export SILERO_OUTPUT="$ALIF_WORK/model-and-builds"
export SILERO_BUILD="$SILERO_OUTPUT/build-alif"
export ZEPHYR_SDK_INSTALL_DIR=/absolute/path/to/zephyr-sdk-0.17.0
export ZEPHYR_TOOLCHAIN_VARIANT=zephyr
mkdir -p "$ALIF_WORK" "$SILERO_OUTPUT"
```

## Get the model source and E8 application

Clone the pinned ExecuTorch source, including its build dependencies:

```bash
git clone https://github.com/pytorch/executorch.git "$EXECUTORCH_ROOT"
git -C "$EXECUTORCH_ROOT" checkout --detach \
12dac4aa042b66a7229e8d7d3af2bdde8c9f262f
git -C "$EXECUTORCH_ROOT" submodule update --init --recursive
```

Download the [E8 Silero application](../silero-alif-e8.zip) and save it as `$ALIF_WORK/silero-alif-e8.zip`. The archive contains source code for `zephyr/samples/silero-vad-ethosu`, its license notices, and a README. It contains no model weights or audio.

Check the archive hash, then extract it into the new checkout:

```bash
shasum -a 256 "$ALIF_WORK/silero-alif-e8.zip"
unzip "$ALIF_WORK/silero-alif-e8.zip" -d "$EXECUTORCH_ROOT"
test -f "$EXECUTORCH_ROOT/zephyr/samples/silero-vad-ethosu/src/main.cpp"
```

The expected SHA256 is `7c671b6665bdf11d087cc4574fd8def27a75b2c5f8ec3b3db0a7ef83eac32f78`.

## Pin the vendor board support

This application uses Alif's Zephyr fork and SDK. The board name and NPU configuration below belong to these revisions:

```bash
git clone https://github.com/alifsemi/zephyr_alif.git "$ZEPHYR_BASE"
git -C "$ZEPHYR_BASE" checkout --detach \
f002a4d8499c35fc70ec4d5324faa7b01c152c72
git clone https://github.com/alifsemi/sdk-alif.git "$SDK_ALIF"
git -C "$SDK_ALIF" checkout --detach \
1db82c9d0cc594e2b548a13699e8a4157e6dcd4c
```

The selected target is `alif_e8_dk/ae822fa0e5597xx0/rtss_hp`: the Cortex-M55 HP core with an Ethos-U85-256. Do not substitute the HE target or an older sample's U55 configuration.

## Install released Python dependencies

Create an isolated environment for export and firmware code generation:

```bash
python3.12 -m venv "$ALIF_WORK/.venv"
source "$ALIF_WORK/.venv/bin/activate"
python -m pip install "torch==2.14.0" \
--index-url https://download.pytorch.org/whl/cpu
python -m pip install "executorch[ethos_u]==1.5.1" \
"torchao==0.18.0" "cmake<4" "west==1.5.0" fdt pytest
python -m pip install -r "$ZEPHYR_BASE/scripts/requirements.txt"
```

These are released packages. The wheel supplies host export and code-generation components; the pinned source supplies the example scripts and the C++ runtime built for Zephyr. Keep this environment active for both operations. The source revision and wheel version are separate pins, so retain the model/firmware validation results for this combination.

The `ethos_u` extra installs Vela and TOSA tooling. This board workflow uses the Zephyr SDK compiler and does not require an FVP installation. Do not run the source tree's general nightly dependency installer over this environment.

## Initialize the vendor west workspace

Initialize west once in the new workspace, resolve the vendor modules, and save the resolved versions:

```bash
cd "$ALIF_WORK"
west init -l "$ZEPHYR_BASE"
west update
west zephyr-export
west manifest --freeze > "$SILERO_OUTPUT/west-manifest.yml"
python -m pip freeze > "$SILERO_OUTPUT/python-requirements.txt"
cd "$EXECUTORCH_ROOT"
```

If resuming an existing workspace, verify its manifest instead of initializing it again. The pinned vendor manifest includes moving module references. Save the frozen manifest above with each build; the Zephyr and SDK commit pins alone do not lock every west project.

## Prepare the board tools

Install Alif Security Toolkit for your E8 silicon revision and SEGGER J-Link. Follow the Security Toolkit and debug-probe portions of the [E8 board setup guide](https://learn.arm.com/learning-paths/embedded-and-microcontrollers/alif-image-classification/board-setup/). Its CMSIS application build is a separate example.

Connect the board's **PRG USB** port with a data-capable cable, retain the vendor jumper settings, and leave **SW4 on SEUART** for programming. Confirm that the host discovers the serial port and J-Link probe. Close applications holding the programming serial port.

The E8 DevKit has an onboard USB-to-UART bridge. SW4 routes it to SEUART for programming or UART4 for the HP application console at 115200 baud, 8N1. No separate adapter is required. The programming lesson shows the single switch change to UART4 after flashing and the return to SEUART before any later programming.

Set the installed tool locations and HP device:

```bash
export ALIF_SE_TOOLS_DIR=/absolute/path/to/alif-security-toolkit
export JLINK_COMMANDER=/absolute/path/to/JLinkExe
export ALIF_DEVICE=AE822FA0E5597LS0_M55_HP
test -d "$ALIF_SE_TOOLS_DIR/build/config"
test -x "$JLINK_COMMANDER"
command -v west
```

Match the toolkit's A0/A1 configuration to your actual board. The device above selects the HP core; it does not detect the silicon revision for you.

## What you've accomplished

You have selected the source, E8 vendor revisions, released Python packages, and board tools. Next, generate the quantized streaming model and its matching probability reference.
Loading
Loading