Skip to content

Instantly share code, notes, and snippets.

@mfikes
Last active January 9, 2020 09:06
Show Gist options
  • Save mfikes/a649ee58b3e9d5c8ecb91f3dbc6be224 to your computer and use it in GitHub Desktop.
Save mfikes/a649ee58b3e9d5c8ecb91f3dbc6be224 to your computer and use it in GitHub Desktop.

Loading :advanced Code into an Unmodified WROVER running Espruino

You can load ClojureScript :advanced code directly into an ESP32 WROVER running Espruino for execution upon boot, by creating a binary and flashing it to the JavaScript "boot ROM" area. This has the same effect as when loading code via the Espruino Web IDE, in the "Direct to Flash (execute code at boot)" mode, but flashing is much quicker and more reliable.

Note: To do this, you'll need an ESP32 WROVER with SPI PSRAM, as opposed to just a WROOM, as the ClojureScript in this example uses more RAM than is available in the WROOM.

Create :advanced Code

Here is a small program that uses enough to pull in data structures, etc, leading to nearly 100 KiB:

src/foo/core.cljs:

(ns foo.core)

(def m {:a 1, :b 2})

(js/print (reduce + (vals m)))

With deps.edn:

{:deps {org.clojure/clojurescript {:mvn/version "1.10.597"}}}

compile this program via

clj -m cljs.main -co '{:process-shim false}' -O advanced -c foo.core

Confirm that Espruino can run the resulting JavaScript by executing

espruino out/main.js

and confirming that it prints 3.

Note: Espruino doesn't support JavaScript labels, which GCC will emit along with break statements to these labels. These often look like a: and break a in the code. It turns out, this doesn't affect the above code. If you encounter this issue, it will look like Uncaught SyntaxError: Got ':' expected EOF in Espruino.

Create JavaScript Boot ROM Binary

In the above example wc -c out/main.js shows that the file is 96503 bytes.

Create the first 16 bytes of the boot ROM in a file that has the size of the file as the first word followed by a word of all FFs and then the ASCII for .bootcde. If you create this in a file named header.bin it will have contents that look like the following:

00000000  f7 78 01 00 ff ff ff ff  2e 62 6f 6f 74 63 64 65  |.x.......bootcde|

Note that, in the above f7 78 01 00 is little-endian for 0x000178f7, the file size 96503 in decimal.

Concatenate this header with your :advanced JavaScript to create the boot ROM binary:

cat header.bin out/main.js > main.bin

Flash the Boot ROM To your Espruino WROVER

esptool.py --chip esp32 --port PORT write_flash 0x2C0000 main.bin

In the above, replace PORT with your WROVER's serial port (something like /dev/cu.wchusbserial620).

Also note that, in the above, 0x2C0000 is the address for the JavaScript BOOT ROM code (js_code per the partition table).

Connect to Your ESP32 WROVER and Confirm

If you connect with the Espruino Web IDE or some other tool (say, screen), then you should see that your Espruino has printed 3.

If you press the hardware reboot button on your ESP32, you shold see that it reboots, loads the :advanced ClojureSript and executes it, printing 3 again in about 4 seconds.

Here are some memory diagnostics from the ESP32 after this:

>process.memory()
={ free: 13500, usage: 6500, total: 20000, history: 0,
  gc: 0, gctime: 121.427 }
>ESP32.getState()
={
  sdkVersion: "v3.1.3-dirty",
  freeHeap: 2629804, BLE: true, Wifi: true, minHeap: 2627732 }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment