Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

30 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ftdude

An avrdude-style command-line flasher for FTDI and LGT programmers.

C11 CMake Platform Version Licence

About Β· Getting Started Β· Usage Β· Deutsch

Table of contents

About the project

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).

Built with

  • 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

Features

  • 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 -U operations per invocation; clean stdout/stderr separation, avrdude-style
  • Auto-detect: with exactly one FTDI attached, -c may be omitted
  • Six transports: MPSSE-SPI, FT232R sync-bitbang and FT4222 hardware SPI (AVR-ISP); LGT-SWD over each of those

Getting started

Prerequisites

  • 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).

Build

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.

Usage

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.

Programmers (-c)

-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)

Wiring

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).

Status LED (optional)

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.

Other transports

  • 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.

Bare-chip pinouts

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

Module and eval-board headers

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.

Schematic pinouts (pin locations)

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.

SWD pin mapping (LGT8F328P)

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.

Examples

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)

Verbosity and tracing

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.

avrdude compatibility

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, -x hardware-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.

Known limitations

  • 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 transient 0x3F only exists within a session after unlocking and does not survive a reset or power-cycle (hardware-confirmed). --id reads 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 recovers 0x400..; the first page reads as erased. --flash always 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.
  • lgt4222 is 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 lgt232r for guaranteed-correct flashing.
  • The LGT-SWD clock is fixed (bit-banged); --sck has 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 bitbang explicitly.

Testing

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.

Roadmap

  • 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: --id reports 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 (-v protocol debug, -vv / --trace raw transport byte trace)
  • --led status 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_led hook (1.8.0-alpha.8)
  • Experimental c0-c3 CBUS bus for FT232R on-board LEDs (1.8.0-alpha.9) β€” removed in 1.8.0-alpha.12: CBUS bit-bang (0x20) can't coexist with sync-bitbang ISP (0x04); bench-confirmed

Contributing

Contributions are welcome. Fork the repo, create a feature branch, commit, and open a pull request:

  1. Fork the project
  2. Create your feature branch (git checkout -b feature/amazing)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing)
  5. Open a pull request

Licence

Distributed under the MIT Licence. See LICENSE for the full text.

Acknowledgments

  • 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

About

An avrdude-style command-line flasher for FTDI programmers. AVR-ISP and SWD.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages