A command-line ISP programmer for the Atmel/Microchip AT89S51 and AT89S52, driven through a USB-to-serial/SPI adapter:
- FT232RL / FT232R (cheap UART bridge boards): software SPI over bit-bang mode. FT232RNL, the pin-compatible successor of the discontinued FT232RL, is expected to work the same way but is untested on real hardware
- FT232H: hardware SPI over MPSSE (untested on real hardware)
A step-by-step explanation with diagrams is in docs/how-it-works.md (繁體中文).
The AT89S51/S52 are programmed through an SPI-like serial interface: RST,
SCK, MOSI, MISO. Programming is done by holding RST high and clocking a
fixed instruction set (Programming Enable, Chip Erase, Read/Write Program
Memory, Read Signature Byte) into the part. See src/isp.rs for the exact
byte sequences, taken from the Microchip datasheets for the
AT89S51 and
AT89S52 ("Serial Programming
Instruction Set").
Two hardware requirements that are easy to miss:
- The target needs its own running crystal/oscillator. The ISP shift
register is clocked internally off
XTAL1. The adapter does not supply a clock signal. - SCK must stay below 1/16 of the target's crystal frequency. The
default
--clock-hz 100000is conservative and safe for any crystal ≥ 3.2 MHz. Lower it if you're using a slower crystal.
| Approach | Adapter firmware | Host software | Notes |
|---|---|---|---|
| This project | None | Single Rust binary | Linux, Windows, macOS |
| Arduino as ISP | Sketch must be flashed first | avrdude or a custom tool | |
| USBasp-style | Custom firmware | avrdude-compatible | |
| Parallel port | None | Linux-only tools | Requires a parallel port |
Prebuilt binaries for Linux (x86_64), Windows (x86_64) and macOS (universal)
are on the releases page.
After downloading, continue at step 3 (Linux), 4 (Windows) or 5 (macOS). To
build from source or use cargo install, start at step 1.
# Rust toolchain (https://rustup.rs), then on Debian/Ubuntu:
sudo apt install build-essentialgit clone https://github.com/single9/at89s5x-programmer.git && cd at89s5x-programmer cargo build --release # binary: target/release/at89s5x-isp
Or install directly from GitHub into ~/.cargo/bin:
cargo install --git https://github.com/single9/at89s5x-programmer
The FT232R backend uses libusb. It detaches the kernel's ftdi_sio driver
automatically while the tool runs and hands it back afterwards, so you do
not need rmmod, and /dev/ttyUSB* keeps working the rest of the time.
It only needs permission to open the USB device. From a clone of the
repository, run:
./scripts/setup-linux.sh
The script adds your user to the plugdev group, and
installs a udev rule. Then unplug and re-plug the adapter (and log out
and back in if you were just added to plugdev). It is safe to re-run.
Manual equivalent, for a downloaded binary without the repository:
echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="0403", ATTR{idProduct}=="6001", GROUP="plugdev", MODE="0660"' \ | sudo tee /etc/udev/rules.d/99-ft232r.rules sudo udevadm control --reload-rules && sudo udevadm trigger
The rule is permanent. Other computers need the same one-time setup.
Windows is supported for the FT232R path (verified with an FT232RL). Use the
.zip from the releases page, or build from source with the MSVC toolchain.
The .exe has no extra runtime requirements.
- Install the WinUSB driver for the adapter with Zadig: select the FT232R, choose WinUSB, and install.
- Run
at89s5x-isp.exe infofrom a terminal.
While WinUSB is bound, the adapter no longer appears as a COM port. To use it as a serial port again, reinstall FTDI's driver in Device Manager.
macOS is supported for the FT232R path (verified with an FT232RL). The release contains one universal binary that runs on both Intel and Apple Silicon, with libusb built in, so nothing else needs to be installed.
tar xzf at89s5x-isp-*-macos-universal.tar.gz && cd at89s5x-isp-*-macos-universal xattr -d com.apple.quarantine at89s5x-isp # required once, see below ./at89s5x-isp info
The binary is not notarized, so macOS blocks it when it was downloaded with a
browser. The xattr command removes the quarantine flag that the
browser added.
If opening the adapter fails with an access error, the system's FTDI driver
may own the device. Try running with sudo.
Both adapters use the same wiring, and only the adapter-side pin names differ.
| Signal | AT89S5x pin | FT232RL (bit-bang) | FT232H (MPSSE, untested) |
|---|---|---|---|
| SCK | 8 (P1.7) | TXD (D0) | AD0 |
| MOSI | 6 (P1.5) | RXD (D1) | AD1 |
| MISO | 7 (P1.6) | RTS# (D2), input | AD2 |
| RST | 9 (with R1, see below) | CTS# (D3) | AD3 |
| GND | 20 | GND | GND |
Set the board's VCCIO/jumper to the target's supply voltage (3.3 V or 5 V) so the logic levels match. Counterfeit FT232RL chips may misbehave in bit-bang mode. The FT232H path has not been tested on real hardware, and only the FT232RL path has been verified.
This is the circuit for the LED blink example. The adapter drives only the ISP signals, so the target board needs its own power, crystal and reset network, as shown.
Entering ISP mode doesn't require a button: enter_programming_mode()
(src/isp.rs) drives RST directly, so running flash right after plugging
in the adapter is enough. The pulse/enable sequence happens automatically
every time.
The adapter (FT232RL or FT232H) is detected automatically from its USB ID.
Pass --adapter ft232r or --adapter ft232h only to override it, e.g. when
both are plugged in.
# Identify the chip (reads the 3 signature bytes) cargo run -- info # Erase, write, and verify a HEX file (erase + verify are on by default) cargo run -- flash firmware.hex # Just erase cargo run -- erase # Verify flash contents against a HEX file without writing cargo run -- verify firmware.hex # Select a specific adapter by serial number, and a slower clock cargo run -- --serial A1B2C3D4 --clock-hz 50000 flash firmware.hex
Speed: verify reads about 8 KB in 12 s at the default 100 kHz and in about
2.4 s at --clock-hz 700000. SCK may go up to crystal / 16, so with a 12 MHz
crystal 700000 is the practical maximum. flash only reads back the bytes it
wrote, so small programs finish in under a second.
Diagnostic commands (no flash is touched):
# MOSI jumpered to MISO, no target needed: checks the adapter's SPI timing cargo run -- selftest # Hold RST high and send Programming Enable every 50 ms, printing replies cargo run -- probe --seconds 30 # Hold RST high/low for N seconds, to measure pin 9 with a multimeter cargo run -- rst high --seconds 20
Set AT89S5X_ISP_TRACE=1 to print the pin states read back when RST changes.
A good first check is info. It should print the adapter and a device line
such as:
Adapter FT232R (bit-bang), SCK 100 kHz
Device AT89S52 signature 1E 52 06 8 KB flash
target did not answer Programming Enable means the wiring, power, or the
target's crystal needs checking (see Troubleshooting).
examples/blink_p1_0.hex blinks an LED on P1.0 (pin 1) at about 2 Hz with a
12 MHz crystal. examples/blink_p1_0.asm is its source. Wire the LED
active-low (VCC, resistor, LED, P1.0), then:
cargo run -- flash examples/blink_p1_0.hex
Verified on a real AT89S52. After programming, RST must be low (pulled down by R1) for the program to run.
target did not answer Programming Enable with reply FF FF FF FF, or
replies that keep changing, means the target is not synchronising:
- Run
selftestwith MOSI jumpered to MISO. If it passes, the adapter is fine. - Check the target crystal really oscillates (XTAL2, pin 18, about 2 V, while 0 V or 5 V means it is not running) and has a 22–30 pF cap from each crystal pin to GND.
- Check VCC/GND decoupling (0.1 µF), EA/VPP (pin 31) at VCC, and keep wires short.
- Remove other loads from P1.5–P1.7 (LEDs, buttons) and, as a test, C6 on RST.
- Try a slower clock, e.g.
--clock-hz 5000.
A 12 MHz crystal is fine: SCK only has to stay below crystal / 16 (750 kHz).
- Blank (
0xFF) bytes are skipped when writing, since erased flash is already0xFF. - The chip is auto-detected from its signature bytes (AT89S51 =
1E 51 06, AT89S52 =1E 52 06) and the flash size (4 KB / 8 KB) is chosen to match. An unrecognised signature falls back to 4 KB with a warning. - Lock bits are not currently read or written, only flash contents.
- FT232H only: it uses the D2XX driver (
libftd2xx), which on Linux cannot open a device the kernel'sftdi_siohas claimed. Unbind it or uselibftd2xx's supplied udev rules first.
MIT.