Introduction - why would you want to extend I/O over USB?
The Beaglebone Black's PRU allows very high speed I/O capabilities with guaranteed timing while Linux applications continue to run. As useful as this is, occasionally there may be a need to use FTDI's USB-interfacing UART/FIFO ICs to extend capabilities further. There are a number of benefits to this:
* It increases the number of I/O pins available
* It increases the number of serial interfaces
* Provides interfacing to traditional peripherals that require *CS, *RD, *WR signals and an 8-bit data bus
* High speed parallel data transfer (60MHz) in a FIFO mode
* Portability so that applications can run on any device with a USB port
In theory the notes here should work just fine for other processor boards too, e.g. RPI, but clearly having a good USB capability (and the processing power to handle high-speed parallel data transfer is important - and the BBB is the ideal platform).
Some example applications could also be listed, but it's clear the possibilities are vast. Another benefit is that it is possible to easily enable a USB interface on custom hardware, by simply adding a FTDI chip to the project. It's only fair to mention that there are alternative, possibly lower cost methods too. People have successfully shoe-horned small USB stacks into small PIC and AVR microcontrollers that do not possess a native USB interface. Atmel offer ATmega devices that already contain USB capability, at very little cost.
Other manufacturers like Silabs, Exar and Cypress produce devices with similar capabilities to FTDI devices too.
Is it easy?
It turned out to be surprisingly easy - almost no soldering if a pre-built board is used, and very little coding. For creating a custom board (e.g. with your own peripherals on it), FTDI devices don't need a lot of additional circuitry.
There are quite a few similar-sounding part codes, but the FT2232H (PDF datasheet) has been on the interest list for quite a while - working with the BBB provided the opportunity to finally experiment with it. For clarity, it is the FT2232H range, available in a QFP package as part code FT2232HL-R.
Connecting up the FT2232H to the BBB
Like most of FTDI's chips, it doesn't take a lot of circuitry to assemble, however in this case I just used a pre-built board available from Seeed Studio for a quick prototyping exercise.
Connecting this to a BBB is trivial - just plug in the USB connector and it will power up from the 5V offered by the BBB's USB host port. For experimentation, I tried the so-called bitbang mode, which provides 16 pins of I/O in two banks of 8. Of more interest will be the FIFO modes for high-speed data transfer at up to 60MHz.
When plugged in, lsusb reveals the following:
root@beaglebone:~# lsusb Bus 001 Device 003: ID 0403:6010 Future Technology Devices International, Ltd FT2232C Dual USB-UART/FIFO IC Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub root@beaglebone:~#
Note the 0403:6010 - this is the vendor and product ID respectively, in hex (needed later). The board doesn't come with any connector, so SIL headers need to be soldered. The reverse of the board shows the pin naming, and the circuit diagram is here.
The bitbang mode is brought out to the ADBUS[7..0] and BDBUS[7..0] pins. For input testing, I just pulled various pins high and low (i.e. to 3.3V and 0V) through a 1k resistor (in case a pin was accidentally still an output) and for output testing a multimeter was used (an LED and resistor would be fine too).
Generally, hi speed I/O may require kernel drivers; in the case of the FT2232H this is no different, but it is already part of Linux images. Some code and libraries are required as part of the application. This is explained in the diagram below.
The application software will be the area of interest, where the data is received and transmitted and any processing with the end data is handled. To connect to the kernel driver, a couple of libraries of code need to be linked in to the application code; these are libftdi (open source library for many FTDI ICs) and libusbx which provides a consistent API regardless of if the OS is Linux or Windows.
Building the software
This was quite simple; three downloads are required:
libftdi (download here) - I used version 1-1.0
libconfuse (download here) - version 2.7 - this is used for parsing text files for configuration purposes
libusbx (download link) - version 1.0.16
Create a folder off your home directory (e.g. called 'development') and create a folder called usb inside it.
The three downloads were extracted in the usb folder.
Installing libconfuse 2.7:
./configure make make install
(installs in /usr/local/include,lib and share)
For libusbx 1.0.16:
./configure --disable-udev make make install
(installs in /usr/local/libusb-1.0 and /usr/local/lib)
For libftdi 1-1.0, the makefiles are intended to be built with cmake, which I didn't have installed (and is a little unfamiliar to me) - however it is possible to build the code from the command line easily, there are not a lot of commands.
In the folder where libftdi was extracted, traverse to the 'src' folder. Then copy ftdi_versio_i.h.in to ftdi_versio_i.h and replace the variables marked with '@' with a custom value. In other words, modify the following lines so that this is how they appear, and then save the file.
#define FTDI_MAJOR_VERSION 1 #define FTDI_MINOR_VERSION 1 #define FTDI_MICRO_VERSION 0 const char FTDI_VERSION_STRING = "1-1.0"; const char FTDI_SNAPSHOT_VERSION = "0";
In the same src folder, compile like this:
gcc -c ftdi.c -I/usr/local/include/libusb-1.0 gcc -c ftdi_stream.c -I/usr/local/include/libusb-1.0 ar rs libftdi.a ftdi.o ftdi_stream.o cp libftdi.a /usr/local/lib/. cp ftdi.h /usr/local/include/.
Now the code in ftdi_eeprom can be compiled (path is development/usb/libftdi1-1.0/ftdi_eeprom). It requires a file ftdi_eeprom_version.h to be created in a similar manner as before.
#define EEPROM_MAJOR_VERSION 1 #define EEPROM_MINOR_VERSION 1 #define EEPROM_VERSION_STRING "1-1.0"
Type these commands to compile it:
gcc main.c -I/usr/local/include/libusb-1.0 -I/usr/local/include -I. -L/usr/local/lib -lftdi -lusb-1.0 -lconfuse -o ftdi_eeprom cp ftdi_eeprom /usr/bin
Then example code files can be compiled as shown here for instance (path is development/usb/libftdi1-1.0/examples):
gcc simple.c -I/usr/local/include/libusb-1.0 -I/usr/local/include -L/usr/local/lib -lftdi -lusb-1.0 -o ftdi_simple cp ftdi_simple /usr/bin
There is an another example program in the same folder, called bitbang_ft2232.c but it needs a small change; replace where it says 0x6001 (product ID) with 0x6010 in two places, and then compile:
gcc bitbang_ft2232.c -I/usr/local/include/libusb-1.0 -I/usr/local/include -L/usr/local/lib -lftdi -lusb-1.0 -o bitbang
When the bitbang program is run, it will just slowly toggle some pins (bits 0 and 1) on the two ports.
As an experiment, the code was modified to toggle pins with no delay for thousands of times; a speed of about 20,000 writes per second is possible, allowing for 10kHz square-waves (this was not measured on a scope, so it is just a guideline). Bitbanging in this manner will not have real-time accuracy like the PRU. (The FIFO mode that the FT2232H is capable of will be far better than bitbanging too, but needs to still be tested. However, bitbanging is still suitable for some purposes). Note: See comments section below. Accuracy is extremely poor with the bitbang way; an alternative method using buffers is available on the FTDI and that method should be investigated.
A quick program was created to test inputs in bitbanging mode too, and it reads input values at a similar speed. The program is attached (very untidy for now - it's late in the evening! but it works). The program reads the AD[7..0] pins repeatedly, and displays the 8-bit value in hex on the screen. Run it, and it will display lots of 0xff on the screen (the inputs appear to float high) and pulling low (1k resistor to 0V) on any of the input pins will make the text change.
To compile the code:
gcc bbtest.c -I/usr/local/include/libusb-1.0 -I/usr/local/include -L/usr/local/lib -lftdi -lusb-1.0 -o bbtest
Summary / Next Steps
To a large extent the PRU capability has rendered this almost redundant, but it's good to know that it is easy to interface high-speed data in several ways with the BBB now. The FTDI device is easy to use because a ready-built board is available, but equally it is easy to include the IC on a PCB where a USB interface is not currently available. Experimenting with the FIFO modes will be interesting.
Part 2: FIFO mode
A "synchronous FIFO" mode is available on the FT2232H, which is supposed to allow far higher rate I/O. In order to enable this, an EEPROM needs to be programmed. There is a ftdi_eeprom program that was compiled earlier (see above), however it did not work. The alternative is to just download a Windows executable called FT_PROG and use that.
Run FT_PROG, click on the magnifying glass icon ("scan and parse") to read the board EEPROM. It will display as lots of FFFF, since it is a blank part.
On the left side device tree, expand to FT EEPROM->Hardware Specific->Port A->Hardware, and change the property from RS232 UART to 245 FIFO, which is needed for the FIFO modes to function. Repeat for Port B.
Then, go to File->Save as Template (e.g. my245fifotemplate.xml).
Select the Device:0 on the device tree, right click, and select 'Program device'. It should be virtually instantaneous, and the Device Output will show some new values instead of FFFF.
You could confirm all is well by restarting the FT_PROG application and clicking the scan icon again, and viewing the EEPROM contents.
Once this is done, unplug the FT2232H from the Windows maching and plug it back into the BBB. There is code in the examples folder called stream_test.c, and it is compiled in a similar manner as the other examples:
gcc stream_test.c -I/usr/local/include/libusb-1.0 -I/usr/local/include -L/usr/local/lib -lftdi -lusb-1.0 -o ftdi_stream_test cp ftdi_stream_test /usr/bin
The program can be run by typing:
ftdi_stream_test -n dump.bin
It will capture data at a very high speed and dump to a file (unformatted raw bytes), whenever the *WR pin (pin 27 on the FT2232H-R chip, or P3_17 (ACBUS3) on the ready-built board is pulled low.
The '-n' suppresses error messages when bytes are skipped.
It appears that bytes are guaranteed to skip, and I'm guessing this is because there is a delay writing to the filesystem. With a very short *WR pulse (of the order of tens of nsec) the number of bytes written to file appear to be close to the expected value (assuming that the FT2232H is trying to capture at 60MHz). At any longer pulse, bytes are skipped. For further investigation!
bbtest.c.txt.zip 1.0 KB