Everything you need to get firmware CI running on your repo.
Visit github.com/apps/embedci/installations/new and grant access to the repositories you want to test.
Create a .embedci.yml file at the root of your repository. See the .embedci.yml reference below for all available options.
On every pull request, EmbedCI compiles your firmware, boots it in the Renode emulator, and posts a check run with pass/fail status directly on the PR.
| Field | Required | Default | Description |
|---|---|---|---|
board | yes | — | Zephyr board name (e.g. stm32f4_disco) |
app | no | . | Path to Zephyr app directory |
test | no | tests/smoke.robot | Path to Robot Framework test file |
mode | no | advisory | advisory | blocking. Advisory (Free) posts the verdict but never blocks the merge. Blocking (Team) makes EmbedCI a required check that stops the merge on failure. |
gates | no | — | Optional budget/quality thresholds. A violated gate fails the check. See Budget gates below. |
Minimal
board: stm32f4_disco
Full
board: stm32f4_disco app: ./firmware test: tests/smoke.robot
Gates turn metrics into enforcement. Add a gates: block to your .embedci.yml and any threshold you exceed will fail the check — even if the build and tests otherwise pass. Gates are fully opt-in: with no gates: block, nothing is enforced. A gate whose metric isn't available for a given build is skipped.
| Gate | Description |
|---|---|
flash_max_pct | Fail if flash usage exceeds this % of the region |
ram_max_pct | Fail if RAM usage exceeds this % of the region |
flash_max_bytes | Fail if flash usage exceeds N bytes |
ram_max_bytes | Fail if RAM usage exceeds N bytes |
stack_max_bytes | Fail if the worst-case stack frame exceeds N bytes |
flash_growth_bytes | Fail if flash grew more than N bytes vs the last build |
ram_growth_bytes | Fail if RAM grew more than N bytes vs the last build |
misra_max | Fail if MISRA findings exceed N |
warnings_max | Fail if static-analysis warnings exceed N |
coverage_min_pct | Fail if line coverage is below this % (when coverage is measured) |
board: stm32f4_disco gates: flash_max_pct: 95 ram_max_pct: 90 stack_max_bytes: 2048 flash_growth_bytes: 512 misra_max: 0
Powered by Renode — supports the most common embedded MCU families out of the box.
STM32 F-series
STM32 H/G/L-series
Nordic
NXP
Renesas
Microchip
Tests use Robot Framework with the renode-test library. The library provides keywords for controlling the Renode emulator — loading platform descriptions, loading your compiled ELF, and asserting on UART output.
Minimal smoke test
*** Settings *** Library renode-test *** Test Cases *** Boot check Execute Command mach create Execute Command machine LoadPlatformDescription @platforms/boards/stm32f4_discovery.repl Execute Command sysbus LoadELF @${ELF} Create Terminal Tester sysbus.usart2 Execute Command start Wait For Line On Uart Hello World
The ${ELF} variable is automatically injected by EmbedCI and points to the compiled firmware binary.
Asserting GPIO & registers
Beyond UART, EmbedCI ships a keyword resource at ${EMBEDCI_KEYWORDS} for asserting peripheral registers, memory, and GPIO pin state against the emulated hardware. Import it alongside the Renode keywords.
*** Settings *** Resource ${RENODEKEYWORDS} Resource ${EMBEDCI_KEYWORDS} *** Test Cases *** LED drives high ... # boot + load ELF as above Wait For Uart Line LED on Pin Should Be High 0x40020C14 12 # GPIOD ODR, pin 12 Register Should Be 0x40023830 0x8 # RCC clock enable
Available keywords: Wait For Uart Line, Read Memory Word, Memory Word Should Be, Read Register, Register Should Be, Register Bits Should Be Set, Pin Should Be High, Pin Should Be Low.
After each build, EmbedCI posts a GitHub check run on your pull request. The result means one of the following:
Firmware compiled successfully, booted in the emulator, and all Robot Framework assertions passed — including the UART output check.
Either the firmware failed to compile (build error), or it compiled but a test assertion failed — for example, expected UART output was never received.
The same verdict can either inform or enforce, set by mode in .embedci.yml:
mode: blocking and make EmbedCI a required status check; a failing verdict then actually blocks the merge.On Free, requesting mode: blocking (or running on a private repo) runs in advisory with an upgrade note — it never hard-fails your build.
Full build logs, compiler output, and Robot Framework test results are available in the Details link on the check run, directly on the pull request page. You can inspect failed assertions, UART traces, and the exact compiler error message without leaving GitHub.