Building & flashing Klipper firmware

Running Klipper means compiling a tiny firmware for your printer's microcontroller and flashing it onto the board. It sounds intimidating and it is genuinely simple — three commands and a copy — but one wrong setting in the menu silently bricks the boot. This is the HOW-TO, written from a real build.

Tool · make menuconfig Output · out/klipper.bin Flash · SD / DFU / BOOT0 AI angle · scripted, reproducible builds
TL;DR

You configure the build for your exact MCU with make menuconfig, run make to produce out/klipper.bin, and copy that file onto the board. The single biggest gotcha is the bootloader offset: most Creality and BigTreeTech boards ship with a bootloader that expects the application at 28KiB (0x7000), not Klipper's default 8KiB (0x2000). Pick the wrong offset and the flash succeeds but the board never boots.

What you're building

Klipper has two halves and you only compile one of them. The host half — the motion planner — already lives on your Raspberry Pi or other SBC; you installed it once and you update it with git. The MCU half is a small program that runs on the printer's own chip and does nothing but execute precisely timed step commands sent from the host. That MCU firmware is hardware-specific, so there is no universal binary: you build it for your board, then flash it.

Everything below happens on the host (the Pi), inside the Klipper source tree — usually ~/klipper. You compile there, then move the resulting binary to the printer board. The host and the MCU firmware are versioned together, which matters later (see The traps).

Step 1 — make menuconfig

From the Klipper directory, run make menuconfig. This opens a text menu where you describe the target board. Three choices matter:

Save and exit. menuconfig writes a .config file that drives the build. On our Creality 4.2.2 board the working answers were STM32F103, 28KiB offset (0x7000), and serial on USART1.

Step 2 — make

Run make. It compiles against the .config from the previous step and, on success, writes the firmware to out/klipper.bin (some targets produce out/klipper.uf2 or out/klipper.elf instead — RP2040 in particular emits UF2). If you change anything in menuconfig, run make clean before make to avoid a stale build. That out/klipper.bin is the entire deliverable; the next step is just getting it onto the board.

Step 3 — flash it

How you flash depends entirely on the board's bootloader. There are three paths you'll meet in practice, plus UF2 for RP2040.

The traps

Find the serial

Once the MCU is flashed and connected, the host needs to know where to reach it. The stable way is by-id, which survives reboots and port swaps:

ls /dev/serial/by-id/*

That prints a long, device-specific path. Copy it into printer.cfg under the [mcu] section as the serial: value, then restart Klipper. If by-id shows nothing, the board either didn't enumerate (wrong interface choice in Step 1) or didn't boot (wrong offset — back to The traps).

Links

This guide is distilled from a real 3d.2nth.ai build: ender-pi (github.com/2nth-ai/ender-pi), where we flash Klipper onto the stock Creality 4.2.2 board of a Creality Ender 3 V2 from a Raspberry Pi 4. The 28KiB-offset trap and the SD-card pickiness above are both lived experience from that build, not theory.

← More boards & controllers