Skip to content

Instantly share code, notes, and snippets.

@mnishiguchi
Last active August 31, 2025 05:06
Show Gist options
  • Select an option

  • Save mnishiguchi/6df85bcc93d62ba449dd430134d24d56 to your computer and use it in GitHub Desktop.

Select an option

Save mnishiguchi/6df85bcc93d62ba449dd430134d24d56 to your computer and use it in GitHub Desktop.
AtomVM Blinky on ESP32-S3 (Debian, 2025-07-31)

AtomVM Blinky on ESP32-S3 (Debian, 2025-07-31)

Let’s run a simple Elixir “Blinky” application on the Seeed Studio XIAO ESP32-S3 using AtomVM — a lightweight virtual machine for running Elixir and Erlang on microcontrollers.


Host Environment

This setup assumes a Debian-based Linux host with the following tools installed:

$ uname
Linux

$ elixir --version
Elixir 1.17.3 (compiled with Erlang/OTP 27)

$ python --version
Python 3.12.5

$ esptool version
esptool v5.0.1

$ picocom -h | head -n1
picocom v3.1

Note: esptool.py is now esptool (without .py) and uses hyphenated options (e.g. --chip, not --chip_esp32). The older syntax still works, but is deprecated.


Target Device

We are targeting:

This board:

  • Has native USB (no need for a USB-to-serial adapter)
  • Exposes its internal LED on GPIO21 (active-low)

Install Espressif IDF

AtomVM firmware is built using Espressif’s ESP-IDF. Here’s how to install it:

For more details and official instructions:

# Install system dependencies
sudo apt install git wget flex bison gperf cmake ninja-build \
  ccache libffi-dev libssl-dev dfu-util libusb-1.0-0

# Clone the ESP-IDF source
mkdir -p $HOME/esp && cd $_
git clone --recursive https://github.com/espressif/esp-idf.git
cd esp-idf

# Checkout a specific stable version (e.g. v5.5)
git checkout v5.4.2
git submodule update --init --recursive

# Install tools only for esp32s3
./install.sh esp32s3

# Add IDF environment to current shell
source ./export.sh

Build AtomVM Core

Now let’s fetch and build the AtomVM virtual machine and core libraries.

AtomVM source and release info:

# Clone AtomVM source
mkdir -p $HOME/Projects/atomvm && cd $_
git clone https://github.com/atomvm/AtomVM.git
cd AtomVM

# Checkout a stable release
git checkout v0.6.6

# Build the core VM
mkdir -p build && cd build
cmake ..
make -j$(nproc)

This compiles AtomVM's core (for desktop/host use) — not the ESP32 firmware yet.


Build AtomVM Firmware for ESP32-S3

Now let’s build the firmware for the actual ESP32-S3 target:

cd $HOME/Projects/atomvm/AtomVM/src/platforms/esp32

# Set up IDF in the shell
source $HOME/esp/esp-idf/export.sh

# Configure for ESP32-S3, then build
idf.py set-target esp32s3
idf.py reconfigure
idf.py build

This builds the full AtomVM firmware for the ESP32-S3: bootloader, partition table, VM binary, and Elixir stdlib.


Flash AtomVM Firmware + Core Libraries

You can now flash AtomVM to your device.

Step 1: Erase the Flash (Recommended)

This ensures no conflicting firmware or partitions remain.

esptool --chip auto --port /dev/ttyACM0 --baud 115200 erase-flash

This wipes the entire flash memory of the ESP32-S3.

Step 2: Flash AtomVM

cd $HOME/Projects/atomvm/AtomVM/src/platforms/esp32
source $HOME/esp/esp-idf/export.sh

idf.py -p /dev/ttyACM0 flash

Build the Elixir “Blinky” Example

Let’s compile the Elixir application that will blink the onboard LED.

cd $HOME/Projects/atomvm
git clone https://github.com/atomvm/atomvm_examples.git
cd atomvm_examples/elixir/Blinky

# Install dependencies (ExAtomVM)
mix deps.get

Edit the LED Pin

To make the on-board yellow LED (GPIO21) blink on your XIAO ESP32-S3, update the pin number in the Blinky module:

  • Open lib/blinky.ex
  • Change GPIO 2 to GPIO 21

The XIAO LED is active-low, so the LED turns ON when the pin is set to 0.

defmodule SampleApp do
  @pin 21

  def start() do
    :gpio.set_pin_mode(@pin, :output)
    loop(@pin, :low)
  end

  defp loop(pin, level) do
    :io.format(~c"Setting pin ~p ~p~n", [pin, level])
    :gpio.digital_write(pin, level)
    Process.sleep(1000)
    loop(pin, toggle(level))
  end

  defp toggle(:high), do: :low
  defp toggle(:low), do: :high
end

Compile and Pack

Now compile the Elixir code and package it into a .avm file:

mix atomvm.packbeam

ls -l *.avm

You should see something like Blinky.avm in the current directory.


Flash the “Blinky” App

Use the AtomVM Mix task to flash your .avm bundle to the ESP32-S3:

mix atomvm.esp32.flash --port /dev/ttyACM0 --baud 115200

You can repeat this step every time you modify your app — no need to reflash the firmware.


Monitor Serial Output

You can view AtomVM logs and Elixir output using either:

Option 1: idf.py monitor

cd $HOME/Projects/atomvm/AtomVM/src/platforms/esp32
source $HOME/esp/esp-idf/export.sh

idf.py --port /dev/ttyACM0 monitor

Press Ctrl+] to exit.

Option 2: picocom (simpler & works anywhere)

picocom /dev/ttyACM0 --baud 115200

To exit: Ctrl+A, then Ctrl+X


Quick Development Cycle

For future updates:

# Make changes to Elixir code
mix atomvm.packbeam
mix atomvm.esp32.flash --port /dev/ttyACM0

No need to rebuild or reflash the firmware unless you update AtomVM itself.

@mnishiguchi
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment