Embedded code that knows your hardware.
Volt is a typed language for microcontrollers. Realtime pin validation against your chip's datasheet before it builds, with built-in task parallelism and first-class state machines.
1hardware {2 pin led = 63 pin relay = 344 pin soil: Analog = 255}6setup {7 wifi.connect("home", "secret")8}9every 1s {10 relay.on()11 led.toggle()12 let v = soil.read()13} Scroll on, or run it yourself.
- led
ErrorFixed main.volt:2
GPIO 6 is connected to the SPI flash chip. Using it will crash the ESP32.
Available output pins: 2, 4, 5, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27, 32, 33
Moved from GPIO 6 to GPIO 2.
- relay
ErrorFixed main.volt:3
GPIO 34 is input-only — cannot be used as Output.
Input-only pins: 34-39.
Moved from GPIO 34 to GPIO 18.
- soil
WarningFixed main.volt:4
GPIO 25 is on ADC2, which is BLOCKED while WiFi is active. Analog reads will return errors or garbage.
Use ADC1 pins instead (GPIO 32-39) which work with WiFi.
Moved from GPIO 25 to GPIO 34.
1hardware {2 pin led = 23 pin motor: PWM = 44 pin battery: Analog = 355}67setup {8 wifi.connect("home", "secret") or retry(10)9 mqtt.connect("mqtt://broker.local") or retry(5)10}1112task blink {13 every 500ms { led.toggle() }14}1516task report {17 every 5s {18 mqtt.send_int("volt/battery", battery.read())19 }20}2122task drive {23 every 1ms strict { motor.set_pwm(512) }24} Write tasks. Volt decides how they run.
There is one task keyword. The compiler reads each body and picks the cheapest way to run it
safely, so a blink loop never pays for a FreeRTOS stack and a network call never stalls your motor control.
First-class state machines.
States, guards, timeouts and entry and exit actions are syntax, not a library. Doors reopen when the beam is broken, the emergency stop halts the car from any moving state, and the checker verifies every transition and flags states that can never be reached.
1// hardware, floor and call-button polling omitted2machine elevator {3 initial state idle {4 on target > floor -> going_up5 on target < floor -> going_down6 }78 state going_up {9 enter { motor_up.on() }10 exit { motor_up.off() }11 on estop.is_pressed() -> stopped12 on floor == target -> doors_open13 }1415 state going_down {16 enter { motor_down.on() }17 exit { motor_down.off() }18 on estop.is_pressed() -> stopped19 on floor == target -> doors_open20 }2122 state doors_open {23 enter { door_open.on() }24 exit { door_open.off() }25 after 5s -> doors_closing26 }2728 state doors_closing {29 enter { door_close.on() }30 exit { door_close.off() }31 on beam.is_pressed() -> doors_open32 after 3s -> idle33 }3435 state stopped {36 on reset.is_pressed() -> idle37 }38} Pins that look free. Aren't.
Under the module's metal can, the SPI flash that stores your program is wired to GPIO 6–11. The DevKitC breaks them out as CLK, D0–D3 and CMD. They look like free pins. Wire anything to one and the ESP32 crashes the moment it tries to read its own code.
Volt checks every pin against the datasheet and stops you before you build:
-- HARDWARE ERROR -- main.volt:2
GPIO 6 is connected to the SPI flash chip.
Using it will crash the ESP32. Coming from Arduino or ESP-IDF
From Arduino
setup works the way you expect. Timed blocks like every 500ms replace
millis() bookkeeping, and they run side by side without you writing a scheduler.
From ESP-IDF
Volt builds on ESP-IDF and FreeRTOS. You keep native performance and stop maintaining task handles, stack sizes and pin-mux tables by hand.
The toolchain
- volt
- One binary to check, build, flash and monitor. No Python to install.
- Volt IDE
- Live diagnostics as you type, formatting, and a hardware panel for wiring pins and devices.
- VoltGrid
- A registry of signed, reviewed device libraries you can add to a project.