From b97ef7794e0c771ae7d3fe1409e08bdce1794eb7 Mon Sep 17 00:00:00 2001 From: Volodymyr Shymanskyy Date: Sat, 18 Jan 2020 00:54:06 +0200 Subject: [PATCH] ESP32 blink example --- platforms/arduino_blink/.gitignore | 1 + platforms/arduino_blink/README.md | 19 ++++ platforms/arduino_blink/platformio.ini | 38 ++++++++ .../arduino_blink/src/arduino_wasm_api.cpp | 86 ++++++++++++++++++ platforms/arduino_blink/src/m3 | 1 + platforms/arduino_blink/src/main.cpp | 70 ++++++++++++++ platforms/arduino_blink/wasm/arduino_app.cpp | 29 ++++++ platforms/arduino_blink/wasm/arduino_app.wasm | Bin 0 -> 197 bytes .../arduino_blink/wasm/arduino_app.wasm.h | 20 ++++ .../arduino_blink/wasm/arduino_wasm_api.h | 30 ++++++ .../arduino_blink/wasm/arduino_wasm_api.syms | 5 + platforms/arduino_blink/wasm/build.sh | 12 +++ 12 files changed, 311 insertions(+) create mode 100644 platforms/arduino_blink/.gitignore create mode 100644 platforms/arduino_blink/README.md create mode 100644 platforms/arduino_blink/platformio.ini create mode 100644 platforms/arduino_blink/src/arduino_wasm_api.cpp create mode 120000 platforms/arduino_blink/src/m3 create mode 100644 platforms/arduino_blink/src/main.cpp create mode 100644 platforms/arduino_blink/wasm/arduino_app.cpp create mode 100755 platforms/arduino_blink/wasm/arduino_app.wasm create mode 100644 platforms/arduino_blink/wasm/arduino_app.wasm.h create mode 100644 platforms/arduino_blink/wasm/arduino_wasm_api.h create mode 100644 platforms/arduino_blink/wasm/arduino_wasm_api.syms create mode 100755 platforms/arduino_blink/wasm/build.sh diff --git a/platforms/arduino_blink/.gitignore b/platforms/arduino_blink/.gitignore new file mode 100644 index 0000000..03f4a3c --- /dev/null +++ b/platforms/arduino_blink/.gitignore @@ -0,0 +1 @@ +.pio diff --git a/platforms/arduino_blink/README.md b/platforms/arduino_blink/README.md new file mode 100644 index 0000000..b70ed26 --- /dev/null +++ b/platforms/arduino_blink/README.md @@ -0,0 +1,19 @@ +## Arduino blink example + +This example was tested with ESP32. +ESP8266 is almost working (just needs a workaround for 64KiB wasm pages). + +`./wasm` directory contains an example Arduino app (sketch) that is compiled to WebAssembly. +Compilation is performed using `wasicc` here, but `clang --target=wasm32` can be used as well. +The resulting `wasm` binary is then converted to a C header using `xxd`. +See `build.sh` for details. + +`PlatformIO` is used to build the host interpreter. +You can change the LED pin number in `platformio.ini` with `-DLED_BUILTIN` option. + +To run the example on ESP32: + +```sh +pio run -e esp32 -t upload && pio device monitor +``` + diff --git a/platforms/arduino_blink/platformio.ini b/platforms/arduino_blink/platformio.ini new file mode 100644 index 0000000..39b33f7 --- /dev/null +++ b/platforms/arduino_blink/platformio.ini @@ -0,0 +1,38 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:esp32] +platform = espressif32 +board = esp32dev +framework = arduino +board_build.f_cpu = 240000000L + +monitor_speed = 115200 + +src_build_flags = + -DLED_BUILTIN=19 + -DESP32 -Dd_m3LogOutput=false + -O3 -flto + -Wno-unused-function -Wno-unused-variable -Wno-unused-parameter -Wno-missing-field-initializers + +[env:esp8266] +platform = espressif8266 +board = nodemcuv2 +framework = arduino +board_build.f_cpu = 160000000L + +monitor_speed = 115200 +upload_speed = 460800 + +src_build_flags = + -DLED_BUILTIN=13 + -DESP8266 -Dd_m3FixedHeap=0x6000 -Dd_m3LinearMemLimit=2048 -Dd_m3LogOutput=false + -O3 -flto + -Wno-unused-function -Wno-unused-variable -Wno-unused-parameter -Wno-missing-field-initializers diff --git a/platforms/arduino_blink/src/arduino_wasm_api.cpp b/platforms/arduino_blink/src/arduino_wasm_api.cpp new file mode 100644 index 0000000..fb66fb4 --- /dev/null +++ b/platforms/arduino_blink/src/arduino_wasm_api.cpp @@ -0,0 +1,86 @@ +#include "m3/m3_api_defs.h" +#include "m3/m3_env.h" + +#include + +/* + * Note: each RawFunction should complete with one of these calls: + * m3ApiReturn(val) - Returns a value + * m3ApiSuccess() - Returns void (and no traps) + * m3ApiTrap(trap) - Returns a trap + */ + +m3ApiRawFunction(m3_arduino_millis) +{ + m3ApiReturnType (uint32_t) + + m3ApiReturn(millis()); +} + +m3ApiRawFunction(m3_arduino_delay) +{ + m3ApiGetArg (uint32_t, ms) + + //printf("api: delay %d\n", ms); // you can also trace API calls + + delay(ms); + + m3ApiSuccess(); +} + +// This maps pin modes from arduino_wasm_api.h +// to actual platform-specific values +uint8_t mapPinMode(uint8_t mode) +{ + switch(mode) { + case (0): return INPUT; + case (1): return OUTPUT; + case (2): return INPUT_PULLUP; + } + return INPUT; +} + +m3ApiRawFunction(m3_arduino_pinMode) +{ + m3ApiGetArg (uint32_t, pin) + m3ApiGetArg (uint32_t, mode) + + pinMode(pin, mapPinMode(mode)); + + m3ApiSuccess(); +} + +m3ApiRawFunction(m3_arduino_digitalWrite) +{ + m3ApiGetArg (uint32_t, pin) + m3ApiGetArg (uint32_t, value) + + digitalWrite(pin, value); + + m3ApiSuccess(); +} + +// This is a convenience function +m3ApiRawFunction(m3_arduino_getPinLED) +{ + m3ApiReturnType (uint32_t) + + m3ApiReturn(LED_BUILTIN); +} + + +M3Result m3_LinkArduino (IM3Runtime runtime) +{ + IM3Module module = runtime->modules; + const char* arduino = "arduino"; + + m3_LinkRawFunction (module, arduino, "millis", "i()", &m3_arduino_millis); + m3_LinkRawFunction (module, arduino, "delay", "v(i)", &m3_arduino_delay); + m3_LinkRawFunction (module, arduino, "pinMode", "v(ii)", &m3_arduino_pinMode); + m3_LinkRawFunction (module, arduino, "digitalWrite", "v(ii)", &m3_arduino_digitalWrite); + + m3_LinkRawFunction (module, arduino, "getPinLED", "i()", &m3_arduino_getPinLED); + + return m3Err_none; +} + diff --git a/platforms/arduino_blink/src/m3 b/platforms/arduino_blink/src/m3 new file mode 120000 index 0000000..03cc5a6 --- /dev/null +++ b/platforms/arduino_blink/src/m3 @@ -0,0 +1 @@ +../../../source \ No newline at end of file diff --git a/platforms/arduino_blink/src/main.cpp b/platforms/arduino_blink/src/main.cpp new file mode 100644 index 0000000..769ed3b --- /dev/null +++ b/platforms/arduino_blink/src/main.cpp @@ -0,0 +1,70 @@ +// +// Wasm3 - high performance WebAssembly interpreter written in C. +// +// Copyright © 2019 Steven Massey, Volodymyr Shymanskyy. +// All rights reserved. +// + +#include "Arduino.h" + +#include "m3/m3.h" + +#include "../wasm/arduino_app.wasm.h" + +M3Result m3_LinkArduino (IM3Runtime runtime); + +#define FATAL(msg, ...) { printf("Fatal: " msg "\n", ##__VA_ARGS__); return; } + +void wasm_task(void*) +{ + M3Result result = m3Err_none; + + IM3Environment env = m3_NewEnvironment (); + if (!env) FATAL("m3_NewEnvironment failed"); + + IM3Runtime runtime = m3_NewRuntime (env, 1024, NULL); + if (!runtime) FATAL("m3_NewRuntime failed"); + + IM3Module module; + result = m3_ParseModule (env, &module, arduino_app_wasm, arduino_app_wasm_len-1); + if (result) FATAL("m3_ParseModule: %s", result); + + result = m3_LoadModule (runtime, module); + if (result) FATAL("m3_LoadModule: %s", result); + + result = m3_LinkArduino (runtime); + if (result) FATAL("m3_LinkArduino: %s", result); + + IM3Function f; + result = m3_FindFunction (&f, runtime, "_start"); + if (result) FATAL("m3_FindFunction: %s", result); + + printf("Running WebAssembly...\n"); + + const char* i_argv[1] = { NULL }; + result = m3_CallWithArgs (f, 0, i_argv); + + if (result) FATAL("m3_CallWithArgs: %s", result); + + // Should not arrive here +} + +void setup() +{ + Serial.begin(115200); + delay(100); + + Serial.print("\nWasm3 v" M3_VERSION ", build " __DATE__ " " __TIME__ "\n"); + +#ifdef ESP32 + // On ESP32, we can launch in a separate thread + xTaskCreate(&wasm_task, "wasm3", 32768, NULL, 5, NULL); +#else + wasm_task(NULL); +#endif +} + +void loop() +{ + delay(100); +} diff --git a/platforms/arduino_blink/wasm/arduino_app.cpp b/platforms/arduino_blink/wasm/arduino_app.cpp new file mode 100644 index 0000000..5532ca9 --- /dev/null +++ b/platforms/arduino_blink/wasm/arduino_app.cpp @@ -0,0 +1,29 @@ + +#include "arduino_wasm_api.h" + +int LED_BUILTIN; + +void setup() { + LED_BUILTIN = getPinLED(); + + // initialize digital pin LED_BUILTIN as an output. + pinMode(LED_BUILTIN, OUTPUT); +} + +// the loop function runs over and over again forever +void loop() { + digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) + delay(100); // wait 100ms + digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW + delay(900); // wait 900ms +} + +/* + * Entry point + */ + +WASM_EXPORT +void _start() { + setup(); + while (1) { loop(); } +} diff --git a/platforms/arduino_blink/wasm/arduino_app.wasm b/platforms/arduino_blink/wasm/arduino_app.wasm new file mode 100755 index 0000000000000000000000000000000000000000..078db5315c814595a2dca4d56da62e9c4928697d GIT binary patch literal 197 zcmYkwI|{-;6ouh)?<5&DDI#t_tXzSJl>zNk>@3Z|3}GM-NyZ{oEL^G!F#!Ws=lma3 zQxE`}dntDvQXr*asN;(#Rjr@4tfrZ9S6iNr2Z+(+!Xs4Q8>eaqZ?>Z?QJ1_XF;>_xmPjZjvF~Ng!{_9KSo{)wzGW;T Ggb2UL#4AYv literal 0 HcmV?d00001 diff --git a/platforms/arduino_blink/wasm/arduino_app.wasm.h b/platforms/arduino_blink/wasm/arduino_app.wasm.h new file mode 100644 index 0000000..5ff8cfb --- /dev/null +++ b/platforms/arduino_blink/wasm/arduino_app.wasm.h @@ -0,0 +1,20 @@ +unsigned char arduino_app_wasm[] = { + 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x11, 0x04, 0x60, + 0x02, 0x7f, 0x7f, 0x00, 0x60, 0x00, 0x00, 0x60, 0x01, 0x7f, 0x00, 0x60, + 0x00, 0x01, 0x7f, 0x02, 0x4e, 0x04, 0x07, 0x61, 0x72, 0x64, 0x75, 0x69, + 0x6e, 0x6f, 0x09, 0x67, 0x65, 0x74, 0x50, 0x69, 0x6e, 0x4c, 0x45, 0x44, + 0x00, 0x03, 0x07, 0x61, 0x72, 0x64, 0x75, 0x69, 0x6e, 0x6f, 0x07, 0x70, + 0x69, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x00, 0x00, 0x07, 0x61, 0x72, 0x64, + 0x75, 0x69, 0x6e, 0x6f, 0x0c, 0x64, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6c, + 0x57, 0x72, 0x69, 0x74, 0x65, 0x00, 0x00, 0x07, 0x61, 0x72, 0x64, 0x75, + 0x69, 0x6e, 0x6f, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x00, 0x02, 0x03, + 0x02, 0x01, 0x01, 0x05, 0x03, 0x01, 0x00, 0x01, 0x07, 0x13, 0x02, 0x06, + 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x06, 0x5f, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x00, 0x04, 0x0a, 0x3a, 0x01, 0x38, 0x01, 0x01, 0x7f, + 0x41, 0x80, 0x08, 0x10, 0x00, 0x22, 0x00, 0x36, 0x02, 0x00, 0x20, 0x00, + 0x41, 0x01, 0x10, 0x01, 0x03, 0x40, 0x41, 0x80, 0x08, 0x28, 0x02, 0x00, + 0x41, 0x01, 0x10, 0x02, 0x41, 0xe4, 0x00, 0x10, 0x03, 0x41, 0x80, 0x08, + 0x28, 0x02, 0x00, 0x41, 0x00, 0x10, 0x02, 0x41, 0x84, 0x07, 0x10, 0x03, + 0x0c, 0x00, 0x0b, 0x00, 0x0b +}; +unsigned int arduino_app_wasm_len = 197; diff --git a/platforms/arduino_blink/wasm/arduino_wasm_api.h b/platforms/arduino_blink/wasm/arduino_wasm_api.h new file mode 100644 index 0000000..0a3fa17 --- /dev/null +++ b/platforms/arduino_blink/wasm/arduino_wasm_api.h @@ -0,0 +1,30 @@ +#ifndef arduino_wasm_api_h +#define arduino_wasm_api_h + +#include + +#define WASM_EXPORT extern "C" __attribute__((used)) __attribute__((visibility ("default"))) +#define WASM_EXPORT_AS(NAME) WASM_EXPORT __attribute__((export_name(NAME))) +#define WASM_IMPORT(MODULE,NAME) __attribute__((import_module(MODULE))) __attribute__((import_name(NAME))) +#define WASM_CONSTRUCTOR __attribute__((constructor)) + +#define LOW 0x0 +#define HIGH 0x1 + +#define INPUT 0x0 +#define OUTPUT 0x1 +#define INPUT_PULLUP 0x2 + +extern "C" { + +WASM_IMPORT("arduino", "millis") uint32_t millis (void); +WASM_IMPORT("arduino", "delay") void delay (uint32_t ms); +WASM_IMPORT("arduino", "pinMode") void pinMode (uint32_t pin, uint32_t mode); +WASM_IMPORT("arduino", "digitalWrite") void digitalWrite (uint32_t pin, uint32_t value); + +// This is a convenience function +WASM_IMPORT("arduino", "getPinLED") uint32_t getPinLED (void); + +} + +#endif // arduino_wasm_api_h diff --git a/platforms/arduino_blink/wasm/arduino_wasm_api.syms b/platforms/arduino_blink/wasm/arduino_wasm_api.syms new file mode 100644 index 0000000..31d142b --- /dev/null +++ b/platforms/arduino_blink/wasm/arduino_wasm_api.syms @@ -0,0 +1,5 @@ +millis +delay +pinMode +digitalWrite +getPinLED diff --git a/platforms/arduino_blink/wasm/build.sh b/platforms/arduino_blink/wasm/build.sh new file mode 100755 index 0000000..260103d --- /dev/null +++ b/platforms/arduino_blink/wasm/build.sh @@ -0,0 +1,12 @@ +# Compile +wasicc -Os \ + -z stack-size=4096 -Wl,--initial-memory=65536 \ + -Wl,--allow-undefined-file=arduino_wasm_api.syms \ + -Wl,--strip-all -nostdlib \ + -o arduino_app.wasm arduino_app.cpp + +# Optimize (optional) +#wasm-opt -O3 arduino_app.wasm -o arduino_app.wasm + +# Convert to header +xxd -i arduino_app.wasm > arduino_app.wasm.h