Introduction To FTDI Bitbang Mode

It was an interface that launched a thousand hacks. Near trivial to program, enough I/O lines for useful work, and sufficiently fast for a multitude of applications: homebrew logic analyzers, chip programmers, LCD interfaces and LED light shows, to name a few.

Today the parallel printer port is on the brink of extinction (and good riddance, some would say). Largely rendered obsolete by USB, few (if any) new peripherals even include a parallel connector, and today’s shrinking computers — nettops, netbooks, media center PCs — wouldn’t have space for it anyway. That’s great for tidy desks, but not so good if you enjoyed the dirt-cheap hacks that the legacy parallel port made possible.

Fear not, for there’s a viable USB alternative that can resurrect many of these classic hacks! And if you’ve done much work with Arduino, there’s a good chance it’s already lurking in your parts drawer.

A recurring element among many recent hacks is the use of an Arduino or other USB-connected microcontroller as an intermediary between a PC and an external circuit. Code running on the microcontroller will poll some sensor to detect a change (for example, an empty coffee pot), then send a message over USB to a host PC where another program then acts on it (updating a web page to tell the world there’s no coffee). This is a reasonable approach, the parts are affordable and simple to program, but for many projects we can get by with just half the code, complexity and expense…and some folks will be thrilled to hear, no Arduino!

When the microcontroller on an Arduino board talks to a host PC over USB, all of the heavy lifting of USB communication is done by a separate chip: the FTDI FT232R USB to serial UART interface. This allows code on both the host and microcontroller to use much simpler asynchronous serial communication. As a size- and cost-cutting measure, some Arduino variants place this chip on a separate board to be attached only when programming the microcontroller, allowing it to be re-used for the next project.

This default USB-to-serial mode of the FT232R is what usually draws all the attention and gets all the girls. An alternate mode, less talked about but no less useful, is bitbang mode. This gives us independent software control of up to eight I/O lines, similar to the classic parallel port or the digital I/O lines of a microcontroller.

Acquiring the Hardware

If one isn’t already in your stash, FT232R breakout boards are easy to come by. Any shop that carries the Arduino Pro or LilyPad, or some of the bargain-priced Arduino derivatives (e.g. Boarduino), will also offer a programming cable that breaks out four of the FT232R I/O lines:

Above: The SparkFun FTDI Basic Breakout board (around $14) is surrounded by the FTDI TTL-232R converter cable (around $20). Both bring out four data lines that can be used for general-purpose I/O. There is a one pin difference in that the FTDI cable brings out the RTS pin, while the SparkFun board uses the DTR pin in the same position.
Above: The SparkFun FTDI Basic Breakout board (around $14) is surrounded by the FTDI TTL-232R converter cable (around $20). Both break out four data lines that can be used for general-purpose I/O. 

Four data lines may seem constraining, but for many tasks this is sufficient; projects using SPI communication, shift registers and port expanders will be well served. If you need the full complement of I/O lines, more sophisticated breakout boards are available:

Above: just a few of the available FTDI breakout boards. Clockwise from top: SparkFun Breakout Board for FT232RL (around $15), Modern Device USB-BUB ($12), DLP Design DLP-USB232R ($18) and DLP-USB1232H ($25), and FTDI’s own FT4232HQ Mini Module ($30). The latter two are based on more capable chips, FTDI’s FT2232H and FT4232H, with additional features far exceeding the scope of this article.
Above: just a few of the available full breakout boards. Clockwise from top: SparkFun Breakout Board for FT232RL (around $15), Modern Device USB-BUB ($12), DLP Design DLP-USB232R ($18) and DLP-USB1232H ($25), and FTDI’s own FT4232HQ Mini Module ($30). The latter two are based on more capable chips, the FT2232H and FT4232H, backwardly compatible but with additional features far exceeding the scope of this article.

Setting Up for Development

Another encouraging aspect of the FTDI interface is cross-platform software support; the same hacks can be created whether you’re using Windows, Linux or Mac OS X. Two software components are required to begin development: a device driver, which operates behind the scenes to handle all the low-level USB communication, and an API library, which is linked with your own code and forwards requests to the driver. Complicating matters slightly, there are two different APIs to choose from, and the setup process is a little different for each OS.

FTDI’s own API is called D2XX. This library is proprietary and closed source, but they do not charge for its use, even in commercial situations. An alternate API, libftdi, is community-developed and fully open source. This library has similar capabilities, but different function names and syntaxes. Conversion between the two APIs is very straightforward, and we’ll provide an example for each.

Windows users: if you’ve used Arduino before, the necessary driver is already installed. Otherwise, download and extract the latest Windows driver from the FTDI web site. When first connecting an FTDI cable or breakout board, use the Found New Hardware Wizard to locate and install the driver. If you want to use the D2XX library, the header and object files are included in the driver folder. This is the easier option. If you’d prefer the open source libftdi, you’ll need to download and install the both the libusb-win32 device driver and source code, then download and build libftdi.

Linux users: most current Linux distributions already have the necessary driver present as a kernel module. The D2XX library for Linux can be downloaded from the FTDI driver page, but libftdi is easier to install: simply locate libftdi-dev in your favorite package manager and have it take care of the dependencies when installing. In either case, FTDI programs for Linux need to be run as root, e.g.

sudo ./hello-ftdi

Mac OS X users: download the D2XX library from the FTDI download page. The included ReadMe file will explain how to install this library. If you’d prefer to use libftdi, download the source for libusb (legacy 0.1.12 version) and libftdi from their respective sites, then use the following commands in a Terminal window to build and install each of the two libraries:

./configure
make
sudo make install

If you’ve used Arduino in the past or have the FTDI Virtual Com Port (VCP) driver installed for any other reason, this needs to be disabled before bitbang mode will work on the Mac; the two cannot coexist. In a Terminal window, type:

sudo kextunload /System/Library/Extensions/FTDIUSBSerialDriver.kext

To restore the driver and resume using Arduino or other FTDI serial devices:

sudo kextload /System/Library/Extensions/FTDIUSBSerialDriver.kext

Other operating systems: drivers for several other platforms are available. Please see the FTDI drivers page for details and links.

Most of the FTDI sample code is written in C, and that’s what we’ll use here. Bindings for other languages are available on the FTDI web site.

Hello World: Flash an LED

The standard introductory program for nearly every microcontroller is the LED flasher, so let’s give that a try. You’ll need an FTDI cable or any of the breakout boards, one LED and a 220 Ohm resistor.

Connect the resistor to either leg of the LED, but keep note of which leg is the positive (anode) side. Then insert the LED/resistor pair into the socket on the end of the FTDI cable as shown below, with the negative leg connected to the GND line (the black wire on the FTDI cable) and the positive leg to the CTS line (brown wire).

ftdi-hello

Here’s the C source code, using the libftdi API. If you plan on using D2XX, have a look at the second listing a bit later; the relationship between functions should be fairly obvious.

/* hello-ftdi.c: flash LED connected between CTS and GND.
   This example uses the libftdi API.
   Minimal error checking; written for brevity, not durability. */

#include <stdio.h>
#include <ftdi.h>

#define LED 0x08  /* CTS (brown wire on FTDI cable) */

int main()
{
    unsigned char c = 0;
    struct ftdi_context ftdic;

    /* Initialize context for subsequent function calls */
    ftdi_init(&ftdic);

    /* Open FTDI device based on FT232R vendor & product IDs */
    if(ftdi_usb_open(&ftdic, 0x0403, 0x6001) < 0) {
        puts("Can't open device");
        return 1;
    }

    /* Enable bitbang mode with a single output line */
    ftdi_enable_bitbang(&ftdic, LED);

    /* Endless loop: invert LED state, write output, pause 1 second */
    for(;;) {
        c ^= LED;
        ftdi_write_data(&ftdic, &c, 1);
        sleep(1);
    }
}

If the program successfully compiles (all of the required headers and libraries in the appropriate locations, and properly linked with our own code), the LED should flash slowly.

The code is largely self-explanatory, but there are a couple of points worth highlighting:

  • Note the second parameter to ftdi_enable_bitbang(). This is an 8-bit mask indicating which lines should be outputs (bit set) vs. inputs (bit clear). As we’re only using a single output line (CTS in this case), we set just the one bit corresponding to that line (0x08). For additional outputs, we can OR the bit values together. The bitbang I/O pin mappings aren’t defined in either API’s header, so you might find it helpful to keep around a header such as this:
    #define PIN_TX  0x01  /* Orange wire on FTDI cable */
    #define PIX_RX  0x02  /* Yellow */
    #define PIN_RTS 0x04  /* Green */
    #define PIN_CTS 0x08  /* Brown */
    #define PIN_DTR 0x10
    #define PIN_DSR 0x20
    #define PIN_DCD 0x40
    #define PIN_RI  0x80
  • Notice that the second parameter to ftdi_write_data() is a pointer to an 8-bit variable. The function normally expects an array (and the second example will demonstrate this), but for this simple case only one value is required. When issuing a single byte like this, remember to always pass by reference (a pointer), not a numeric constant. The last parameter to the function is the number of bytes.

The value(s) passed to ftdi_write_data() indicate the desired state of the output lines: a set bit indicates a logic high state (3.3 or 5 volts, depending on the FTDI adapter used), and a clear bit indicates logic low (0 volts). The mapping of bits to I/O pins is exactly the same as for ftdi_enable_bitbang(), so the prior #defines may be helpful in that regard.

More Bells and Whistles

There are many project ideas that only occasionally need to toggle an I/O line: ring a bell when a web counter increments, flash a light when email arrives, send a Tweet when the cat uses the litter box. The code for such tasks will often be just as simple as the example above. But when communicating with more complex devices and protocols, this byte-at-a-time approach becomes very inefficient. Every call to ftdi_write_data(), even a single byte, issues a USB transaction that will be padded to a multiple of 64 bytes, and there can be latencies of a full millisecond or more before this request is actually sent down the wire. To efficiently send complex data streams, it’s necessary to pass an entire array to the ftdi_write_data() function.

Bitbang mode operates very differently than the chip’s default serial UART mode. In the serial configuration, one simply calls fwrite() to issue a block of data to the serial port, and the chip manages all the details of the transmission protocol: word length, start, stop and parity bits, and toggling the logic state of the TX line at the required baud rate. In Bitbang mode there is no implied protocol; this is raw access to the data lines, and we must take care to construct a meaningful signal ourselves, essentially creating an image map of the data lines over time:

analogy

Suppose we want to communicate with a device that uses the SPI protocol (Serial Peripheral Interface, also sometimes called Microwire, synchronous serial or three- or four-wire serial, depending on the implementation). The required output would resemble the waveform in the illustration above: one output line provides a clock signal, another represents the data bits (in sync with the clock), and a third issues an end-of-data latch signal. If sending 8 bits of data, our output array would need to be twice that size (to represent the high and low state of each clock tick), plus two additional bytes for the latch high/low at the end. 8 * 2 + 2 = 18 bytes in the output array (possibly a few extra bytes, if a specific device requires a short delay before the latch signal).

SPI might be too esoteric for an introductory article; not everyone will have the right components around. Instead, let’s make something visually gratifying: we’ll drive a group of LEDs using pulse width modulation. This is of dubious utility but it’s flashy and hints at the speed and fine control that’s possible using this port.

The hardware setup is similar to the first example, but repeated four times: four LEDs, four 220 Omh resistors (we’re limiting it to four in order to work with the FTDI cable or SparkFun Basic Breakout, but it’s easily expandable to eight with the other boards). The negative legs are all connected in common to the GND line (black wire on the FTDI cable), while the positive legs are connected to CTS, TX, RX and RTS (brown, orange, yellow and green wires, respectively). The SparkFun Basic Breakout has DTR in place of RTS for the last pin, but the example code will work the same with either one…we’ll explain how shortly.

Here’s how the components look on a breadboard. Notice that the +5V line (red wire on FTDI cable) is skipped:

ftdi-pwm

And here’s the source code, using the D2XX API. Adapting this to libftdi is straightforward; see the first example for the different syntaxes.

/* pwmchase.c: 8-bit PWM on 4 LEDs using FTDI cable or breakout.
   This example uses the D2XX API.
   Minimal error checking; written for brevity, not durability. */

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ftd2xx.h>

#define LED1 0x08  /* CTS (brown wire on FTDI cable) */
#define LED2 0x01  /* TX  (orange) */
#define LED3 0x02  /* RX  (yellow) */
#define LED4 0x14  /* RTS (green on FTDI) + DTR (on SparkFun breakout) */

int main()
{
    int i,n;
    unsigned char data[255 * 256];
    FT_HANDLE handle;
    DWORD bytes;

    /* Generate data for a single PWM 'throb' cycle */
    memset(data, 0, sizeof(data));
    for(i=1; i<128; i++) {
        /* Apply gamma correction to PWM brightness */
        n = (int)(pow((double)i / 127.0, 2.5) * 255.0);
        memset(&data[i * 255], LED1, n);         /* Ramp up */
        memset(&data[(256 - i) * 255], LED1, n); /* Ramp down */
    }   

    /* Copy data from first LED to others, offset as appropriate */
    n = sizeof(data) / 4;
    for(i=0; i<sizeof(data); i++)
    {
        if(data[i] & LED1) {
            data[(i + n    ) % sizeof(data)] |= LED2;
            data[(i + n * 2) % sizeof(data)] |= LED3;
            data[(i + n * 3) % sizeof(data)] |= LED4;
        }
    }   

    /* Initialize, open device, set bitbang mode w/5 outputs */
    if(FT_Open(0, &handle) != FT_OK) {
        puts("Can't open device");
        return 1;
    }
    FT_SetBitMode(handle, LED1 | LED2 | LED3 | LED4, 1);
    FT_SetBaudRate(handle, 9600);  /* Actually 9600 * 16 */

    /* Endless loop: dump precomputed PWM data to the device */
    for(;;) FT_Write(handle, &data, (DWORD)sizeof(data), &bytes);
}

When successfully compiled and run, the LEDs should slowly pulsate in a repeating “chaser” cycle. There are some notable differences from the first example:

  • LED4 is defined by two bits, a logical OR of both RTS and DTR, and the two bits are always toggled in unison. This isn’t a mandatory requirement, it simply makes the program compatible with different hardware: the FTDI cable and the SparkFun Basic Breakout use a different signal on the last pin, and toggling both bits makes it work the same regardless.
  • The baud rate is explicitly set to 9600 bps (bitbang mode will actually run at 16 times the baud rate). This is so the PWM speed will be the same whether using libftdi or D2XX. The former library normally initializes the port to 9600 baud by default, while the latter API (used here) opens the port at maximum speed and we need to slow it down to match. In practice, at maximum speed we’re able to get about 650,000 8-bit samples per second out this port.
  • In Mac OS X 10.6, you may find it necessary to pass the -m32 flag to gcc in order to compile and link with the D2XX library. And Windows programmers using Cygwin may need some additional header files:
    #include <stdarg.h>
    #include <windef.h>
    #include <winnt.h>
    #include <winbase.h>

Pulse width modulation makes for a nice visual demonstration of speed but unfortunately can’t really be put to serious use. In addition to the previously-mentioned I/O latency, other devices may be sharing the USB bus, and the sum total is that we can’t count on this technique to behave deterministically nor in realtime. PWM with an LED looks just fine to the eye…the timing is close enough…but trying to PWM-drive a servo is out of the question. For a synchronous serial protocol such as SPI, where a clock signal accompanies each data bit, this method works perfectly, and hopefully that can be demonstrated in a follow-up article.

Not a Panacea

FTDI bitbang mode comes in handy for many projects, but it’s not a solution to every problem. There are many situations where a microcontroller is still preferable:

  • For extended standalone use, it’s a no-brainer: a microcontroller board costs less than a fancy meal and runs for days on a 9-volt battery. Only when a project is going to involve a full-on PC anyway should bitbang mode be considered.
  • If a task involves basic analog-to-digital conversion, you’re almost certainly better off using a USB-connected microcontroller with built-in ADC. It’s just less hassle than the alternative.
  • For tasks that require continual high-speed polling of a sensor, bitbang mode will needlessly gobble USB bandwidth and CPU cycles. Most microcontrollers have an interrupt-on-change feature that avoids polling entirely, using resources only when a change actually occurs.

We hope this introduction has planted the seeds of new hacks in your mind, or will breathe new life into forgotten classic parallel port hacks. To dig deeper, the FTDI web site is the best resource. Here you’ll find data sheets, articles, and most useful of all are the application notes. There’s also information for working with other languages: Java, Perl, Python and Visual Basic, among others.

80 thoughts on “Introduction To FTDI Bitbang Mode

  1. This is an awesome and detailed article, and USB/Parallel interfaces have a place, but remember you can also buy straight Parallel port cards, too, that have broader functionality.

    The parallel port was originally designed for direct real-time machine control, at which it excels, not data transfer. When devices got ‘smart’, it was eventually hacked for use doing data transfer, and it sucked at that job.

    It is still heavily used today for its originally designed purpose in automation and CNC as there is no other alternative. It is the only thing that runs real-time, and it still excels at that function where timing is critical. If you had to redesign it today, it would do exactly the same thing.

    You can’t do that with USB or a USB/Parallel adapter, so the parallel port does still has some life left in it.

  2. Although USB might be the hardware nail in the parallel port’s coffin, the software nail was Window’s protection of i/o ports making direct and easy access to the ports more difficult. For high speed and deterministic timing (like driving CNC stepper motors), DOS and parallel ports still have a nitch.

  3. Excellent work! This is exactly the type of article that keeps me coming back to Hack a Day. I have nothing against Arduino articles, but the lego ‘hacks’ almost drove me away for good.

  4. I used the bit-bang mode of FTDIs UM245R development board to get an LCD displaying system information. It literally took 5 minutes to find my jumper wires and wire the thing together. These little devices are amazing, and make simple USB projects actually simple.

  5. this is one of the best articles i’ve seen here for quite some time. job well done phil! It’s nice to see a hardware programming article that doesn’t focus on the ‘duino for a change. Also, thanks for presenting alternative approaches using the different libraries. It’s always nice to see options for doing things differently.

  6. Well, i’ve allways thought of (and heard of) windows as not-so-realtime OS, but is DOS better in this regard?

    A Linux-distro would in my head make mutch more sense in my head for real-time cnc control :)

    1. Much so. Protected-mode DOS programs almost entirely control the CPU, RAM, and I/O ports. The exception is interrupts/DMA for stuff like DRAM/video refresh or ATA(IDE) hard drive access. You can safely disable those if your hardware has no need for software refresh and you’re not needing the hard drive to run at full speed. Ralf Brown’s big honking book of PC info lists the most common uses for IRQs, by the way.

      In fact, DOS is so bare-metal, that you’re better off reading the PC BIOS info if you’re wanting to use DOS for realtime programs. You can pretty much run a DOS program the same as if you burned an EPROM and replaced the BIOS, if that’s what you desire. Few did this because the BIOS has a good reason for existing – BIOS calls work no matter the underlying hardware >99% of the time! Windows and Linux do this because they have implemented protected-mode drivers that run much better. Running your program as an ‘option ROM’ is possible if you compile it correctly. ’55 AA’ signature and all… This leaves the BIOS interrupt implementation intact, but still makes your program not use DRAM. You can use 128KB or so of SRAM to get a bare-bones version of DOS running. Since you’re likely using a FPGA and Flash ROM, that is awfully convenient! ;)

    2. If you MUST have lower latency than USB supports or want a cheap way to get beyond 1MB/second, you’re going to need a PCMCIA (PC Card) Parallel port adapter. And if you’re doing that, it’s really tempting to just make a native PC Card/Cardbus adapter that has the advantage of interrupts and such. I can see the ‘Express’ slots on newer laptops putting the dirt onto the coffin of parallel ports after USB 2.0 put the nails in.

      Some smarter people needing real-time timing to get the most speed out of protocols like JTAG is to implement the low-level stuff using a microcontroller and then sending commands in a batch to it on the USB side using a program running on the PC. For stuff like programming a router’s firmware, this is a LOT faster!

  7. thank you phil! this was very informative article and it remebered me why i love this site! where else can you find such blogpost on a regular basis?

    now focus more on this style and you will see no more negatives comments! this is what we all waited for, a good structured, long and detailed article!
    excellent work

  8. Great job,that was an informative article.
    would love to see more in the way of old school parallel bus hacks. I used to have an old XT IBM box i used for that kinda stuff, brings back the DOS nostalgia.

  9. Thank you, Phil. There was a post a few days ago about putting two voltage regulators on a power supply which was pretty lame. To make it worse, the same webpage discussed bitbanging SPI and that was considered unworthy of mention.

    Keep it up!

  10. XP can be forced to allow real-time, but it REALLY doesn’t like it and you usually have to break some stuff first. I assume Vista won’t allow it at all.

    DOS and many Linux kernels can both do real-time very well.

    DOS may be old and limited as computer OS’s go, but for controllers its simple, stable, and has all the needed functions for Real Time control and more importantly no issues with more complex functions to interfere.

    Older DOS actually makes a decent platform for machine control, and easy to develop on. I’ve heard of people using DR-DOS, FreeDOS, and even MS-DOS 2.0 (yes, the one from 1983).
    Everything you need, nothing you don’t.

  11. Another way to do something similar, though probably slower, is to put V-USB firmware on an AVR. I’d like to see a V-USB tutorial on here at some point; it’s a great AVR library.

  12. Thanks for the info. I always see cool projects on here and just recent got a microcontroller kit to learn from but my creativity doesn’t usually expand beyond basic I/O so this is great!

  13. Doesn’t exactly *resurrect* all those legacy hacks though, it just makes it more possible to recreate them. I got all excited about being able to throw away the old Win98 box I use for talking to some legacy LPT kit…(no, really!)

  14. If only I knew this a few months ago, I made a Parallel port outlet controller using the Parallel port on my home server and thought it would be great to use USB if I could, though wasn’t able to find anything cheap.

    There is one thing with this method, I cannot really program, though I have recently been taking interest in Python… I just can’t find any sample code for this device.

  15. >If you had to redesign it today, it would do exactly the same thing.

    Probably not. As a dedicated G.CODE parser and machine controller, a DOS PC isn’t bad… but neither is a small embedded ARM/MIPS/etc. machine running a much more modern RTOS. Smaller, less power hungry, easier to integrate with the CAD workstation, easier access to more GPIO, cheaper and simpler, yadda-yadda.

  16. Well I dug out my ftdi cable and decided to try to play with this. I can’t get libftdi to make under cygwin. I would prefer not to used the closed source driver and would like to use gcc for compiling. I don’t currently have a linux box to use that would be practical. What is your setup? What compilier are you using?

  17. i guess I’m saying this a bit late.. but you don’t need to be root to run programs linked with libftdi.
    libftdi uses libusb which in turn is a userspace library.
    needless to say, i never run my ftdi programs as root. nether should anyone else.

    still, its one of the best posts on hackaday.
    thanks.

  18. Great posting – the FTDI tech guy I spoke to on Friday should read it as he said that what you describe above could not be done!
    Two questions if I may: What is the maximum speed possible and what is the programming environment used i.e. where would I copy the code examples to on a mac?

    Thanks Simon

  19. @Simon: the FT232R chip in the FTDI cable and most breakout boards tops out at about 650,000 bytes/sec (though with some caveats as mentioned in the article).

    In Mac OS X, the code samples can be compiled using gcc from the Terminal command line.

  20. Yes the older DOS actually made a decent platform for machine control, and was easy to develop on. I’ve heard of people using DR-DOS, FreeDOS, and even MS-DOS 2.0 Could work??
    Tony Granims

Leave a Reply to jeff-oCancel reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.