wasm2mpy
October 3, 2024 ยท View on GitHub
wasm2mpy enables developers to write code in statically compiled languages and run it on MicroPython-based embedded systems (such as ESP32, Raspberry Pi Pico, STM32, and nRF52) with near-native performance. Since MicroPython is relatively slow for computationally intensive applications, wasm2mpy provides the tools necessary to run demanding software, such as AI models and signal processing algorithms, more efficiently.
Status
| App \ Target | x86/x64 | armv6m | armv7m/+s/+d | esp82661 | esp32 | rv32imc |
|---|---|---|---|---|---|---|
| ๐ TypeScript2 | โ โ | โ | โ โ โ | โ ๏ธ3 | โ | โ |
| ๐คฉ C++ | โ โ | โ | โ โ โ | ๐ก | โ | โ |
| ๐ฆ Rust | โ โ | โ | ๐ก๐กโ | โ ๏ธ3 | โ | โ |
| ๐ค TinyGo | โ โ | โ | ๐ก๐กโ | โ ๏ธ3 | โ | โ |
| โก Zig | โ โ | โ | โ โ โ | โ ๏ธ3 | โ | โ |
| โจ Virgil | โ โ | โ | โ โ โ | ๐ก | โ | โ |
| โ WAT | โ โ | โ | โ โ โ | ๐ก | โ | โ |
| ๐จ Coremark | โ โ | ๐ง | โ โ โ | ๐ก | โ | โ |
โ
builds and runs OK
๐ก builds OK, doesn't run
๐ง work in progress
CoreMark results
- ESP32-C3 160MHz:
179.791 - STM32F405 168MHz:
233.918 - ESP32 240MHz:
228.363 - ESP32-S3 240MHz:
271.573 - BL616 320MHz:
344.293 - iMXRT1062 600MHz:
1911.437 - i5-8250U 1.6GHz:
18696.248
Upload and Run
Follow the build instructions
mpremote cp zig.mpy :lib/
mpremote exec "import zig; zig.setup()"
โก Zig is running!
Run any exported function
Note
This requires adding some glue code to the runtime.
Glue code can be auto-generated, but for now it's a manual process.
For example, test/simple.wasm just adds 2 numbers:
(module
(func (export "add") (param i32 i32) (result i32)
(i32.add (local.get 0) (local.get 1))
)
)
MicroPython v1.24.0-preview.224.g6c3dc0c0b on 2024-08-22; Raspberry Pi Pico W with RP2040
Type "help()" for more information.
>>> import simple
>>> simple.add(3, 4)
7
>>> simple.add(10, 6)
16
Access WASM module memory
>>> import cpp
>>> cpp.setup()
๐คฉ C++ is running!
>>> cpp._memory[4096:4096+32]
bytearray(b' Blink\x00\xf0\x9f\xa4\xa9 C++ is running!\x00\n\x00\x00\x00')
>>> new_data = b"Hello C++ world"
>>> cpp._memory[4096+12:4096+12+len(new_data)] = new_data
>>> cpp.setup()
๐คฉ Hello C++ world
How It Works?
The idea is very similar to embedded-wasm-apps:

TODO
- Support exports
- Auto-generate exports bindings
- Support imports
- Support memory
- Support
.ainputs formpy_ld - XIP for native modules
- TBD: Support globals
- Add RISC-V support: https://github.com/micropython/micropython/pull/15603
- Optimize codegen
- Use
u32instead ofu64for mem addresses - Use a directly addressable
.bsssection as memory (skip indirection)
- Use
- Implement WASM Custom Page Sizes
- Implement WASM Exceptions
- Implement WASM Stack Switching
Further reading
- Discussions: GitHub, Hacker News
- wasm2c, w2c2
- MicroPython Native Modules
- Feasibility of WASM for MicroPython
Footnotes
-
esp8266requires the use ofesp.set_native_code_location, and settingWASM_PAGE_SIZEto8192(or need to wait forWASM Custom Page Sizes) โฉ -
not enough memory to run, need to wait for
WASM Custom Page Sizesโฉ โฉ2 โฉ3 โฉ4