Skip to content

mlaass/wamr-esp32-arduino

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

WAMR-ESP32-Arduino

WebAssembly Micro Runtime (WAMR) library for ESP32/ESP32-S3 with Arduino and PlatformIO support.

License Platform

Overview

This library packages the WebAssembly Micro Runtime (WAMR) from the Bytecode Alliance for easy use with ESP32 and ESP32-S3 in Arduino and PlatformIO projects.

WAMR is a lightweight WebAssembly runtime that allows you to:

  • Run sandboxed WebAssembly code on your ESP32
  • Dynamically load and execute code without reflashing
  • Achieve near-native performance with AOT compilation
  • Isolate untrusted code in a safe execution environment
  • Update application logic over-the-air

Features

  • Fast Interpreter - Optimized WASM interpreter (~2X faster than classic)
  • Small Footprint - Minimal memory overhead (50-100KB + module size)
  • Arduino-Friendly - Simple C++ API with Serial debugging
  • Thread-Safe API - Automatic pthread wrapping for Arduino compatibility
  • PSRAM Support - Automatically uses PSRAM when available
  • Native Functions - Call Arduino functions from WASM
  • Built-in libc - Standard C library functions available to WASM
  • ESP32 & ESP32-S3 - Supports Xtensa architecture

Current Configuration

This library is configured for minimal interpreter-only build:

  • Fast interpreter mode (enabled)
  • AOT runtime (disabled - can be enabled)
  • WASI (disabled - libc-builtin only)
  • Multi-threading (disabled)
  • JIT compilation (disabled)

Installation

PlatformIO

Add to your platformio.ini:

[env:esp32]
platform = espressif32
board = esp32dev  ; or your board
framework = arduino
lib_deps =
    https://github.com/mlaass/wamr-esp32-arduino.git

Arduino IDE

  1. Download this repository as ZIP
  2. In Arduino IDE: Sketch → Include Library → Add .ZIP Library
  3. Select the downloaded ZIP file
  4. Restart Arduino IDE

Manual Installation

Clone or download this repository to your Arduino libraries folder:

cd ~/Arduino/libraries/  # or your libraries directory
git clone https://github.com/mlaass/wamr-esp32-arduino.git

Quick Start

#include <WAMR.h>

// Your WASM module binary (embed or load from file)
const unsigned char my_wasm[] = { /* ... */ };
const unsigned int my_wasm_len = /* ... */;

WamrModule module;

void setup() {
  Serial.begin(115200);

  // Initialize WAMR runtime
  if (!WamrRuntime::begin(128 * 1024)) {  // 128KB heap
    Serial.println("Failed to init WAMR!");
    return;
  }

  // Load WASM module
  if (!module.load(my_wasm, my_wasm_len)) {
    Serial.println("Failed to load module!");
    return;
  }

  // Call WASM function (safe - auto pthread-wrapped)
  uint32_t args[2] = {42, 58};
  if (module.callFunction("add", 2, args)) {
    Serial.printf("Result: %u\n", args[0]);
  }
}

void loop() {
  // Your code here
}

Examples

The library includes four example sketches:

1. Basic WASM (basic_wasm.ino)

Demonstrates:

  • Runtime initialization
  • Loading a simple WASM module
  • Calling WASM functions with parameters
  • Getting results

2. Native Functions (native_functions.ino)

Demonstrates:

  • Exporting Arduino functions to WASM
  • Calling native functions from WASM
  • Hardware control (LED blinking) from WASM code

3. Memory Test (memory_test.ino)

Demonstrates:

  • Memory allocation strategies
  • PSRAM usage
  • Heap size configuration
  • Performance profiling

4. Threading (threading.ino)

Demonstrates:

  • Safe API with automatic pthread wrapping (recommended)
  • Raw API for manual thread management (advanced)
  • Performance comparison between APIs
  • Custom thread stack configuration with setThreadStackSize()

Documentation

Memory Requirements

ESP32 (without PSRAM)

  • Minimum: 64KB runtime heap + 32KB module heap
  • Recommended: 128KB runtime heap + 64KB module heap

ESP32-S3 (with PSRAM)

  • Can use 256KB+ for runtime heap
  • PSRAM is automatically detected and used
  • Better for larger WASM applications

Typical Memory Usage

  • WAMR Runtime: ~50-100KB (depending on features)
  • WASM Module: Varies by module size
  • Stack: 16KB per execution (default)
  • Heap: Configurable per module

Supported Platforms

  • ESP32 (Xtensa dual-core)
  • ESP32-S3 (Xtensa dual-core, PSRAM support)

Planned Support

  • ESP32-C3 (RISC-V) - requires RISC-V build configuration
  • ESP32-C6 (RISC-V) - requires RISC-V build configuration

Building WASM Modules

You need the WASI SDK or Emscripten to compile C/C++ to WASM.

Simple example:

# Install WASI SDK
wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-21/wasi-sdk-21.0-linux.tar.gz
tar xf wasi-sdk-21.0-linux.tar.gz

# Compile C to WASM
wasi-sdk-21.0/bin/clang --target=wasm32 -O3 \
    -nostdlib -Wl,--no-entry \
    -Wl,--export=add \
    -o add.wasm add.c

See docs/BUILDING_WASM.md for detailed instructions.

API Overview

WamrRuntime Class

// Initialize runtime (call once in setup())
WamrRuntime::begin(heap_size);

// Shutdown runtime
WamrRuntime::end();

// Check if initialized
WamrRuntime::isInitialized();

// Print memory usage
WamrRuntime::printMemoryUsage();

WamrModule Class

WamrModule module;

// Load WASM module
module.load(wasm_bytes, size, stack_size, heap_size);

// Call function (SAFE - recommended for Arduino)
// Automatically wraps in pthread context
uint32_t args[] = {arg1, arg2};
module.callFunction("function_name", num_args, args);

// Call function (RAW - advanced use only)
// Must be called from pthread context, crashes otherwise
module.callFunctionRaw("function_name", num_args, args);

// Configure pthread stack size for callFunction()
WamrModule::setThreadStackSize(64 * 1024);  // 64KB stack

// Get result
uint32_t result = args[0];  // Result in first argument

// Get error
const char* error = module.getError();

// Unload module
module.unload();

Log Level Configuration

The library supports configurable logging to help with debugging and reduce serial output in production.

Available Log Levels

  • WAMR_LOG_NONE (0) - No logging output
  • WAMR_LOG_ERROR (1) - Only error messages (default)
  • WAMR_LOG_DEBUG (2) - Error and debug messages

Usage

Define WAMR_LOG_LEVEL before including the WAMR header:

// Option 1: No logging (production builds)
#define WAMR_LOG_LEVEL WAMR_LOG_NONE
#include <WAMR.h>

// Option 2: Errors only (default - no need to define)
#include <WAMR.h>

// Option 3: Full debug output (development/troubleshooting)
#define WAMR_LOG_LEVEL WAMR_LOG_DEBUG
#include <WAMR.h>

What Gets Logged

ERROR level includes:

  • Runtime initialization failures
  • Module loading/instantiation errors
  • Function call failures
  • Memory allocation errors
  • Thread creation errors

DEBUG level includes all errors plus:

  • Runtime initialization progress
  • Module loading steps
  • Function call traces
  • Memory allocation details (PSRAM vs internal RAM)
  • Thread stack configuration

Example Output

With WAMR_LOG_DEBUG:

WAMR: Initializing runtime...
WAMR: Using PSRAM for heap
WAMR: Runtime initialized with 131072 bytes heap
WAMR: Loading module (1234 bytes)...
WAMR: Module loaded successfully
WAMR: Instantiating module (stack: 16384, heap: 65536)...
WAMR: Module instantiated successfully
WAMR: Module ready for execution
WAMR: Calling function 'add'...
WAMR: Function returned: 100
WAMR: Function 'add' completed successfully

With WAMR_LOG_ERROR (default):

(Only errors are shown if they occur)

With WAMR_LOG_NONE:

(No WAMR logging output)

Note: The log level is set at compile time, so there's zero runtime overhead when logging is disabled.

Performance

Typical performance characteristics:

  • Function call overhead: ~10-50μs
  • Execution speed: ~50-70% of native C (interpreter mode)
  • Memory overhead: ~2X for fast interpreter vs classic
  • Startup time: <100ms for small modules

Note: AOT (Ahead-of-Time) compilation can provide near-native performance but requires the wamrc compiler.

Limitations

Current build limitations:

  • Interpreter only (no AOT/JIT runtime included)
  • No WASI support (libc-builtin only)
  • No multi-threading support
  • Xtensa only (RISC-V not yet configured)

These can be enabled by modifying src/wamr/build_config.h and adding the required source files.

Contributing

Contributions are welcome! Please:

  1. Test on real hardware (ESP32/ESP32-S3)
  2. Follow the existing code style
  3. Update documentation as needed
  4. Add examples if introducing new features

License

This library is licensed under Apache License 2.0 with LLVM Exception, the same as WAMR.

See LICENSE for details.

Acknowledgments

Version

  • Library Version: 1.0.0
  • WAMR Version: 2.4.1+ (see src/wamr/WAMR_VERSION.txt)

Links

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages