Deploying WAMR on Zephyr for ESP32#
1. Set Up Zephyr Development Environment#
Install Dependencies on your development machine#
Update your system. For debian based systems you can use the following command:
sudo apt update
sudo apt upgrade
Install the required tools:
sudo apt install --no-install-recommends git cmake ninja-build gperf \
ccache dfu-util device-tree-compiler wget \
python3-dev python3-pip python3-setuptools python3-tk python3-wheel xz-utils file \
make gcc gcc-multilib g++-multilib libsdl2-dev libmagic1
Verify tool versions:
cmake --version
python3 --version
dtc --version
Ensure versions meet the minimum requirements: CMake 3.20.5, Python 3.10, and Devicetree Compiler 1.4.6.
Get Zephyr and Python Dependencies on your development machine#
Install Python venv package::
sudo apt install python3-venv
Create a new virtual environment:
python3 -m venv ~/zephyrproject/.venv
Activate the virtual environment:
source ~/zephyrproject/.venv/bin/activate
Install west:
pip install west
Create a Zephyr workspace and clone the repository:
west init ~/zephyrproject
cd ~/zephyrproject
west update
Export Zephyr CMake package:
west zephyr-export
Install Python dependencies:
west packages pip --install
Install the Zephyr SDK:
cd ~/zephyrproject/zephyr
west sdk install
You can also install Zephyr SDK without using the west sdk command, as described in this Zephyr SDK installation guide.
Fetch Espressif binary blobs:
west blobs fetch hal_espressif
The ZEPHYR_BASE
environment variable is essential for locating Zephyr's core build system, CMake scripts, and modules. Without this variable set, Zephyr tools like west
will fail to build applications.
To confirm whether the ZEPHYR_BASE
environment variable is configured correctly, use the following command:
echo $ZEPHYR_BASE
If the output is empty or incorrect, follow the steps below to set it.
- Activate your Zephyr Virtual Environment:
If you're using a virtual environment for Zephyr, activate it first:
bash
source ~/zephyrproject/.venv/bin/activate
- Set the
ZEPHYR_BASE
Variable:
Once activated, set the ZEPHYR_BASE
variable to point to the Zephyr directory:
bash
export ZEPHYR_BASE=~/zephyrproject/zephyr
- Make the Change Permanent:
To ensure the ZEPHYR_BASE
variable is set automatically in future sessions, add the following line to your shell's configuration file (.bashrc
for Bash or .zshrc
for Zsh):
bash
export ZEPHYR_BASE=~/zephyrproject/zephyr
After adding the line, apply the changes by running:
bash
source ~/.bashrc # For Bash users
source ~/.zshrc # For Zsh users
- For more information on Zephyr environment variables, visit the Zephyr Environment Variables Documentation.
- For a comprehensive guide on setting up Zephyr, refer to the official Zephyr Getting Started Guide.
- For board-specific information, such as the Espressif ESP32-S3 DevKitC, refer to the official documentation for setup and configuration details.
- To see the full list of supported boards, refer to the Zephyr Board Documentation.
2. Install ESP-IDF on your development machine#
Do not install ESP-IDF inside the Zephyr virtual environment. ESP-IDF is a separate development framework with its own setup and toolchain requirements, which should be installed and managed globally or in its own isolated environment. Global Installation (Preferred). This way, its tools and environment are available for any project on the ESP32, including Zephyr.
Without ESP-IDF:
- You cannot compile or flash code for the ESP32.
- Zephyr won’t be able to recognize or support the ESP32-S3 during build or runtime.
Option 1: Using VS Code Extension (Recommended)#
Install the ESP-IDF extension:
- Navigate to View > Extensions in VS Code.
- Search for "ESP-IDF Extension" and install it.
Configure the ESP-IDF extension:
- Open Command Palette (
Ctrl+Shift+P
orCmd+Shift+P
). - Run
ESP-IDF: Configure ESP-IDF Extension
. - Follow the setup wizard to download and install ESP-IDF.
Ensure correct paths for IDF:
- Set
IDF_PATH
andIDF_TOOLS_PATH
appropriately (default:$HOME/.espressif
).
Add OpenOCD rules for Linux. The command typically looks like:
sudo cp --update=none /home/<username>/.espressif/tools/openocd-esp32/<version>/share/openocd/contrib/60-openocd.rules /etc/udev/rules.d/
then reload udev rules to apply the changes:
sudo udevadm control --reload-rules
sudo udevadm trigger
For more detailed information, refer to the official ESP-IDF Extension Guide.
Option 2: Manual Installation#
Download ESP-IDF:
mkdir -p ~/esp
cd ~/esp
wget https://github.com/espressif/esp-idf/releases/download/v5.3.2/esp-idf-v5.3.2.zip
unzip esp-idf-v5.3.2.zip -d v5.3.2
Ensure the directory structure is correct after unzipping. The export script requires paths to be consistent.
Export the ESP-IDF environment:
source ~/esp/v5.3.2/esp-idf/export.sh
Run this command in every new terminal session, or automate it by adding the export command to your shell's startup script (~/.bashrc, ~/.zshrc, etc.).
Verify the installation:
Check the installed ESP-IDF version:
idf.py --version
If the idf.py
command fails with command not found
, source the ESP-IDF Environment in VS Code. To avoid manually sourcing the export.sh
script every time you open a terminal:
- Open your shell configuration file (
~/.zshrc
or~/.bashrc
):
bash
nano ~/.zshrc
- Add this line at the bottom:
bash
source ~/esp/v5.3.2/esp-idf/export.sh
- Save and reload the shell configuration:
bash
source ~/.zshrc
-
Once the environment is sourced:
-
Check the Xtensa toolchain:
bash xtensa-esp32s3-elf-gcc --version
-
Verify
idf.py
again:bash idf.py --version
3. Test Zephyr's Integration with ESP-IDF#
Navigate to your Zephyr workspace:
cd ~/zephyrproject
Activate the virtual environment. This ensures that Zephyr tools (e.g., west, CMake) and configurations are properly used during the build process.
source .venv/bin/activate
Build the Hello World sample:
west build -b esp32s3_devkitc/esp32s3/procpu zephyr/samples/hello_world
Flash the firmware:
west flash
Monitor the output:
west espressif monitor
A successful run shows that the entire build-flash-boot-debug toolchains are functional for your development board.
NOTE:
- Before building, list all supported boards to verify the correct target name. Look for your desired board in the output of:
bash
west boards
In Zephyr’s newer versions, boards like esp32s3_devkitc are split into multiple “sub-boards” for each core. So instead of building with:
bash
west build -b esp32s3_devkitc zephyr/samples/hello_world
you need to specify which core to target, e.g. esp32s3_devkitc/esp32s3/procpu
(for the primary processor core, which we will use in this example) or the esp32s3_devkitc/esp32s3/appcpu
(for the application processor core)
- If you see the message
ninja: no work to do
, it means the build system has detected no changes since the last build, and no new compilation is needed. Use the--pristine
flag to ensure a completely clean build environment:
bash
west build -b esp32s3_devkitc/esp32s3/procpu zephyr/samples/hello_world --pristine
- Use
west flash --erase
if the board has residual firmware causing conflicts. - Ensure that
west espressif monitor
is not running when you attempt to flash the firmware. It keeps the serial port busy, preventing thewest flash
command from accessing it.
Using WebAssembly Micro Runtime (WAMR) with Zephyr#
Step 1: Clone WAMR repository#
cd ~/zephyrproject
git clone https://github.com/bytecodealliance/wasm-micro-runtime.git
After running the above commands, your folder structure will look like this:
~/zephyrproject/
├── zephyr/
├── modules/
├── wasm-micro-runtime/
Note: It's not necessary to clone WAMR inside the
zephyrproject
folder, but it’s easier to keep everything organized in one place. If you choose to place it elsewhere, you will need to update some configuration files to point to the correct location of the WAMR repository.
Step 2: Update CMakeLists.txt (Optional)#
If you decided to place the WAMR repository outside of the zephyrproject
folder, you will need to tell Zephyr where to find it. You can do this by updating your CMakeLists.txt
file.
Add these lines:
set(WAMR_ROOT /path/to/wasm-micro-runtime)
include(${WAMR_ROOT}/build-scripts/runtime_lib.cmake)
Make sure to replace /path/to/wasm-micro-runtime
with the actual path where you placed the WAMR source.
Step 3: Test Your Installation#
To make sure everything is set up correctly, build and run a test application.
- Go to the
basic
sample directory:
bash
cd samples/basic
- Inside the
basic
sample folder, you’ll find a script calledbuild.sh
. This script compiles both the native application and the WebAssembly (WASM) application. To build the project, run:
bash
./build.sh
- After the build finishes, you will find the output files in the
out
directory. To run the test application, go to theout
folder:
bash
cd out
- Run the application with the following command:
bash
./basic -f wasm-apps/testapp.wasm
You should see output like this:
calling into WASM function: generate_float
Native finished calling wasm function generate_float(), returned a float value: 102009.921875f
calling into WASM function: float_to_string
calling into native function: intToStr
calling into native function: get_pow
calling into native function: intToStr
Native finished calling wasm function: float_to_string, returned a formatted string: 102009.921
Step 4: Clean Build Artifacts#
If you want to clean up the build files, simply run:
./build.sh clean
Step 5: Deploy WAMR on Zephyr for ESP32#
After testing WAMR locally, deploy it to the ESP32 board using Zephyr.
- Go to the WAMR example directory for Zephyr:
bash
cd ~/zephyrproject/wasm-micro-runtime/product-mini/platforms/zephyr/simple
- If you haven’t already, activate your Zephyr virtual environment:
bash
source ~/zephyrproject/.venv/bin/activate
- Build the WAMR example for your ESP32 board. Replace
<your_board>
with your specific board name, likeesp32s3_devkitc
:
bash
west build -b <your_board>
- Flash the firmware to your ESP32 board:
bash
west flash
- To see what's happening on the board, open the serial monitor:
bash
west espressif monitor
Using a WebAssembly Module with Zephyr#
The sample C code is in src/wasm-app-riscv64/main.c
. To generate a .wasm
file, run the build script located in src/wasm-app-riscv64/build.sh
.
./build.sh
This creates test.wasm
, test_wasm.h
, and test_wasm_riscv64.h
. Replace src/test_wasm.h
and src/test_wasm_riscv64.h
with the newly generated files from src/wasm-app-riscv64
.
Build the firmware (replace <your_board>
with the board name):
west build -b <your_board>
Flash the firmware:
west flash
Use the serial monitor to see output:
west espressif monitor
Potential Pitfalls and Solutions#
1. Permission Denied for /dev/ttyUSB0
#
Add your user to the dialout
group then log out and log back in or restart the system.:
sudo usermod -aG dialout $USER
2. west
Not Found#
Activate the virtual environment:
source ~/zephyrproject/.venv/bin/activate
3. Build Fails with Missing Board Qualifiers#
Use the correct board target as described in The board qualifiers. For ESP32s3, for example:
west build -b esp32s3_devkitc/esp32s3/procpu zephyr/samples/hello_world
4. Serial Port Already in Use#
- Identify the process using the port and kill it:
bash
lsof /dev/ttyUSB0
kill <PID>
5. CMake source directory mismatch#
Clear the existing CMake cache to resolve the mismatch by deleting the build
directory and then re-run the west build
command.
rm -rf ~/zephyrproject/zephyr/build