Flashing firmware
Flash Pico (UF2), Arduino (arduino-cli), and Nucleo (probe-rs), plus device code read/write/exec.
This page covers how Revka puts firmware onto a microcontroller and how the agent reads, writes, and runs code on a board once it is online. Each board family uses a different flashing toolchain — the Raspberry Pi Pico flashes a UF2 over a mass-storage drive, the Arduino Uno uses arduino-cli, and the STM32 Nucleo uses probe-rs over its built-in ST-Link. The Arduino Uno Q is different again: it runs a Bridge app rather than taking a firmware flash.
All hardware features require the hardware Cargo feature at build time:
cargo build --release --features hardwareAfter you flash a board, register it so the GPIO tools can reach it — see GPIO tools and the supported boards reference. New to the hardware stack? Start with the hardware quickstart.
Raspberry Pi Pico (UF2)
Section titled “Raspberry Pi Pico (UF2)”The Pico is flashed by the LLM-callable pico_flash tool. It copies the embedded Revka MicroPython firmware (a UF2 image) onto the Pico in BOOTSEL mode, deploys main.py over mpremote, waits for the serial port to reappear, and reconnects the device transport — so GPIO commands work immediately without restarting the daemon.
Prerequisites
Section titled “Prerequisites”-
The
hardwarefeature compiled in. -
mpremoteinstalled:Terminal window pip install mpremote
Flash a Pico
Section titled “Flash a Pico”-
Hold the BOOTSEL button while plugging in the Pico. The
RPI-RP2drive mounts (a volume on macOS/Linux, a drive letter on Windows). -
Tell the agent to flash the board, for example: “Flash my Pico.”
-
The agent calls the tool with the safety gate set:
pico_flash(confirm=true) -
The tool copies the UF2, waits up to 20 seconds for the serial port, deploys
main.py, and reconnects the transport. On success it reports something like:Pico flashed and main.py deployed successfully. Firmware is online at/dev/cu.usbmodem101. pico0 is ready — you can use gpio_write immediately.
Parameters
| Parameter | Type | Required | Meaning |
|---|---|---|---|
confirm | boolean | yes | Must be true to proceed. Safety gate. |
Device code read / write / exec
Section titled “Device code read / write / exec”Once a MicroPython (or CircuitPython) device is online, three tools let the agent manage the program running on it. All three use mpremote, so pip install mpremote is required. The optional device parameter is auto-selected when exactly one device is registered.
Read current code (device_read_code)
Section titled “Read current code (device_read_code)”Reads the current main.py from the device. Run this before modifying device behavior.
device_read_code()device_read_code(device="pico0")Internally it runs mpremote connect <port> cat :main.py and returns the file contents. If main.py does not exist, it returns a friendly “no program yet” message rather than an error.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
device | string | no | Device alias; auto-selected if only one device is registered. |
Write code (device_write_code)
Section titled “Write code (device_write_code)”Writes a complete Python program to the device as main.py, then resets the board.
device_write_code( device="pico0", code="import machine, time\nled = machine.Pin(25, machine.Pin.OUT)\nwhile True:\n led.toggle()\n time.sleep(0.5)\n")Internally it copies the code to main.py over mpremote and resets the device, then waits up to 15 seconds for the serial port to reappear and reports whether reconnection succeeded.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
device | string | no | Device alias; auto-selected if only one device. |
code | string | yes | Complete program to write as main.py. Empty values are rejected. |
Run a one-off snippet (device_exec)
Section titled “Run a one-off snippet (device_exec)”Runs a Python snippet on the device without modifying main.py. The device keeps running its current program after the snippet completes. Use this for sensor reads, quick tests, and blink loops.
device_exec(code="print(machine.Pin(25).value())")Internally it runs mpremote connect <port> run <snippet> and returns captured output (including MicroPython stderr, such as exceptions). There is a 30-second timeout; an unresponsive device produces a descriptive timeout error. Empty code is rejected.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
device | string | no | Device alias; auto-selected if only one device. |
code | string | yes | Python snippet to execute; output is captured and returned. |
Arduino Uno (arduino-cli)
Section titled “Arduino Uno (arduino-cli)”The Arduino uses arduino-cli for both the one-time Revka firmware flash and per-sketch uploads.
Flash Revka firmware (revka peripheral flash)
Section titled “Flash Revka firmware (revka peripheral flash)”This CLI command flashes the embedded Revka firmware sketch to an Arduino Uno. It handles installing arduino-cli (via Homebrew on macOS), installing the AVR core, compiling the sketch, and uploading it. The firmware enables the capabilities, gpio_read, and gpio_write commands over serial.
# Explicit portrevka peripheral flash --port /dev/cu.usbmodem14301
# Or, if the board is already in config.tomlrevka peripheral flash| Flag | Type | Required | Meaning |
|---|---|---|---|
--port | string | no | Serial port. Auto-resolved from config.toml if omitted. |
Add the board to ~/.revka/config.toml after flashing:
[peripherals]enabled = true
[[peripherals.boards]]board = "arduino-uno"transport = "serial"path = "/dev/cu.usbmodem14301"baud = 115200Upload a custom sketch (arduino_upload)
Section titled “Upload a custom sketch (arduino_upload)”arduino_upload is an LLM-callable tool that compiles and uploads an agent-generated Arduino sketch — separate from the Revka firmware flash above. It is added automatically when a board named exactly arduino-uno is configured, and it uses that board’s configured path as the serial port.
The agent writes the full .ino sketch (both setup() and loop()) and passes it as code. Revka writes the sketch to a temp directory, then runs arduino-cli compile and arduino-cli upload against the arduino:avr:uno board.
arduino_upload(code="void setup() {\n pinMode(13, OUTPUT);\n}\nvoid loop() {\n digitalWrite(13, HIGH);\n delay(500);\n digitalWrite(13, LOW);\n delay(500);\n}\n")A natural-language trigger such as “Upload a blink sketch to the Arduino” causes the agent to generate the sketch and call the tool.
| Parameter | Type | Required | Meaning |
|---|---|---|---|
code | string | yes | Full .ino sketch content (complete file). Empty values are rejected. |
STM32 Nucleo (probe-rs)
Section titled “STM32 Nucleo (probe-rs)”The Nucleo-F401RE is flashed with probe-rs over the ST-Link debugger built into the board — no separate debug probe is needed. The CLI command builds the Embassy Rust firmware and flashes it. After flashing, the board speaks the Revka serial JSON protocol on USART2 (PA2/PA3), which is bridged to the ST-Link virtual COM port.
Prerequisites
Section titled “Prerequisites”Install the probe-rs CLI tools (note the crate is probe-rs-tools, not probe-rs):
cargo install probe-rs-tools --lockedFlash via Revka (revka peripheral flash-nucleo)
Section titled “Flash via Revka (revka peripheral flash-nucleo)”revka peripheral flash-nucleoThis builds firmware/nucleo and runs probe-rs run --chip STM32F401RETx. The firmware runs immediately after flashing.
Manual flash (equivalent)
Section titled “Manual flash (equivalent)”cd firmware/nucleocargo build --release --target thumbv7em-none-eabihfprobe-rs run --chip STM32F401RETx target/thumbv7em-none-eabihf/release/nucleoKey constants: chip STM32F401RETx, target triple thumbv7em-none-eabihf.
Find the serial port and configure
Section titled “Find the serial port and configure”After flashing, the Nucleo appears as a serial device:
/dev/cu.usbmodem* or /dev/tty.usbmodem* (for example /dev/cu.usbmodem101).
/dev/ttyACM0 (check dmesg after plugging in). If GPIO commands are ignored, add your user to the dialout group: sudo usermod -a -G dialout $USER, then log out and back in.
Add the board to ~/.revka/config.toml:
[peripherals]enabled = true
[[peripherals.boards]]board = "nucleo-f401re"transport = "serial"path = "/dev/cu.usbmodem101" # adjust to your portbaud = 115200Pin 13 = PA5 = the User LED (LD2) on the Nucleo-F401RE.
You can read chip info and memory maps from a Nucleo over USB/SWD without any firmware on the target by building with the probe feature (cargo build --features hardware,probe) and running revka hardware info. See supported boards for details.
Arduino Uno Q Bridge (setup-uno-q)
Section titled “Arduino Uno Q Bridge (setup-uno-q)”The Arduino Uno Q is not flashed in the usual sense. Its Linux side runs Revka, and GPIO control goes through a Bridge app — a Python + MCU socket server that listens on TCP port 9999 and exposes gpio_read / gpio_write from the Linux side to the MCU’s GPIO. The revka peripheral setup-uno-q command deploys the Bridge app via scp + arduino-app-cli.
# From your Mac (with the revka repo)revka peripheral setup-uno-q --host 192.168.0.48
# From the Uno Q itself (SSH'd in) — defaults to localhostrevka peripheral setup-uno-qThis copies the Bridge app (from firmware/uno-q-bridge/) to ~/ArduinoApps/uno-q-bridge and starts it.
| Flag | Type | Required | Meaning |
|---|---|---|---|
--host | string | no | IP address of the Uno Q. Defaults to localhost. |
After setup, register the board in config.toml with the bridge transport:
[peripherals]enabled = true
[[peripherals.boards]]board = "arduino-uno-q"transport = "bridge"With this configured, the standard gpio_read / gpio_write tools are transparently backed by the Bridge TCP socket (127.0.0.1:9999) instead of a serial port — the agent uses the same tool names. The Bridge must be running for these to work; setup-uno-q starts it. Connection timeout is 5 s and response timeout is 3 s; error responses from the Bridge are prefixed with error:.