#prusawire #einsy #klipper #avr #atmega2560 #atmega32u2 #usbasp #avrdude #3d-printing
# Overview
How to get Klipper running on a Prusa-sourced **Einsy RAMBo 1.1a** — the board in [[erikbuild - Prusawire PW.0011 - Thoth Station]] — with a Raspberry Pi 4 host. The Einsy carries two AVRs: the **ATmega2560** that runs the printer, and an **ATmega32u2** that is only a USB-to-serial bridge. Prusa ships the 32u2 with firmware that corrupts serial traffic under Klipper's protocol, so the job has two halves:
1. Reflash the 32u2 with the PrusaOwners *hoodserial* firmware using a **USBasp** programmer — the method Chris Warkocki worked out and nikolak wrote up. Four commands, no soldering, no auto-reset tricks.
2. Build and flash Klipper onto the 2560 over plain USB through the stock bootloader — no programmer needed for that half.
Scope: USBasp only. The PrusaOwners README's default is an Arduino Uno running ArduinoISP; that and Pi-GPIO (`linuxspi`) routes are not covered here.
# Resources
- [[Prusawire]] — parent build note
- [[Prusawire Software Installation and Configuration]] — Mainsail/Klipper host install and Prusawire config; it stops at "if you're on the Einsy you're done", which is where this note picks up
- [[Prusawire NeoPixel Pico MCU And Level Shifting]] — why the Einsy's spare pins and AVR timing pushed the LEDs onto a KB2040
- [[How to Klipper on Prusa MK3S+]] — clipping of nikolak's post: the USBasp procedure below, plus a known-good MK3S config
- [[PrusaOwnersmk3-32u2-firmware Updated Atmega 32u2 Firmware for the Einsy Rambo]] — clipping of the upstream README (wiring tables, commands, firmware background)
- [nikolak — How to: Klipper on Prusa MK3S/+](https://nikolak.com/klipper-on-prusa-mk3s/) — source of the four-command USBasp procedure
- [Chris Warkocki — Stock Prusa MK3S Klipper (Patreon)](https://www.patreon.com/chriswarkocki/posts/stock-prusa-mk3s-48015680) — original write-up nikolak credits; ==Patreon is blocked from here, so this note relays it via nikolak==
- [PrusaOwners/mk3-32u2-firmware](https://github.com/PrusaOwners/mk3-32u2-firmware) — the fixed 32u2 firmware, USBasp pin table, background
- [USBasp — fischl.de](https://www.fischl.de/usbasp/) — the original design; clone jumper functions are described here
- [DollaTek USBasp (Amazon B07DK5M7LZ)](https://www.amazon.com/DollaTek-USBASP-USBasp_H6-Programmer-Support/dp/B07DK5M7LZ) — the ~$5 clone nikolak used; any 16c0:05dc clone with the 10→6 pin adapter works
- [Einsy Rambo 1.1a schematic (PDF)](https://raw.githubusercontent.com/ultimachine/Einsy-Rambo/1.1a/board/Project%20Outputs/Schematic%20Prints_Einsy%20Rambo_1.1a.PDF) — sheet 4 "USB-Serial" has X17 and the isolator
- [Klipper `generic-einsy-rambo.cfg`](https://github.com/Klipper3d/klipper/blob/master/config/generic-einsy-rambo.cfg) · [Klipper Installation](https://www.klipper3d.org/Installation.html) · [Klipper Bootloaders](https://www.klipper3d.org/Bootloaders.html)
- [charminULTRA 32u2 Hoodserial Flash Guide](https://github.com/charminULTRA/Klipper-Input-Shaping-MK3S-Upgrade/blob/main/32u2-Hoodserial-Flash-Guide.md) — 2026 write-up (also USBasp) with before/after `bytes_invalid` numbers and measured fuses
- [avrdude programmer definitions (`avrdude.conf.in`)](https://github.com/avrdudes/avrdude/blob/main/src/avrdude.conf.in) — `usbasp` vs `usbasp-clone`
# Design
## The two chips and why the 32u2 must be reflashed
| Chip | Role | Package / location | Programmed via |
|---|---|---|---|
| ATmega2560 | Runs Marlin or Klipper | Big 100-pin QFP, board centre | USB, through the stock STK500v2 bootloader (`avrdude -c wiring`) |
| ATmega32u2 | USB↔serial bridge only | Small chip beside the USB-B jack | ISP header **X17** ("32u2 ICSP") — the only 2×3 header on the board |
Klipper's own config says it plainly: *"The Einsy boards sold by Prusa have defective firmware on the usb-to-serial chip that make the boards unusable with Klipper (boards sold by Ultimaker do not have this issue)."* Prusa knows — PrusaSlicer ships a patched avrdude that avoids sending semicolons inside data packets because of the same bug.
**Symptom under Klipper:** `bytes_invalid` and `bytes_retransmit` climb steadily in the klippy.log stats lines, ending in `Lost communication with MCU 'mcu'` — often mid-print. One documented case went from 468,627 invalid bytes after a 75-minute print to 0 after the reflash. Check with:
```bash
grep bytes_invalid ~/printer_data/logs/klippy.log | tail -5
```
## What the replacement firmware is
`DFU-hoodserial-combined-PrusaMK3-32u2.hex` from PrusaOwners = **hoodserial** (a port of Nico Hood's HoodLoader2 USB-serial, with Urja Rannikko's fastserial) + a **DFU bootloader** in the top 4 KiB. Points that matter:
- USB identity is unchanged: VID `2c99`, PID `0002`, product string "Original Prusa i3 MK3". The printer's **serial number is read from the 32u2's EEPROM**, which is why the fuse dance below protects EEPROM.
- hoodserial wires **DTR → 2560 reset**, so both `avrdude -c wiring` and Klipper's `restart_method: arduino` keep working.
- Prusa/Marlin firmware still works over USB afterwards, and PrusaSlicer can still flash the 2560. The change is reversible (see [[#Reverting to Prusa firmware]]).
- The DFU bootloader is resident, but entering it needs the 32u2's **HWB pin held low during reset**, which the Einsy does not break out conveniently. ==In practice, any future 32u2 reflash still goes through ISP.==
## Why the programmer can power the target
X17 pin 2 is **USBVCC**, pin 6 is **GND1** — the 32u2's own power island, fed from the USB jack. An **ADUM7441** digital isolator sits between that island and the board's 5 V SMPS rail / 2560. So with the printer PSU off and no USB cable, the USBasp's 5 V powers exactly the 32u2, its crystal, and the USB side of the isolator — it cannot backfeed the rest of the board. This is why the procedure runs with the printer completely unpowered.
## Programmer: USBasp
A USBasp is a ~$5 ATmega8-based ISP dongle (Thomas Fischl's open design, cloned everywhere). It shows up as USB `16c0:05dc`, needs no driver on Linux, and — unlike an Arduino running ArduinoISP — has no serial port and therefore no auto-reset to defeat. Clones ship with a 10-pin IDC ribbon and a **10→6 pin adapter**; the 6-pin end is the standard AVR ISP layout, which is exactly what X17 is.
| Function | Typical clone label | Setting for the Einsy |
|---|---|---|
| Target voltage / power select | `JP1` (5V/3.3V) or a `VCC` jumper | **5 V** — the 32u2 island is 5 V and the USBasp must supply it |
| Self-programming (update the USBasp's own firmware) | `JP2` | **open** |
| Slow SCK (< 1.5 MHz targets) | `JP3` | **open** — the 32u2 runs at 16 MHz. Close it only if `target doesn't answer` persists |
==Silkscreen labels differ between clones; identify the jumpers by function on the board in hand.==
**10-pin USBasp connector → Einsy X17** (from the PrusaOwners README):
| USBasp 10-pin | Signal | Einsy X17 pin |
|---|---|---|
| 1 | MOSI | 4 |
| 2 | VCC | 2 |
| 4 | GND | 6 |
| 5 | RESET | 5 |
| 7 | SCK | 3 |
| 9 | MISO | 1 |
With the 10→6 adapter you don't wire any of that: the 6-pin socket maps 1 MISO · 2 VCC · 3 SCK · 4 MOSI · 5 RESET · 6 GND, same as X17. Only pin-1 orientation matters.
# Configuration
## Part 1 — Reflash the 32u2 with a USBasp
### 1. Prepare the USBasp and the Pi
1. Set the USBasp's voltage/power jumper to **5 V**; leave self-program and slow-SCK open.
2. On the Pi 4:
```bash
sudo apt-get install avrdude
lsusb | grep -i 16c0
# Bus 001 Device 00x: ID 16c0:05dc Van Ooijen Technische Informatica shared ID for use with libusb
```
The `16c0:05dc` line is the USBasp. Commands below use `sudo` because the clone's USB device isn't group-accessible by default (a udev rule is the tidy alternative).
### 2. Connect the USBasp to X17
Everything unplugged: printer PSU off, no USB cable on the Einsy, USBasp not yet in the Pi.
X17 is the 2×3 header immediately to the right of the USB-B jack (USB jack at the top). Pin 1 (MISO) is top-left, pin 2 (5 V) top-right; rows go 3/4, then 5/6. The PrusaOwners wiring photo shows the header: [einsy_uno.png](https://raw.githubusercontent.com/PrusaOwners/mk3-32u2-firmware/master/images/einsy_uno.png).
- Plug the adapter's 6-pin socket onto X17 with its **pin 1 (red ribbon stripe / triangle) on X17 pin 1**. Rotated 180° puts 5 V on GND1 and RESET on SCK — nothing fatal with the board unpowered, but the target won't answer.
- ==Meter adapter pin 2 → USB-B VBUS and pin 6 → USB shield ground once seated. Cheap adapters have been found miswired.==
- Then plug the USBasp into the Pi. The 32u2 island powers up from the programmer.
### 3. Back up the stock 32u2
```bash
mkdir -p ~/mk3_32u2_backup && cd ~/mk3_32u2_backup
sudo avrdude -p m32u2 -F -P usb -c usbasp-clone \
-U flash:r:firmware_backup.hex:i -U eeprom:r:eeprom.hex:i \
-U lfuse:r:lowfuse:h -U hfuse:r:highfuse:h -U efuse:r:exfuse:h -U lock:r:lockfuse:h
```
- `-c usbasp-clone` matches any device with the USBasp VID/PID regardless of its USB strings; plain `-c usbasp` insists on Fischl's `www.fischl.de` / `USBasp` strings, which many clones don't carry. `-P usb` is a placeholder — the usbasp driver ignores the port.
- `avrdude: warning: cannot set sck period. please check for usbasp firmware update.` is normal on clone firmware; ignore it.
- `-F` skips the signature check; still **read the signature line**. ATmega32U2 is `0x1e 0x95 0x8a`. If you see `0x1e 0x98 0x01` (that's a 2560), all zeros, or all 0xFF, stop — wrong header, rotated connector, or a bad wire.
- Expected stock fuses: lfuse `0xEF`, hfuse `0xD9`, efuse `0xF4`, lock `0xCF`. The EEPROM dump is the valuable part (serial number lives there). If the flash read times out, fuses + EEPROM are what matter.
### 4. Flash hoodserial
```bash
# 1. Enable EESAVE first so the chip erase does not wipe the serial number
sudo avrdude -p m32u2 -F -P usb -c usbasp-clone -U hfuse:w:0xD1:m
# 2. Fetch the combined DFU + hoodserial image
wget https://raw.githubusercontent.com/PrusaOwners/mk3-32u2-firmware/master/hex_files/DFU-hoodserial-combined-PrusaMK3-32u2.hex
# 3. Write it and put the fuses back to stock (hfuse 0xD9 = EESAVE off again)
sudo avrdude -p m32u2 -F -P usb -c usbasp-clone \
-U flash:w:DFU-hoodserial-combined-PrusaMK3-32u2.hex \
-U lfuse:w:0xFF:m -U hfuse:w:0xD9:m -U efuse:w:0xF4:m
```
These are nikolak's four commands verbatim (backup, EESAVE, fetch, flash). Order matters: 0xD1 before the flash write, 0xD9 after. Because the final state has EESAVE off, **any later reflash must set 0xD1 first again** or the serial number is gone. lfuse moves `0xEF → 0xFF`; efuse stays `0xF4` (HWBE on, which is what makes the DFU bootloader reachable via HWB).
### 5. Verify
Unplug the USBasp from the Pi, then lift the adapter off X17. Plug the Einsy's USB into the Pi (PSU can stay off — USB powers the 32u2):
```bash
dmesg | tail -n 20
# idVendor=2c99, idProduct=0002 ... Product: Original Prusa i3 MK3
# SerialNumber: <your serial, unchanged> ... cdc_acm ... ttyACM0
ls -l /dev/serial/by-id/
# usb-Prusa_Research__prusa3d.com__Original_Prusa_i3_MK3_<SERIAL>-if00 -> ../../ttyACM0
```
If the serial number is intact and it enumerates as `cdc_acm`, the 32u2 is done.
## Part 2 — Klipper on the ATmega2560
No programmer involved. Prusa's 2560 bootloader is their edition of the standard STK500v2 "wiring" bootloader at `0x3E000`, which is exactly what Klipper's `make flash` targets.
### Build
```bash
cd ~/klipper && make menuconfig
```
- Micro-controller Architecture: **Atmega AVR**
- Processor model: **atmega2560**
- Defaults are already correct: 16 MHz, UART0, 250000 baud. They're only visible after ticking *Enable extra low-level configuration options*; if you look, confirm **UART0** (UART1 would be the Pi GPIO header path).
`Q`, `Y`, then `make`.
### Flash
```bash
ls /dev/serial/by-id/*
sudo service klipper stop
make flash FLASH_DEVICE=/dev/serial/by-id/usb-Prusa_Research__prusa3d.com__Original_Prusa_i3_MK3_<SERIAL>-if00
sudo service klipper start
```
Under the hood that is `avrdude -patmega2560 -cwiring -P<dev> -D -Uflash:w:out/klipper.elf.hex:i` at 115200, with DTR/RTS bouncing the 2560 into its bootloader — which only works because hoodserial passes DTR through. A successful run writes ~41 KB and verifies.
### `[mcu]`
```ini
[mcu]
serial: /dev/serial/by-id/usb-Prusa_Research__prusa3d.com__Original_Prusa_i3_MK3_<SERIAL>-if00
# restart_method: default 'arduino' (DTR toggle) works with hoodserial.
# Community MK3S configs set 'command'; either is valid over USB.
```
Klipper's `generic-einsy-rambo.cfg` ships only `serial: /dev/ttyACM0`; use the by-id path so a USB re-enumeration (e.g. the KB2040 from [[Prusawire NeoPixel Pico MCU And Level Shifting]] grabbing `ttyACM0`) doesn't swap devices. Prusawire-specific pins and macros come from the [Positron3D config](https://github.com/Positron3D/prusawire-klipper-config) per [[Prusawire Software Installation and Configuration]].
Kalico builds for `atmega2560` identically (same `make menuconfig` path, same `generic-einsy-rambo.cfg` present in its tree); AVR is not deprecated there.
## Reverting to Prusa firmware
With hoodserial in place, the 2560 flashes back the normal way: PrusaSlicer → *Configuration → Flash Printer Firmware* with the `.hex` from Prusa's downloads, or `avrdude -p atmega2560 -c wiring -P <dev> -b 115200 -D -U flash:w:<prusa>.hex:i`. Nothing about the 32u2 needs to change; leave hoodserial on it.
## Fallback only: ISP-flashing the 2560
Only relevant if the 2560's bootloader is ever destroyed. There is no separate 2560 ICSP header on a 1.1a — its SPI lines are on **J19 pins 9–14** (MISO J19-9, SCK J19-11, MOSI J19-12). ==Which J19 pin carries the 2560's nRESET is unverified — trace from the schematic (sheet 5) before trying.== Bootloader hex: [prusa3d/stk500v2-prusa](https://github.com/prusa3d/stk500v2-prusa). ==Prusa's shipped 2560 fuse bytes are undocumented; UltiMachine's RAMBo-family values are lfuse 0xFF / hfuse 0xD0 / efuse 0xFD / lock 0x0F.==
# Build Log
## 2026-09-21
- Researched the 32u2 fix and the USB path for the 2560; wrote this note.
- Confirmed from the 1.1a schematic (sheet 4): X17 is the 32u2 ICSP, pin 2 = USBVCC, pin 6 = GND1, pin 5 = RESET2, and the ADUM7441 isolates that island from the SMPS rail. Programmer-powered flashing is safe by design.
- First draft used an Arduino Mega 2560 as an ArduinoISP programmer. Replaced with the USBasp method from nikolak / Chris Warkocki: no reset-capacitor dance, plugs straight onto X17 via the 10→6 adapter, and it's the procedure most MK3S Klipper converts have actually run.
- ==Not yet flashed — Thoth Station's current 32u2 state is unknown. First step is the `bytes_invalid` check above.==
# Decisions
- **Decision**: USBasp as the ISP programmer.
- **Why**: It is the method Chris Warkocki documented and nikolak verified — four commands. No serial port means no DTR auto-reset to suppress, so none of the 10 µF-capacitor fiddling an Arduino-as-ISP needs. The bundled 10→6 adapter mates directly with X17. ~$5.
- **Alternatives**: Arduino Uno with ArduinoISP (the PrusaOwners README default; needs six jumpers and a reset cap); an Arduino Mega 2560 the same way (hardware SPI on D50/51/52, reset from D10 — considered, dropped); avrdude `linuxspi`/`linuxgpio` straight from the Pi 4 header.
- **Decision**: `-c usbasp-clone -P usb`, as nikolak wrote it.
- **Why**: Clone dongles usually lack Fischl's USB strings, so `-c usbasp` may refuse to find the device. `usbasp-clone` is the same driver minus the string match. If a given dongle does carry the strings, either works.
- **Decision**: Flash the 2560 over USB via the stock bootloader, never via ISP.
- **Why**: The bootloader is there and `make flash` uses it. ISP on the 2560 means J19 pin-hunting and re-burning a bootloader for no gain.
# Troubleshooting
- **Symptom**: `avrdude: error: could not find USB device with vid=0x16c0 pid=0x5dc vendor='www.fischl.de' product='USBasp'`.
- **Cause**: Used `-c usbasp` with a clone that has blank USB strings — or the dongle isn't visible (permissions, bad USB cable, dead clone).
- **Fix**: `-c usbasp-clone`; confirm with `lsusb | grep 16c0`; run under `sudo` or add a udev rule.
- **Symptom**: `avrdude: warning: cannot set sck period. please check for usbasp firmware update.`
- **Cause**: Clone firmware predates the settable-SCK feature.
- **Fix**: None needed. It proceeds normally.
- **Symptom**: `error: program enable: target doesn't answer. 1` / `initialization failed, rc=-1`.
- **Cause**: Adapter rotated 180° on X17, a miswired adapter, target unpowered (voltage jumper not supplying 5 V), or a pin not seated.
- **Fix**: Re-seat with pin 1 on pin 1; meter pins 2 and 6; check the jumper. As a last resort close the slow-SCK jumper and retry.
- **Symptom**: Signature reads `0x1e9801`, `0x000000`, or `0xffffff`.
- **Cause**: Wrong header (that first one is the 2560), connector rotated, or MISO/MOSI swapped in a hand-made cable.
- **Fix**: Stop; `-F` only suppresses the check, it does not make the write land somewhere sane. Re-verify X17 pin 1 orientation against the photo and meter pins 2/6.
- **Symptom**: `make flash` (or PrusaSlicer) times out with `stk500v2_ReceiveMessage(): timeout` immediately after the 32u2 reflash.
- **Cause**: 32u2 hasn't been fully power-cycled since the new firmware went on.
- **Fix**: Unplug USB *and* the printer PSU, wait, reconnect, retry. Reported and resolved in PrusaOwners issue #1.
- **Symptom**: Flash *read* during the backup hangs or times out.
- **Cause**: Slow ISP link / cheap clone.
- **Fix**: Make sure `eeprom.hex` and the four fuse files were captured; those are what restore the serial. Retry the flash read separately if you want it.
- **Symptom**: Still seeing `Lost communication with MCU` or climbing `bytes_invalid` after hoodserial.
- **Cause**: The 32u2 is no longer the suspect — look at the USB cable, Pi power supply, EMI from stepper/heater wiring near the USB run, or host overload (`Timer too close`).
- **Fix**: Different cable, ferrite, reroute; check `klippy.log` for which error it actually is.
# TODO
- ==Check Thoth Station's klippy.log for `bytes_invalid` / `bytes_retransmit` to learn whether its 32u2 already carries hoodserial (VID/PID/product string are identical either way, so `dmesg` won't tell).==
- ==Get a USBasp with the 10→6 adapter if none is on hand (DollaTek B07DK5M7LZ or any 16c0:05dc clone).==
- ==Identify the voltage / self-program / slow-SCK jumpers on the actual dongle and set 5 V before first use.==
- ==Meter adapter pins 2 / 6 on X17 before plugging the USBasp into the Pi.==
- ==Find the 32u2 HWB test point on the 1.1a (would allow DFU updates without ISP).==
- ==Trace J19's 2560 nRESET pin from schematic sheet 5 (fallback ISP path).==
# References
- [[Prusawire]] · [[erikbuild - Prusawire PW.0011 - Thoth Station]] · [[Prusawire Software Installation and Configuration]] · [[Prusawire NeoPixel Pico MCU And Level Shifting]]
- [[How to Klipper on Prusa MK3S+]] · [[PrusaOwnersmk3-32u2-firmware Updated Atmega 32u2 Firmware for the Einsy Rambo]]
- [nikolak — Klipper on Prusa MK3S/+](https://nikolak.com/klipper-on-prusa-mk3s/) · [Chris Warkocki — Patreon post](https://www.patreon.com/chriswarkocki/posts/stock-prusa-mk3s-48015680)
- [PrusaOwners/mk3-32u2-firmware README](https://github.com/PrusaOwners/mk3-32u2-firmware) · [issue #1 (post-flash stk500v2 timeout)](https://github.com/PrusaOwners/mk3-32u2-firmware/issues/1) · [`hoodserial.c` (DTR→reset)](https://github.com/PrusaOwners/mk3-32u2-firmware/blob/master/hoodserial/hoodserial.c) · [`Descriptors.c` (serial from EEPROM)](https://github.com/PrusaOwners/mk3-32u2-firmware/blob/master/hoodserial/Descriptors.c)
- [USBasp — fischl.de](https://www.fischl.de/usbasp/) · [avrdude.conf.in (`usbasp`, `usbasp-clone`)](https://github.com/avrdudes/avrdude/blob/main/src/avrdude.conf.in)
- [Einsy Rambo 1.1a schematic](https://raw.githubusercontent.com/ultimachine/Einsy-Rambo/1.1a/board/Project%20Outputs/Schematic%20Prints_Einsy%20Rambo_1.1a.PDF) · [ultimachine/Einsy-Rambo issue #2 (2560 ISP on J19)](https://github.com/ultimachine/Einsy-Rambo/issues/2) · [RepRap EinsyRambo development](https://reprap.org/wiki/EinsyRambo_development)
- [Klipper `generic-einsy-rambo.cfg`](https://github.com/Klipper3d/klipper/blob/master/config/generic-einsy-rambo.cfg) · [`src/avr/Makefile`](https://github.com/Klipper3d/klipper/blob/master/src/avr/Makefile) · [Bootloaders](https://www.klipper3d.org/Bootloaders.html) · [Config Reference `[mcu]`](https://www.klipper3d.org/Config_Reference.html#mcu)
- [prusa3d/stk500v2-prusa](https://github.com/prusa3d/stk500v2-prusa) · [PrusaSlicer `FirmwareDialog.cpp`](https://github.com/prusa3d/PrusaSlicer/blob/master/src/slic3r/GUI/FirmwareDialog.cpp)
- [Klipper Discourse: MCU disconnect sadness (MK3S)](https://klipper.discourse.group/t/mcu-disconnect-sadness/1396) · [charminULTRA 32u2 flash guide](https://github.com/charminULTRA/Klipper-Input-Shaping-MK3S-Upgrade/blob/main/32u2-Hoodserial-Flash-Guide.md)
- [KalicoCrew/kalico `src/avr/Kconfig`](https://github.com/KalicoCrew/kalico/blob/main/src/avr/Kconfig)