An avrdude-style command-line flasher for FTDI and LGT programmers.
About Β· Getting Started Β· Usage Β· Deutsch
- About the project β Built with Β· Features
- Getting started β Prerequisites Β· Build
- Usage β Programmers Β· Wiring Β· Examples Β· Verbosity
- avrdude compatibility
- Known limitations
- Testing
- Roadmap
- Contributing
- Licence
- Acknowledgments
ftdude is a single, self-contained command-line tool that flashes AVR microcontrollers through FTDI USB interface chips (and the register-compatible LGT8F328P), speaking a subset of the familiar avrdude CLI. It rolls what used to be several separate FTDI flash tools into one binary: -c picks the programmer and transport, -p the part, and -U flash:β¦ / -U eeprom:β¦ the operation.
Unlike avrdude, ftdude needs no avrdude.conf and no external configuration β the part catalogue and fuse tables are built in. It deliberately covers FTDI and LGT over SPI-ISP and LGT-SWD only; it is not a full avrdude replacement (see avrdude compatibility).
- C11 β no runtime dependencies beyond the FTDI drivers
- CMake (>= 3.15) β Windows (MSVC), Linux, Raspberry Pi (aarch64)
- FTDI D2XX (
ftd2xx) and LibFT4222 β vendor SDKs, placed alongside the sources
- Flash write / read / verify in Intel-HEX and raw binary
- EEPROM write / read / verify, with read-diff (only changed bytes are written)
- Fuse read plus model-specific decode for ~199 AVR types; set fuse bits by name (
--fuses-set EESAVE=0) - Signature read, chip erase, dry-run (
-n), quiet (-q), configurable ISP clock (-B) - Multiple
-Uoperations per invocation; clean stdout/stderr separation, avrdude-style - Auto-detect: with exactly one FTDI attached,
-cmay be omitted - Six transports: MPSSE-SPI, FT232R sync-bitbang and FT4222 hardware SPI (AVR-ISP); LGT-SWD over each of those
- An FTDI-based interface: an FT232H cable (e.g. C232HD), an FT2232H / FT4232H(A), an HP-series chip (FT2x3xHP / FT4x3xHP), an FT2232D, an FT232R(N) / FT245R(N) / UM232R, or a UMFT4222EV board.
- The FTDI D2XX driver and the LibFT4222 SDK.
- A C toolchain and CMake >= 3.15.
Place the vendor SDKs next to the sources (as in the ft4222 reference layout):
ft4222/libft4222.h + ft4222/windows/dll/{amd64,x86}/...
ftd2xx/ftd2xx.h + ftd2xx/win/{AMD64,x86}/...
On Linux / Raspberry Pi, install D2XX and LibFT4222 (headers to /usr/local/include, libraries to /usr/local/lib).
cmake -S . -B build -A x64 # Windows (MSVC)
cmake --build build --config Debug
cmake -S . -B build # Linux / Raspberry Pi
cmake --build build
The executable lands in build/Debug/ftdude.exe (Windows) or build/ftdude (Linux). If your FTDI SDK lives elsewhere on Linux, pass -DFT4222_ROOT=/path.
ftdude [-c <prog>] -p <part> [--sck <kHz>] [-F] -U <mem>:<op>:<file>[:<fmt>]
-p selects the part (or -p ? to list all ~199; omit it to auto-detect by signature). <mem> is flash | eeprom | lfuse | hfuse | efuse | lock | signature, <op> is w | r | v, and <fmt> is i (Intel-HEX, default), r (raw binary), h/d/b/o (fuse/signature values) or m (immediate).
Convenience flags: --flash / --verify (auto-detect input), --dump (Intel-HEX output), --flash-bin / --dump-bin (raw binary), --flash-srec / --dump-srec (Motorola S-record), --flash-elf (ELF, read-only), --eeprom / --eeprom-verify / --eeprom-dump, --fuses, --fuses-set NAME=0|1 β¦, --id, --erase. Plus -D (no auto-erase), -n (dry-run), -q (quiet), -B <clock>. --json streams machine-readable NDJSON results on stdout (for scripts/GUIs); the human log stays on stderr.
-c |
Transport |
|---|---|
mpsse / c232hd / ft2232 / ft4232 / ft2232d |
AVR-ISP via MPSSE-SPI (FT232H / FT2232H / FT4232H(A) / HP series / FT2232D) |
bitbang / um232r / ft232r / ft245r |
AVR-ISP via sync-bitbang (FT232R/RN, FT245R/RN, UM232R) |
ft4222 |
AVR-ISP via FT4222 hardware SPI |
lgt / c232hd_lgt |
LGT8F328P via SWD (MPSSE-GPIO) |
lgtfast |
LGT8F328P via SWD, MPSSE shift-reads (fast verify; different wiring) |
lgt232r |
LGT8F328P via SWD on FT232R sync-bitbang |
lgt4222 |
LGT8F328P via SWD on FT4222 GPIO (novelty; very slow) |
C232HD cable to AVR ICSP (3.3 V):
| C232HD wire | Signal | ICSP pin |
|---|---|---|
| orange | SCK | 3 |
| yellow | MOSI | 4 |
| green | MISO | 1 |
| brown | RESET | 5 |
| red | VCC | 2 |
| black | GND | 6 |
The standard C232HD-DDHSP-0 red wire is 5 V VBUS; power 3.3 V-only targets externally.
Full C232HD wire β ADBUS reference (pad numbers and colours per FTDI datasheet FT_000430). The UART names are how the datasheet labels the pads; the pins are plain ADBUS lines in MPSSE mode. The I/O pins are 3.3 V cells, 5 V-tolerant.
| Pad | Colour | UART name | ADBUS | mpsse ISP |
lgt |
lgtfast |
|---|---|---|---|---|---|---|
| 1 | red | VCC | β | VCC | VCC | VCC |
| 2 | orange | TXD | AD0 | SCK | SWC | SWC |
| 3 | yellow | RXD | AD1 | MOSI | SWD | SWD (bridged) |
| 4 | green | RTS# | AD2 | MISO | RSTN | SWD (bridged) |
| 5 | brown | CTS# | AD3 | RESET | free | RSTN |
| 6 | grey | DTR# | AD4 | free | free | free |
| 7 | purple | DSR# | AD5 | free | free | free |
| 8 | white | DCD# | AD6 | free | free | free |
| 9 | blue | RI# | AD7 | free | free | free |
| 10 | black | GND | β | GND | GND | GND |
Grey (DTR# / AD4) is unused by every transport β the natural pin for a status LED (below).
The stock C232HD has red/green LEDs in the connector hood, but they are wired to the FT232H's TXLED#/RXLED# outputs, which are UART-mode activity signals: they do not pulse on MPSSE (SPI/SWD) traffic, and they are not on the flying leads, so they cannot indicate flashing.
For a driveable status light, wire an LED (+ ~330 Ξ© to GND) to a spare ADBUS lead β grey (DTR# / AD4) is free on every transport. Because AD4 rides in the same MPSSE Set Data Bits Low Byte word as SCK/MOSI/SWD, it can be toggled per phase (e.g. blink on erase, solid on write, solid on verify-OK, fast blink on error) with exact timing and no EEPROM changes. Output drive strength is EEPROM-selectable (4/8/12/16 mA, default 4 mA) via FT_PROG.
Plug-and-play alternative without soldering: use an FT232H / FT2232H breakout board instead of the cable. There the ACBUS pins (C0βC7) are broken out on headers and driveable in software (FT232H high byte via Set Data Bits High Byte, or the free second channel on an FT2232H), so an LED β or an existing on-board user LED β drops straight onto a header pin.
(--led <pin> covers all transports since 1.8.0-alpha.7: 4-7 / ad4-ad7 = MPSSE ADBUS (low byte), ac0-ac7 = MPSSE ACBUS via Set Data Bits High Byte (H-series; FT2232D only AC0β3; rejected on FT4232H β no high byte), d4-d7 = FT232R sync-bitbang, g0-g3 = FT4222 GPIO (ft4222: g0βg2, GPIO3 is RESET; lgt4222: g3 only). Invalid pin/transport pairings fail at open with a clear message. The default build stays byte-identical when --led is absent.)
Per-interface status-LED options. The stock TX/RX LEDs are UART-only on every device, but each interface exposes free, software-driveable pins:
| Interface (chip) | Transports | Free driveable pins | Driven via |
|---|---|---|---|
| FT232H (C232HD, breakout) | mpsse lgt lgtfast |
AD4βAD7, plus all ACBUS AC0βAC7 | Set Data Bits Low / High Byte |
| FT2232H (mini-module, breakout) | mpsse/ft2232 lgt lgtfast |
AD4β7, AC0β7, and the entire second channel | low/high byte; channel B separate |
| FT4232H / FT4232HA | mpsse/ft4232 lgt lgtfast |
AD4β7 of the active channel (no high byte), + 3 other channels | low byte; other channels separate |
| FT2232D | mpsse/ft2232d (ISP only) |
AD4β7, AC0β3 (12-bit port), + channel B | low byte + 4-bit high byte |
| FT232R/RN, FT245R/RN, UM232R | bitbang lgt232r |
D4βD7 (in the sync-bitbang byte) | direction mask + output byte |
| FT4222H (UMFT4222EV) | ft4222 lgt4222 |
ft4222: g0βg2 (GPIO3 = RESET) Β· lgt4222: g3 |
FT4222 GPIO API (not MPSSE) |
| HP series (232HP/233HP/2232HP/4232HP) | as their non-HP twins | as above per type | as above |
The H-series expose ACBUS via Set Data Bits High Byte (0x82); FT4232H has no per-channel high byte (low byte only). The FT2232H is the most convenient β ftdude drives only channel A, so channel B's 16 pins are entirely free for an independent LED. FT4222H is the odd one out: no MPSSE, so a LED there runs through the FT4222 GPIO API on its own code path.
Phase patterns (since 1.8.0-alpha.8): during flash/EEPROM operations the LED signals the phase via the flash layer's set_led hook β solid on while erasing, one toggle per page while writing, half rate while verifying, quarter rate while reading. A successful run ends with the LED dark; a verify error latches it on until the run ends. Outside these operations (e.g. --id) the plain activity heartbeat of alpha.1 remains, decimated on buses where a toggle costs its own command (ACBUS 1/8, FT4222 GPIO 1/32). Erase, write and verify are thus distinguishable at a glance on the bench.
CBUS on the FT232R β removed in 1.8.0-alpha.12. alpha.9 offered --led c0-c3 to drive the FT232R's on-board TX/RX LEDs (wired to CBUS0/CBUS1) via CBUS bit-bang (FT_SetBitMode mode 0x20), no soldering. A bench test killed it: the FT232R holds only one bit-mode at a time, and CBUS bit-bang (0x20) is mutually exclusive with the sync-bitbang mode (0x04) that carries ISP. Switching to CBUS to update the LED drops the sync-bitbang engine β and RESET with it β so programming enter/verify fails at the first LED write (all-zero reads, no 0x53 echo). That is an FT232R architecture limit, not a tuning issue, so the pin spec was removed; --led c0-c3 now prints a one-line pointer to this note. Use d4-d7 instead (a free pin in the sync-bitbang byte, driven in-band β that path is bench-verified). A solderless on-board-LED option exists only on the FT2232H/breakout boards, where the LED sits on an ACBUS or second-channel pin reachable in-band via MPSSE.
bitbangβ FT232R / UM232R to AVR ICSP: TXD(D0)=SCK->3, RXD(D1)=MOSI->4, RTS#(D2)=MISO->1, CTS#(D3)=RESET->5, VIO->2 (VCC), GND->6. FT232R bitbang caps at roughly 0.5-1 MHz SCK.ft4222β UMFT4222EV (Mode 0) to AVR ICSP, 3.3 V: JP5.9=SCK->3, JP5.7=MOSI->4, JP5.8=MISO->1, JP4.7=GPIO3=RESET->5, JP5.2=VOUT3V3->2 (VCC), JP4.3=GND->6. Set jumper JP8 1-2 for 3.3 V I/O.lgtβ C232HD to LGT8F328P (SWD): orange=SWC, yellow=SWD (bidirectional), green=RSTN, red=VCC, black=GND.lgtfastβ C232HD to LGT8F328P (SWD), fast verify: orange=SWC, yellow and green both to SWD (bridged, no resistor), brown=RSTN, red=VCC, black=GND. The MPSSE shift-in samples ADBUS2, so SWD must reach ADBUS1 (drive) and ADBUS2 (sense); RESET therefore moves to ADBUS3.
The role assignment never changes: MPSSE uses xDBUS0=SCK, xDBUS1=MOSI, xDBUS2=MISO, xDBUS3=RESET; sync-bitbang uses D0=SCK, D1=MOSI, D2=MISO, D3=RESET. Physical IC pins per package:
| Chip (package) | SCK | MOSI | MISO | RESET |
|---|---|---|---|---|
| FT232H (48 LQFP/QFN) | 13 | 14 | 15 | 16 |
| FT2232H (64) β channel A / B | 16 / 38 | 17 / 39 | 18 / 40 | 19 / 41 |
| FT4232HΒ·HA (64) β A / B | 16 / 26 | 17 / 27 | 18 / 28 | 19 / 29 |
| FT4232H-56Q β A / B | 12 / 22 | 13 / 23 | 14 / 24 | 15 / 25 |
| FT2232D (48 LQFP) β channel A | 24 | 23 | 22 | 21 |
| FT233HP (64 LQFP/QFN) | 28 | 29 | 30 | 31 |
| FT232HP (56 QFN) | 23 | 24 | 25 | 26 |
| Chip (SSOP-28) | SCK (D0) | MOSI (D1) | MISO (D2) | RESET (D3) |
|---|---|---|---|---|
| FT232R / FT232RN | TXD = 1 | RXD = 5 | RTS# = 3 | CTS# = 11 |
| FT245R / FT245RN | D0 = 1 | D1 = 5 | D2 = 3 | D3 = 11 |
FT2232D caveat: its ADBUS pin order runs backwards (24β21) compared to the FT2232H (16β19). Wiring from H-series muscle memory swaps SCK and RESET. (FT232RN in QFN-32: TXD=30, RXD=2, RTS#=32, CTS#=8.)
FT4222H (QFN-32, chip mode 0) β the ft4222 transport uses the SPI master plus GPIO3:
| Role | Signal | IC pin | UMFT4222EV |
|---|---|---|---|
| SCK | SCK | 8 | JP5.9 |
| MOSI | MOSI | 10 | JP5.7 |
| MISO | MISO | 9 | JP5.8 |
| RESET | GPIO3 | 16 | JP4.7 |
Complete header maps for the four boards this project meets most often, in the same column scheme as the C232HD table above: one role column per transport, verified against the FTDI board datasheets (document numbers in the sources line). Every connector pin is listed individually under its real designation (CN2-7, CN3-9, JP5-1 β¦); rows follow the connector's pin order, so the scrambled runs (AC1 before AC0, BD1 before BD0) are visible. "free" = the transport could drive the pin but doesn't; "β" = a supply, status or other-channel pin outside the transport's reach. Every possible channel is listed.
FT2232H Mini Module. Two MPSSE channels: channel A on CN2, channel B on CN3 β both can do ISP/SWD. ftdude opens channel A by default; select channel B by its device index with -P. Bus power needs two straps: VBUSβVCC (CN3-1 to CN3-3) and V3V3βVIO (CN2-1/3/5 to CN2-11, CN2-21, CN3-12, CN3-22).
CN2 β channel A (ADBUS + ACBUS):
| CN pin | Signal | mpsse ISP | lgt | lgtfast |
|---|---|---|---|---|
| CN2-1 | V3V3 | 3V3 | 3V3 | 3V3 |
| CN2-2 | GND | GND | GND | GND |
| CN2-3 | V3V3 | 3V3 | 3V3 | 3V3 |
| CN2-4 | GND | GND | GND | GND |
| CN2-5 | V3V3 | 3V3 | 3V3 | 3V3 |
| CN2-6 | GND | GND | GND | GND |
| CN2-7 | AD0 | SCK | SWC | SWC |
| CN2-8 | RESET# | β | β | β |
| CN2-9 | AD2 | MISO | RSTN | SWD (bridged) |
| CN2-10 | AD1 | MOSI | SWD | SWD (bridged) |
| CN2-11 | VIO | VIO | VIO | VIO |
| CN2-12 | AD3 | RESET | free | RSTN |
| CN2-13 | AD5 | free | free | free |
| CN2-14 | AD4 | free | free | free |
| CN2-15 | AD7 | free | free | free |
| CN2-16 | AD6 | free | free | free |
| CN2-17 | AC1 | free | free | free |
| CN2-18 | AC0 | free | free | free |
| CN2-19 | AC3 | free | free | free |
| CN2-20 | AC2 | free | free | free |
| CN2-21 | VIO | VIO | VIO | VIO |
| CN2-22 | AC4 | free | free | free |
| CN2-23 | AC6 | free | free | free |
| CN2-24 | AC5 | free | free | free |
| CN2-25 | SUSPEND# | β | β | β |
| CN2-26 | AC7 | free | free | free |
AD4βAD7 are the --led 4-7 pins, AC0βAC7 the --led ac0-ac7 pins. RESET# (CN2-8) resets the FT2232H itself β not the target RESET; SUSPEND# is a status output.
CN3 β channel B (BDBUS + BCBUS, supply, EEPROM):
| CN pin | Signal | mpsse ISP | lgt | lgtfast |
|---|---|---|---|---|
| CN3-1 | VBUS | β | β | β |
| CN3-2 | GND | GND | GND | GND |
| CN3-3 | VCC | β | β | β |
| CN3-4 | GND | GND | GND | GND |
| CN3-5 | CS | β | β | β |
| CN3-6 | CLK | β | β | β |
| CN3-7 | DATA | β | β | β |
| CN3-8 | PWREN# | β | β | β |
| CN3-9 | BC7 | free | free | free |
| CN3-10 | BC6 | free | free | free |
| CN3-11 | BC5 | free | free | free |
| CN3-12 | VIO | VIO | VIO | VIO |
| CN3-13 | BC4 | free | free | free |
| CN3-14 | BC3 | free | free | free |
| CN3-15 | BC2 | free | free | free |
| CN3-16 | BC1 | free | free | free |
| CN3-17 | BC0 | free | free | free |
| CN3-18 | BD7 | free | free | free |
| CN3-19 | BD6 | free | free | free |
| CN3-20 | BD5 | free | free | free |
| CN3-21 | BD4 | free | free | free |
| CN3-22 | VIO | VIO | VIO | VIO |
| CN3-23 | BD3 | RESET | free | RSTN |
| CN3-24 | BD2 | MISO | RSTN | SWD (bridged) |
| CN3-25 | BD1 | MOSI | SWD | SWD (bridged) |
| CN3-26 | BD0 | SCK | SWC | SWC |
The channel-B roles apply once you open channel B via -P; by default (channel A active) all of CN3 is free β ideal for an independent LED. BD4βBD7 are then the low-byte --led pins, BC0βBC7 the high-byte ones. CS/CLK/DATA belong to the configuration EEPROM (leave unconnected).
FT4232H Mini Module. Of the four channels only A and B can do MPSSE β and both sit on CN2. Channel A is the default, select channel B with -P; exactly one channel is active per run. Same bus-power straps as the FT2232H module. The chip has no high byte β --led ac* is rejected at open; the LED pins are AD4βAD7 (channel A) or BD4βBD7 (channel B).
CN2 β channels A and B (both MPSSE-capable):
| CN pin | Signal | mpsse ISP | lgt | lgtfast |
|---|---|---|---|---|
| CN2-1 | V3V3 | 3V3 | 3V3 | 3V3 |
| CN2-2 | GND | GND | GND | GND |
| CN2-3 | V3V3 | 3V3 | 3V3 | 3V3 |
| CN2-4 | GND | GND | GND | GND |
| CN2-5 | V3V3 | 3V3 | 3V3 | 3V3 |
| CN2-6 | GND | GND | GND | GND |
| CN2-7 | AD0 (ch A) | SCK | SWC | SWC |
| CN2-8 | RESET# | β | β | β |
| CN2-9 | AD2 (ch A) | MISO | RSTN | SWD (bridged) |
| CN2-10 | AD1 (ch A) | MOSI | SWD | SWD (bridged) |
| CN2-11 | VIO | VIO | VIO | VIO |
| CN2-12 | AD3 (ch A) | RESET | free | RSTN |
| CN2-13 | AD5 (ch A) | free | free | free |
| CN2-14 | AD4 (ch A) | free | free | free |
| CN2-15 | AD7 (ch A) | free | free | free |
| CN2-16 | AD6 (ch A) | free | free | free |
| CN2-17 | BD1 (ch B) | MOSI | SWD | SWD (bridged) |
| CN2-18 | BD0 (ch B) | SCK | SWC | SWC |
| CN2-19 | BD3 (ch B) | RESET | free | RSTN |
| CN2-20 | BD2 (ch B) | MISO | RSTN | SWD (bridged) |
| CN2-21 | VIO | VIO | VIO | VIO |
| CN2-22 | BD4 (ch B) | free | free | free |
| CN2-23 | BD6 (ch B) | free | free | free |
| CN2-24 | BD5 (ch B) | free | free | free |
| CN2-25 | SUSPEND# | β | β | β |
| CN2-26 | BD7 (ch B) | free | free | free |
The mpsse column doubles as ft4232. RESET# (CN2-8) is the chip reset, not the target RESET.
CN3 β channels C and D (UART/bit-bang only):
| CN pin | Signal | mpsse ISP | lgt | lgtfast |
|---|---|---|---|---|
| CN3-1 | VBUS | β | β | β |
| CN3-2 | GND | GND | GND | GND |
| CN3-3 | VCC | β | β | β |
| CN3-4 | GND | GND | GND | GND |
| CN3-5 | CS | β | β | β |
| CN3-6 | CLK | β | β | β |
| CN3-7 | DATA | β | β | β |
| CN3-8 | PWREN# | β | β | β |
| CN3-9 | DD7 | β | β | β |
| CN3-10 | DD6 | β | β | β |
| CN3-11 | DD5 | β | β | β |
| CN3-12 | VIO | VIO | VIO | VIO |
| CN3-13 | DD4 | β | β | β |
| CN3-14 | DD3 | β | β | β |
| CN3-15 | DD2 | β | β | β |
| CN3-16 | DD1 | β | β | β |
| CN3-17 | DD0 | β | β | β |
| CN3-18 | CD7 | β | β | β |
| CN3-19 | CD6 | β | β | β |
| CN3-20 | CD5 | β | β | β |
| CN3-21 | CD4 | β | β | β |
| CN3-22 | VIO | VIO | VIO | VIO |
| CN3-23 | CD3 | β | β | β |
| CN3-24 | CD2 | β | β | β |
| CN3-25 | CD1 | β | β | β |
| CN3-26 | CD0 | β | β | β |
Channels C and D can't do MPSSE β so they're out of reach for ftdude's transports ("β"). They remain usable as GPIO for other tools.
UMFT4222EV. Mode 0 for ftdude: JP2 and JP3 each in position 2-3 (DCNF0 = DCNF1 = 0). Bus power: JP9 fitted (default); 3.3 V I/O: JP8 fitted (VOUT3V3βVCCIO).
JP5 β SPI side:
| JP pin | Signal | ft4222 ISP | lgt4222 |
|---|---|---|---|
| JP5-1 | VCCIO | VCCIO | VCCIO |
| JP5-2 | VOUT3V3 | VCC | VCC |
| JP5-3 | GND | GND | GND |
| JP5-4 | IO3 | free | free |
| JP5-5 | IO2 | free | free |
| JP5-6 | GND | GND | GND |
| JP5-7 | MOSI | MOSI | free |
| JP5-8 | MISO | MISO | free |
| JP5-9 | SCK | SCK | free |
| JP5-10 | GND | GND | GND |
| JP5-11 | RESET# | β | β |
| JP5-12 | GND | GND | GND |
JP4 β GPIO side:
| JP pin | Signal | ft4222 ISP | lgt4222 |
|---|---|---|---|
| JP4-1 | VBUS | β | β |
| JP4-2 | VCCIN | β | β |
| JP4-3 | GND | GND | GND |
| JP4-4 | GPIO0 | free | SWC |
| JP4-5 | GPIO1 | free | SWD |
| JP4-6 | GPIO2 | free | RSTN |
| JP4-7 | GPIO3 | RESET | free |
| JP4-8 | GND | GND | GND |
| JP4-9 | SS0O | β | β |
| JP4-10 | BCD_DET | free | free |
| JP4-11 | SS | β | β |
| JP4-12 | GND | GND | GND |
ft4222 LED pins: --led g0-g2 (GPIO0βGPIO2); lgt4222: --led g3 (GPIO3). GPIO2 ships as SUSP_OUT and is freed at open. VOUT3V3 delivers β€ 100 mA in total; RESET# (JP5-11) is the chip reset, not the target RESET. SS0O is the hardware chip select (unused); tie SS high in master mode per the datasheet.
UM232R (24-pin DIP). J2 fitted = bus powered (default); J1 in position 1-2 = 3.3 V I/O.
| DIP pin | Signal | bitbang ISP | lgt232r |
|---|---|---|---|
| 1 | TXD = D0 | SCK | SWC |
| 2 | DTR# = D4 | free | free |
| 3 | RTS# = D2 | MISO | free |
| 4 | VIO | VIO | VIO |
| 5 | RXD = D1 | MOSI | SWD |
| 6 | RI# = D7 | free | free |
| 7 | GND | GND | GND |
| 8 | DSR# = D5 | free | free |
| 9 | DCD# = D6 | free | free |
| 10 | CTS# = D3 | RESET | RSTN |
| 11 | CB4 | β | β |
| 12 | CB2 | β | β |
| 13 | SLD | β | β |
| 14 | USB | β | β |
| 15 | VCC | β | β |
| 16 | PU2 | β | β |
| 17 | PU1 | β | β |
| 18 | CB3 | β | β |
| 19 | 3V3 | 3V3 | 3V3 |
| 20 | RST# | β | β |
| 21 | VCC | β | β |
| 22 | CB1 | β | β |
| 23 | CB0 | β | β |
| 24 | GND | GND | GND |
D4βD7 are the --led d4-d7 pins. The CBUS pins (CB0βCB4) sit on the DIP pins, but ftdude can't drive them β --led c0-c3 was removed in alpha.12 (see the status-LED section); the UM232R has no on-board LEDs anyway. VIO sets the I/O level (J1 1-2 = 3.3 V) and doubles as the target-VCC tap; RST# is the chip reset, not the target RESET; PU1/PU2 are for self-power only; 3V3 sources β€ 50 mA.
The tables above say which pin is what; these sketches show where it sits. The FTDI side of the wiring is in the C232HD table / header maps above; here is the target side.
AVR ICSP and Arduino Nano (mpsse / bitbang transports):
AVR 6-pin ISP (2x3, 2.54 mm) -- top view, pin 1 = square pad
+---------+
MISO | 1 2 | VCC
SCK | 3 4 | MOSI
RST# | 5 6 | GND
+---------+
Arduino Nano (ATmega328P) -- the SCK/MISO/MOSI trio and the on-board ICSP
digital side on-board 6-pin ICSP (end opposite USB)
D13 = SCK +---------+
D12 = MISO MISO | 1 2 | VCC (+5V)
D11 = MOSI SCK | 3 4 | MOSI
RST = RESET RST# | 5 6 | GND
5V / GND +---------+
LGT8F328P board (lgt / lgt232r / lgt4222 transports):
LGT8F328P "Nano-style" (LQFP32 MiniEVB) -- programmed via SWC/SWD, NOT via ISP
Long sides match the Arduino Nano; SWC + SWD are extra pins,
usually a small group near one end (silk varies by vendor):
+----------------------+
| ... D13 GND ... |
| |
| [SWC] [SWD] | <- extra pins (sometimes 4-pin with VCC/GND)
+----------------------+
ftdude SWD wiring (lgt / lgt232r / lgt4222):
SWC -> board SWC
SWD -> board SWD (bidirectional)
RSTN -> board RST
VCC -> board 5V / VCC GND -> board GND
The exact SWC/SWD location differs between vendors (Nano, UNO, Pro-Mini, Micro form factors) β check the silkscreen before wiring. The UNO-like AZ-Delivery boards sometimes don't break SWC/SWD out at all.
The three lgt* routes use fixed lines (defined at the top of each transport source file):
| Route | SWC | SWD (bidirectional) | RSTN |
|---|---|---|---|
lgt (MPSSE, H series only) |
ADBUS0 | ADBUS1 | ADBUS2 |
lgtfast (MPSSE, H series only) |
ADBUS0 | ADBUS1 + ADBUS2 (bridged) | ADBUS3 |
lgt232r (FT232R/RN) |
D0 = TXD (SSOP pin 1, UM232R pin 1) | D1 = RXD (SSOP pin 5, UM232R pin 5) | D3 = CTS# (SSOP pin 11, UM232R pin 10) |
lgt4222 (FT4222H) |
GPIO0 = pin 13 (JP4.4) | GPIO1 = pin 14 (JP4.5) | GPIO2 = pin 15 (JP4.6) |
lgtfast is the same protocol as lgt but reads flash through the MPSSE shift engine (one command per byte instead of one GPIO read per bit), so verify runs several times faster. The shift-in samples TDI (ADBUS2), which is why SWD is bridged across ADBUS1+ADBUS2 and RESET moves to ADBUS3 β a small rewire versus lgt. Writes stay GPIO-bitbanged and are unchanged. New in 1.7.0; hardware-verify a known image before relying on it. Best over a USB hub (direct laptop ports can glitch the unbuffered high-Z read windows).
For bare H-series chips, reuse the first three signal columns of the MPSSE table above (SCK column = SWC, MOSI column = SWD, MISO column = RSTN); ADBUS3 stays free. LGT-SWD runs on the H series only, not on the FT2232D. GPIO2 of the FT4222H ships configured as SUSP_OUT β ftdude frees the pin on open via SetSuspendOut.
Header maps for the FT2232H/FT4232H Mini Modules, the UMFT4222EV and the UM232R are above; other breakouts label their headers with the xDBUS signal names, so the role table is all you need there. The FT4233HP/FT4232HP and FT2233HP/FT2232HP IC pin numbers were not cross-checked here β see DS_FT4233HP / DS_FT2233HP, section 3.4. Sources: DS_FT232H, DS_FT2232H, DS_FT4232H (FT_000060), DS_FT2232D, FT233HP/FT232HP datasheet (FT_001484), DS_FT232RN, DS_FT245R(N), DS_FT4222H, AN_184 (FT_000507), DS_UMFT4222EV (FT_001057), DS_FT2232H_Mini_Module (FT_000114), DS_FT4232H_Mini_Module (FT_000115), DS_UM232R (FT_000051).
Pin bit assignments are defined at the top of each transport source file and are easy to change.
All examples use -p m328p (ATmega328P) β swap in your part (ftdude -p ? lists ~199). -c is optional when exactly one FTDI is attached; otherwise pick a transport (ftdude -c ?).
Flash, verify, read.
# Auto-detect the FTDI, flash and verify (Intel-HEX in; verify is implied)
ftdude -p m328p --flash blink.hex
# Explicit programmer + ISP clock (-B is an alias for --sck)
ftdude -c c232hd -p m328p --sck 1MHz --flash blink.hex
# Verify only (no write); dump flash to Intel HEX
ftdude -c c232hd -p m328p --verify blink.hex
ftdude -c c232hd -p m328p --dump backup.hex
# Skip the auto-verify; keep existing flash (no auto chip-erase, avrdude -D)
ftdude -c c232hd -p m328p --flash blink.hex --no-verify
ftdude -c c232hd -p m328p -D --flash patch.hex
# Progress bar; quiet (errors only); dry-run (writes nothing)
ftdude -c c232hd -p m328p --flash blink.hex --progress
ftdude -c c232hd -p m328p --flash blink.hex -q
ftdude -c c232hd -p m328p -n --flash blink.hex
File formats (a = auto-detect on input, the default; output defaults to Intel HEX).
# Raw binary in / out
ftdude -c c232hd -p m328p --flash-bin firmware.bin
ftdude -c c232hd -p m328p --dump-bin backup.bin
# Motorola S-record in / out
ftdude -c c232hd -p m328p --flash-srec firmware.srec
ftdude -c c232hd -p m328p --dump-srec backup.srec
# ELF straight from avr-gcc (input only) β auto-detected, or forced
ftdude -c c232hd -p m328p --flash firmware.elf
ftdude -c c232hd -p m328p --flash-elf firmware.elf
# Same operations, avrdude-style -U with an explicit format field
ftdude -c c232hd -p m328p -U flash:w:firmware.bin:r # write raw binary
ftdude -c c232hd -p m328p -U flash:v:blink.hex:i # verify Intel HEX
ftdude -c c232hd -p m328p -U flash:r:backup.srec:s # read -> S-record
Fuses (AVR only).
# Read lfuse / hfuse / efuse / lock
ftdude -c c232hd -p m328p --fuses
# Write one fuse by value (dedicated flag, or -U with immediate m)
ftdude -c c232hd -p m328p --lfuse 0xE2
ftdude -c c232hd -p m328p -U hfuse:w:0xD9:m
# Read one fuse to stdout (hex); set bits by name (safer than raw values)
ftdude -c c232hd -p m328p -U hfuse:r:-:h
ftdude -c c232hd -p m328p --fuses-set EESAVE=0 SPIEN=0
EEPROM (AVR-ISP only β the LGT emulates EEPROM in flash).
# Write (auto-verify, no chip erase), read, verify
ftdude -c c232hd -p m328p --eeprom data.eep
ftdude -c c232hd -p m328p --eeprom-dump eeprom.hex
ftdude -c c232hd -p m328p --eeprom-verify data.eep
# Flash and EEPROM in one run (executed in order)
ftdude -c c232hd -p m328p --flash fw.hex --eeprom data.eep
Signature, erase, listings.
ftdude -c c232hd -p m328p --id # read + report signature
ftdude -c c232hd -p m328p --erase # chip erase only
ftdude -c c232hd -p m328p -U signature:r:-:h # signature -> stdout (hex)
ftdude -p ? # list ~199 parts
ftdude -c ? # list all programmers
ftdude --version
Status LED β a spare pin signals the phase during flash/read/verify (see Status LED for wiring). The bus depends on the chip:
ftdude -c c232hd -p m328p --led ad4 --flash fw.hex # MPSSE ADBUS (FT232H/2232H)
ftdude -c c232hd -p m328p --led ac0 --flash fw.hex # MPSSE high byte (H-series only)
ftdude -c bitbang -p m328p --led d4 --flash fw.hex # FT232R sync-bitbang byte
ftdude -c ft4222 -p m328p --led g0 --flash fw.hex # FT4222 GPIO
Transport / chip specific.
# FT2232H / FT4232H: select channel B by its device index (channel A is default)
ftdude -c ft2232 -P 1 -p m328p --flash fw.hex # channel B = BDBUS on CN3
ftdude -c ft4232 -P 1 -p m328p --flash fw.hex # channel B = BDBUS on CN2
# FT2232C/D (12 MHz MPSSE base clock)
ftdude -c ft2232d -p m328p --id
# FT245R parallel adapter (SPI on D0..D3 instead of TXD/RXD/RTS/CTS)
ftdude -c ft245r -p m328p --flash fw.hex
# FT4222H hardware SPI
ftdude -c ft4222 -p m328p --flash fw.hex
# Machine-readable NDJSON on stdout (human log stays on stderr) β for scripts / GUIs
ftdude -c c232hd -p m328p --flash fw.hex --json
LGT8F328P (proprietary one-wire SWD, not ARM-SWD).
ftdude -c lgt -p m328p --flash fw.hex # via MPSSE-GPIO (C232HD)
ftdude -c lgtfast -p m328p --flash fw.hex # same, MPSSE shift-reads -> much faster verify
ftdude -c lgt232r -p m328p --id # via FT232R sync-bitbang (verify slow)
ftdude -c lgt4222 -p m328p --id # via FT4222 GPIO (very slow -- novelty)
# Non-destructive info: signature, SWDID, lock state, GUID
ftdude -c lgt -p m328p --id
# Read a locked chip: breaks read-protection, ERASES the first 1 KB (0x000-0x3FF),
# recovers 0x400.. β two equivalent spellings:
ftdude -c lgt -p m328p --dump out.hex -F
ftdude -c lgt -p m328p --crack
Debugging.
ftdude -c mpsse -p m328p --id -v # protocol diagnostics (ISP connect, RD_DELAY)
ftdude -c mpsse -p m328p --id --trace # + raw transport byte trace (= -vv)
ftdude has three output levels:
| Level | Flags | What you get |
|---|---|---|
| 0 | (default) | status and errors only |
| 1 | -v |
protocol diagnostics: ISP connect attempts, bitbang read-phase calibration (RD_DELAY) |
| 2 | -vv / --trace |
additionally a raw byte trace of every transport transfer |
-v stacks generically (-v -v, -vvv, -vvvv all work; levels above 2
currently behave like 2), and --trace simply raises the level to 2 β use
whichever reads better.
The trace shows every write to (>>) and read from (<<) the FTDI driver,
tagged per transport (mpsse, bitbang, ft4222, swd-mpsse,
swd-bitbang). Annotated real capture of --id against an ATmega328P on an
FT232H:
[mpsse >>] aa MPSSE sync probe
[mpsse >>] 8a 97 8d 86 ef 00 80 08 0b clock init + pin setup (an FT2232D omits 8a/97/8d)
[mpsse >>] 31 03 00 ac 53 00 00 4-byte SPI frame: AVR-ISP programming enable
[mpsse <<] ff ff 53 00 echoed 53 in byte 3 -> target is in ISP mode
[mpsse >>] 31 03 00 30 00 00 00 read signature byte 0
[mpsse <<] 00 30 00 1e reply carries the data in the last byte (1E)
Transfers longer than 32 bytes are truncated with a remainder counter
(... (+n)); [ft4222 rs] lines mark /RESET GPIO changes on the FT4222;
lgt4222 is deliberately untraced (GPIO wiggling, no byte stream). Most
useful when bringing up a new chip or wiring: compare a failing trace
against the healthy capture above.
ftdude speaks the avrdude CLI for its domain (classic AVRs over ISP): -c/-p/-P, -U mem:op:file:fmt, formats a/i/r/s/e/h/d/b/o/m, -e/-D/-n/-q/-F/-V/-v, -B (ISP clock), multiple -U, stdout/stderr separation, -p ? / -c ?. -b <baud> is accepted and ignored.
Input format is auto-detected from the file contents: the ELF magic -> ELF, : -> Intel-HEX, S+digit -> S-record, otherwise raw binary. So --flash / --verify and -U ...:w/:v accept any of the three with no suffix; force one with :i/:r/:s (or --flash-bin / --flash-srec). Output defaults to Intel-HEX.
Deliberately out of scope (ftdude is FTDI + LGT, ISP + SWD):
- Non-FTDI programmers (JTAG-ICE, PICkit / SNAP / Atmel-ICE, USBasp, serial Arduino-as-ISP, ...)
- UPDI / PDI / TPI (AVR-0/1/2, Xmega, newer ATtiny)
- Terminal mode (
-t), config file (-C/ avrdude.conf), the avrdude GUI - High-voltage programming,
-xhardware-specific parameters
Because of this, ftdude will not work as a drop-in behind AVRDUDESS, which drives the real avrdude with -C avrdude.conf and avrdude's own programmer IDs.
- The LGT8F328P has no standard SPI-ISP β its native interface is SWD/SWC. Use the
lgt*transports for LGT parts; the SPI transports (mpsse/bitbang/ft4222) are for genuine AVRs. - The LGT8F328P re-locks on every reset β there is no non-destructive flash read. A fresh SWD session always sees the chip locked (SWDID
0x3E); the transient0x3Fonly exists within a session after unlocking and does not survive a reset or power-cycle (hardware-confirmed).--idreads the SWDID and GUID non-destructively. Reading flash back requires breaking the read protection via--crack(or-F), which erases the first 1 KB (0x000β0x3FF) by chip design and recovers0x400..; the first page reads as erased.--flashalways full-erases and writes. So "flash now, dump later in a separate run" cannot be non-destructive on this silicon β verify within the same flash session instead. lgt4222is the slow "for the honour" route (~50 B/s): writing works, but verify is unreliable and address 0x00FF loses bit 0. Use--flash --no-verify, and-c lgt/-c lgt232rfor guaranteed-correct flashing.- The LGT-SWD clock is fixed (bit-banged);
--sckhas no effect there. - LGT-SWD requires an H-series chip (FT232H / FT2232H / FT4232H / HP). The SWD init sends H-only MPSSE commands, so it will not work on an FT2232D.
- HP-series autodetect needs a current D2XX driver; with an older driver the chips still work via an explicit
-c mpsse. - FT232RN and FT245R/RN have no dedicated D2XX type code. The RN parts identify as FT232R (drop-in); if enumeration reports an unknown type, use
-c bitbangexplicitly.
Unit tests (no hardware, via CTest):
cmake --build build
ctest --test-dir build
Hardware test suite (a real chip on a C232HD) β a cross-platform Python runner and an equivalent PowerShell one, both with automatic backup and restore:
cd test/hardware
python hw_test.py --ftdude ../../build/Debug/ftdude.exe
# or: .\hw_test.ps1 -Ftdude ..\..\build\Debug\ftdude.exe
See test/hardware/README.md for details and safety notes.
- avrdude-style
-U, EEPROM, fuse decode, raw binary,-D/-n/-q/-B - Cross-platform hardware and unit test suites
- Motorola S-record (
:s) read/write β data records S1/S2/S3 (1.8.0-alpha.2) - Read the LGT ID/config region:
--idreports SWDID, lock state and GUID non-destructively. The factory trim values (RCMCAL/RCKCAL/VCAL) live in a hardware-loaded info block, are not addressable over SWD, and survive the chip erase. Flash read-back requires--crack(sacrifices the first 1 KB). - Multi-level verbosity (
-vprotocol debug,-vv/--traceraw transport byte trace) -
--ledstatus LED on every transport: MPSSE low byte (AD4β7) and high byte (AC0β7), FT232R sync-bitbang (D4β7), FT4222 GPIO (1.8.0-alpha.7) - Phase-specific LED patterns β erase/write/verify/read distinguishable, error latches β via the flash layer's
set_ledhook (1.8.0-alpha.8) -
Experimentalβ removed in 1.8.0-alpha.12: CBUS bit-bang (0x20) can't coexist with sync-bitbang ISP (0x04); bench-confirmedc0-c3CBUS bus for FT232R on-board LEDs (1.8.0-alpha.9)
Contributions are welcome. Fork the repo, create a feature branch, commit, and open a pull request:
- Fork the project
- Create your feature branch (
git checkout -b feature/amazing) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing) - Open a pull request
Distributed under the MIT Licence. See LICENSE for the full text.
- avrdude β the CLI conventions ftdude follows
- avr-libc β the fuse-bit definitions the decode tables are generated from
- dbuezas/lgt8fx β LGT8F328P board support and SWD reference
- Flipper Zero β AVR-ISP FAP groundwork