[ home ]

AVR bitbang-programmer using FT230X

This page presents a small USB Atmel AVR programming-dongle, made out of an FTDI FT230X USB-to-UART bridge.

Don't expect any spectacular design here (it's basically a chip soldered onto a board). This was made as a tool for myself, and it serves that purpose well. I like simplicity, and it doesn't get much simpler than this.

A huge number of AVR programming-dongles already exists out there, and among them are quite a few FTDI-chip based ones. This is simply one of them.


I use quite a few Atmel AVR microcontrollers, and over time, have been using a number of programming-dongles. (By "programming-dongle" I mean the physical interface between host-system and embedded target.)

Starting with STK200 (parallel port), STK500 (legacy serial port), AVRISP mkII (USB), and when I blew up the latter, a makeshift FTDI FT232RL based bitbanging programmer, which looked like this:

Not very pretty. The 5 / 3.3 V target-voltage selection was done through (de)soldering a green wire-bridge. This dongle can do ISP programming, which I almost always use.

This thing is ugly, fragile, and only 1 exists.

Time for something new

The above dongle and the one presented here are protocol-less dongles, by which I mean that there is not yet another layer of software inside the dongle itself.

Because of the timing-insensitive nature of ISP-programming (using an SPI interface), I don't see the need for additional software in the dongle, when the host-system itself can control and read every interface-pin on the target-side.

Keep complex things minimal.

For FTDI-based programmers (including aforementioned DIY-dongle), libFTDI offers such control. FTDI-based programmers can be used - together with AVRDUDE on the host-system side - to program most if not all ISP-programmable AVR-targets.

Making a new programming-dongle was also a nice opportunity to try an FTDI FT230XS bridge-chip where I had normally used the bigger, more versatile and more expensive FTDI FT232RL (both leaded packages).

There are similar ready-made programming-dongles out there, but frankly, I have little patience, and I enjoy making certain things myself.


Of course there is failure!

Whereas the FT232R can be used with 5 V as I/O voltage (VCCIO), the FT230X only accepts up to 3.3 V. I assumed it could use 5 V as well, and therefore made target-voltage selection DIP-switches: provide either 5 or 3.3 V, or use supplied target-voltage.

One of these switches (for providing 5 V to the target) is thus useless and should not be used. Oh well.


See below for the schematic, including aforementioned flaw w.r.t. 5 V target-voltage DIP-switch:


This thing can be quite small - convenient for tossing into a laptop-bag:

6-pin ISP-header is now mounted vertically. Perhaps I'll see if there's a right-angle version fitting the same footprint, because that's a bit slimmer and probably less prone to breakage.


Making use of micro-USB B connector instead of legacy A or B makes this thing fit to most cellphone-cables:

My monthly income is displayed here as well.


Mental checklist in case something fails using this kind of programmer:


I think I noticed a mismatch between configured bitclock (using the "-B" switch to AVRDUDE) and the one actually used. This can be a bug in AVRDUDE 6.1 (which is what I use here now), or it can be an error on my behalf.

Didn't investigate far enough then, but if programming fails for some reason, use e.g. "-B 1000".

USB product-ID (PID)

The FT230X has a different product-ID (0x6015) than the FT232R (0x6001) - see this list (FTDI has vendor-ID 0x0403). You can see vendor- and product-ID when running lsusb(8):


    $ lsusb | grep 0403
    Bus 005 Device 017: ID 0403:6001 Future Technology Devices International, Ltd FT232 Serial (UART) IC


    $ lsusb | grep 0403
    Bus 005 Device 018: ID 0403:6015 Future Technology Devices International, Ltd Bridge(I2C/SPI/UART/FIFO)

This might require defining a programmer in the AVRDUDE config-file, like thus:

      id    = "my_ft230x_programming_dongle";
      desc  = "FT230X Synchronous BitBang";
      type  = "ftdi_syncbb";
      usbpid = 0x6015;
      connection_type = usb;
      miso  = 3;  # CTS
      sck   = 0;  # TxD
      mosi  = 2;  # RTS
      reset = 1;  # RxD

Also note the pin-assignments.


I noticed 2 problems with my previous FTDI programming-dongle, one of which was solved by using the patch refered to in this post, but the original post mentioning the patch seems to be gone. Another problem (mentioned in the same post) has to do with AVRDUDE sometimes hanging on program exit - described quickfix seemed to work.

I tried a clean AVRDUDE 6.3 tree, which could program OK, but sometimes hung at program-exit or -entry (forgot which). I therefore continue to use my 6.1 tree.

Combined patch is here (use at will - I used this against an AVRDUDE 6.1 tree here):

    Index: avrdude-6.1/ft245r.c
    --- avrdude-6.1/ft245r.c
    +++ avrdude-6.1/ft245r.c
    @@ -47,10 +47,15 @@
       How to add the wires to an arduino is documented here:
    +#define BBB( x )   # x
    +#define AAA( x )   BBB( x )
     #include "ac_cfg.h"
     #include <stdio.h>
     #include <stdlib.h>
    @@ -294,10 +299,14 @@
         ft245r_recv (pgm, buf, 1);
         ft245r_in = buf[0];
         return 0;
    +static int set_sck(PROGRAMMER * pgm, int value) {
    +    return set_pin(pgm, PIN_AVR_SCK, value);
     static int set_reset(PROGRAMMER * pgm, int value) {
         return set_pin(pgm, PIN_AVR_RESET, value);
    @@ -419,16 +428,21 @@
     static int ft245r_initialize(PROGRAMMER * pgm, AVRPART * p) {
    +    set_sck( pgm, OFF );   // XXX MR
         set_reset(pgm, OFF);
         usleep(5000); // 5ms
         set_reset(pgm, ON);
         usleep(5000); // 5ms
         set_reset(pgm, OFF);
    -    usleep(5000); // 5ms
    +    usleep(20000);   // XXX MR was: 5000
         return ft245r_program_enable(pgm, p);
     static inline int set_data(PROGRAMMER * pgm, unsigned char *buf, unsigned char data) {
    @@ -651,12 +665,12 @@
             // I think the switch to BB mode and back flushes the buffer.
             ftdi_set_bitmode(handle, 0, BITMODE_SYNCBB); // set Synchronous BitBang, all in puts
             ftdi_set_bitmode(handle, 0, BITMODE_RESET); // disable Synchronous BitBang
             pthread_join(readerthread, NULL);
    -        ftdi_usb_close(handle);
    -        ftdi_deinit (handle); // TODO this works with libftdi 0.20, but hangs with 1.0
    +//        ftdi_usb_close(handle);   XXX MR
    +//        ftdi_deinit (handle); // TODO this works with libftdi 0.20, but hangs with 1.0   XXX MR
             handle = NULL;

That's all.