Skip to content

One main.cpp. Any microcontroller.

A from-scratch C++23 framework for microcontrollers: write your app once, recompile it for a different board by changing one line — no #ifdef, no RTOS required, no IDE required. Mistakes are caught at compile time, in errors a beginner can read.

Get started Browse the guide View on GitHub

src/main.cpp — identical bytes on every supported board
#include <alloy/board.hpp>
using namespace alloy::literals;

int main() {
    board::init();
    while (true) {
        board::led.toggle();
        alloy::sleep_for(500ms);
    }
}
$ uv tool install alloy-embedded         # or: pipx install alloy-embedded
$ alloy new hello --board esp32_devkit && cd hello
$ alloy run                              # build + flash + serial monitor
$ alloy build --board nucleo_g071rb      # same code, different MCU — one flag

Why alloy

  • Truly portable


    The same main.cpp recompiles for another board by changing one config line. Portability comes from board roles and if constexpr (board::caps::x)zero preprocessor conditionals, enforced by CI.

    Portable code

  • Safe at compile time


    A wrong pin route is a compile error that names the pin, not a runtime surprise. Peripherals are selected by type, with no vtables and no heap — the zero-cost claim is real.

    Architecture

  • Trivially easy


    uv tool install alloy-embedded && alloy new && alloy run → a blinking LED in minutes. No IDE, no vendor code generator, no CMake to hand-write.

    Get started

  • Data-driven


    Facts are generated, behavior is hand-written. Adding a chip that reuses known peripheral IP costs data only — no new C++, no new emitter branches.

    Adding a board

  • Updatable in the field


    A/B firmware slots computed from chip data, a trial boot that rolls back on its own, and optional Ed25519-signed images — over a plain UART.

    Firmware update

  • Testable without hardware


    Firmware boots on an emulated MCU generated from the same chip data, and CI asserts on real UART output — drivers, coroutines and the whole update lifecycle.

    Emulation

Supported boards

The same 14-line main.cpp runs on all of these. The last column says how far each has actually been proven — a distinction alloy keeps everywhere.

Family Core Board Proven
ST STM32G0 Cortex-M0+ Nucleo-G0B1RE silicon I²C, ADC, DMA, PWM, RTC, DAC, CAN, watchdog, flash
ST STM32G0 Cortex-M0+ Nucleo-G071RB silicon PLL, GPIO, UART echo · 8 emulation gates
Microchip SAME70 Cortex-M7 SAM E70 Xplained silicon PLLA, PIO, USART, I²C, ADC, DMA, EEPROM, Ethernet
Espressif ESP32 Xtensa LX6 WROVER-KIT, DevKit silicon boot chain, UART, LEDC PWM
Raspberry Pi RP2040 2× Cortex-M0+ RP2040-Zero silicon boot2+CRC, 125 MHz clock, WS2812
ST STM32F7 Cortex-M7 Nucleo-F722ZE emulation boot + async runtime
Raspberry Pi RP2040 2× Cortex-M0+ Raspberry Pi Pico compiles hardware validation pending
ST STM32F7 Cortex-M7 Nucleo-F767ZI compiles the network examples only

What “silicon” means here

A commit reports the peripheral running on that named board, with observed register values or byte-level results. These are maintainer self-reports — there is no hardware CI runner. See the README for the per-family driver matrix.

Your board isn't listed?

alloy is designed so a new board is data, not code. See Adding a board — if it reuses a peripheral IP alloy already models, it costs zero new C++.

What you get

  • Peripherals: GPIO, UART, SPI, I²C, ADC, PWM, DMA, timers, watchdog, RTC, DAC, CAN, on-chip flash/NVM — coverage varies by family; GPIO and UART are everywhere, CAN and DAC are one chip.
  • Async without an RTOS: C++20 coroutines with no heap and no dynamic allocation.
  • A single CLI: new, build, flash, monitor, run, emulate, image, update, testsee all commands.
  • A driver ecosystem: sensors, displays and clocks you vendor with one command — grown outside the core, portable by construction.
  • Field updates: A/B slots, trial boot with automatic rollback, and signed images.
  • An IDE, if you want one: a VS Code extension with a visual pin/clock configurator — driven entirely by the CLI.
  • Host-testable app logic: the scheduler and drivers run on your laptop against fakes, so you unit-test without hardware.
  • CI that executes, not just compiles: firmware is booted under Renode and asserted on real UART output.