A working, from-scratch Linux driver for the RT809H universal SPI NOR/EEPROM
programmer that talks to the hardware directly, without running the
vendor's Windows RT809H.exe software at all — not even under Wine.
See rt809h-notes for the
Wine-based approach (running the official software as-is). This repo is a
different, independent path: a real reimplementation of the SPI NOR
read/write protocol.
The RT809H is internally an FTDI FT2232H chip (USB VID:PID 0403:6010).
Static analysis showed the vendor software drives it in low-level MPSSE
mode over FTD2XX.dll, doing ordinary SPI transactions. FTDI's MPSSE
protocol is publicly documented (Application Notes AN_108/AN_135), and the
open-source pyftdi library speaks it
directly over libusb — so in principle no Windows software is required at
all to use the programmer's ZIF socket as a plain SPI reader/writer.
The one missing piece was that the RT809H's onboard microcontroller expects
a specific USB handshake before it connects the ZIF socket pins through to
the FTDI SPI lines — without it, the SPI lines float and every read comes
back 0xFF. That handshake was captured by sniffing the real USB traffic
of the genuine RT809H.exe, and is simply replayed byte-for-byte.
RT809H.exe was run under Wine with its ftd2xx.dll swapped for a thin
logging shim that recorded every FT_Write / FT_Read / FT_SetBitMode /
device-reset call before passing it through to the real DLL. The resulting
log — arm_sequence.log — is the literal byte sequence
the vendor software sends to "arm" the ZIF socket, including its initial
attempts that the real GUI also shows as a transient "Chip ID identified
error" before it settles.
The exact shim/capture tooling isn't included here (it's tied to a specific Wine debugging setup); what matters and what's reusable is the captured log itself and the replay logic.
rt809h_replay.py— generic parser/player for a captured log ofWRITE/READ/SETBITMODE/RESET_DEVICElines, replayed in exact original order overpyftdi.arm_sequence.log— the captured handshake that arms the ZIF socket. Replaying this against the real device is what makes the SPI lines live.rt809h_native.py— standalone CLI: arms the socket, reads the SPI NOR chip's JEDEC ID, dumps the full chip to a file.python3 rt809h_native.py dump.bin # full chip, size from JEDEC ID python3 rt809h_native.py --id # just identify the chiprt809h_link.py— the same functionality wrapped as a reusableRT809HLinkclass (read_sectors,read_flash,write_flash,erase_chip,verify_flash) with a 512-byte-sector interface, meant to be dropped into a larger tool as one interchangeable data source among others.rt809h_setup_usb.sh— one-time-per-plug USB setup: unbinds the kernel'sftdi_siodriver from the RT809H (VID:PID0403:6010) so it doesn't grab the device as a serial port, thenchmod 666s the USB device node so it's usable without root. Run this (with the device plugged in) before using any of the scripts above.
SPI NOR commands used, once the socket is armed:
| Byte | Command |
|---|---|
0x06 |
Write Enable (WREN) |
0x05 |
Read Status Register 1 |
0x9F |
Read JEDEC ID (3 bytes: manufacturer / memory type / capacity) |
0x03 |
Read Data (CS low, 0x03 + 3-byte address, clock out data — address auto-increments while CS stays low) |
0x02 |
Page Program (256-byte pages) |
0xC7 |
Chip Erase |
MPSSE commands (FTDI AN_108/AN_135) used to drive them:
| Byte(s) | Meaning |
|---|---|
0x8A |
Disable clk/5 (60MHz base clock instead of 12MHz) |
0x86 <lo> <hi> |
Set TCK/SK clock divisor |
0x80 <value> <dir> |
Set Data Bits Low Byte (bit0=SCK, bit1=MOSI, bit2=MISO in, bit3=CS) |
0x11 <lenL> <lenH> <data...> |
Clock Data Bytes Out, MSB first |
0x20 <lenL> <lenH> |
Clock Data Bytes In, MSB first (up to 65536B) |
0x87 |
Send Immediate (flush buffer without waiting for it to fill) |
- Read: confirmed working — JEDEC ID and full chip dump tested against real hardware.
- Write / erase: implemented (
0x06/0x02/0xC7+ status-register polling) but not yet verified on real hardware — treat as experimental until confirmed.
- Python 3,
pyftdi - Linux with the RT809H's
ftdi_siobinding removed and USB permissions set (seert809h_setup_usb.sh) - A real RT809H programmer with a SPI NOR chip in the ZIF socket
Code here is original work (a from-scratch reimplementation based on
publicly documented FTDI protocols and observed USB traffic timing/framing
— not decompiled or copied from the vendor's software). Shared as-is for
reference; no warranty. arm_sequence.log is raw USB traffic captured
against the author's own hardware, included because the replay logic is
useless without it.