MATLAB Mex-File for Fast USB-based Asynchronous I/O
Using an FTDI USB-to-Parallel I/O Device
(32/64-bit Windows XP, Vista, 7)


Introducing the FTDI UM245R USB-to-Parallel Interface
UM245R Data Sheet      FT245R Data Sheet

A simple, reliable, fast and inexpensive approach to reading and writing to an 8-bit digital I/O interface can be achieved using the FTDI FT234R USB-to-Parallel interface module (cost: approximately $20).  A photograph of the UM245R development module (which contains a FT245R device with easily accessible pin outs) is shown in Figure 1. This device allows the developer to quickly read and/or update the states of 8 digital I/O lines over a USB interface.  The FTDI drivers and programming API are free of charge and easily downloadable from the FTDI website.  The 8 I/O lines are depicted as pins DB0-DB7 in Figure 2.  The directionality (i.e., input vs. output functionality) of these 8 lines is completely programmable (i.e., any combination of input and output lines can be configured by the user).  MATLAB code for accessing this device is presented below.

Figure 1.
FTDI's UM245R Development Module

Figure 2.
UM245R pin descriptions and layout

How fast can the UM245R's I/O lines be read via MATLAB

In order to determine the time required to read the UM245R device, a benchmark program that measures the latencies of 10,000 consecutive USB reads (in a tight loop) was developed.  This simple benchmark (testUSB245.m) utilized a MATLAB mex file developed in C++ which allows MATLAB to communicate with the FTDI kernel-level USB driver via the FTDI API library functions (ftd2xx.dll).  More details regarding the use of this custom MATLAB mex function, named USB245.mex32, are presented below.

The distribution of USB read time latencies obtained via this benchmark program is graphically represented in Figure 3.  As can be seen, the latencies are relatively brief (mean = 3.99 msec) and tightly cluster around the mean value (standard deviation = 0.008 msec).  The complete time series depicting the read time latencies observed across all 10,000 trials can be seen in Figure 4.  This remarkably consistent 4 msec latency is highly representative of the behavior of the FTDI USB driver as it can be observed every time the benchmark is run.  See Figures 6 and 7 (bottom of page) for benchmark results obtained on a 64-bit Windows platform (Spoiler alert: consistent sub-millisecond latencies were observed).

 

Benchmark Computer: MATLAB 7.7 (R2008b); FTDI ftdibus.sys Version 2.08.14 driver; Windows Vista 32-bit; Intel Q9550 @ 2.83 GHz; 4 GB RAM; Cogent 2000 mode (see bottom of page for 64-bit benchmark results).

 

 

Figure 3.
Distribution of times required to read input status from an FTDI UM245R USB-to-PARALLEL device.

 

Figure 4.
Time required to read USB-to-Parallel device over 10,000 successive trials.

Computer Setup
The FTDI USB driver installation package can be download an run from the following link: FTDI Driver Downloads
Detailed information about the FTDI driver installation process can be found at FTDI Driver Installation Guidelines
Manual installation of the drivers is recommended as problems sometimes occur when drivers are loaded automatically via an internet connection upon plugging in the UM245R device.

After you have installed the drivers, plug the UM245R module into the computer using the appropriate USB cable. 
Once the computer has successfully recognized the FTDI UM245R device and loaded its drivers the computer will be ready to use the USB245() mex function.

Download USB245.mexw64 (for 64-bit MATLAB) and move it to a directory in your MATLAB path.
Follow the examples below to test the functionality of the MATLAB-UM245R USB interface. Enjoy!

USB245() Command Usage Summary:

device = USB245() Calling USB245() with no input arguments from the MATLAB command window (or script) creates a persistent MATLAB object that can be used to interact with the USB-based UM245R device.  If successful, a 64-bit handle to the interface is returned.  A zero is returned if unsuccessful.  This function call must be made prior to any subsequent use of USB245() since all subsequent applications require the device handle as an input parameter.
status = USB245( device ) Calling USB245(device) with the device handle as the only input parameter and a single return variable searches for the FTDI USB device and loads the FTD2XX.dll library if it is found (This routine assumes that the UM245R module is the one and only FTDI device currently plugged into your computer).  A zero is returned if the library initialization was successful.  This version of the initialization function uses the default setup of the 8 I/O lines available on the UM245R device: digital lines D0-D3=inputs and digital lines D4-D7=outputs.  See below if you need a different mix of I/O line directionality.
status = USB245(device, iomask) Calling USB245(device, iomask) with the device handle parameter followed by an iomask allows the user to configure the 8 bidirectional I/O lines of the UM245R.  The iomask is an 8-bit number ranging from 0 (all bits off) to 255 (all bits on).  Each of these bits represents the "direcionality" (i.e., input vs. output) of one of the UM245R's I/O lines.  The least significant bit (bit 0) represents the directionality of the D0 line while the most significant bit (bit-7) represents the directionality of the D7 line.  If the bit representing a given I/O line is set to '1' then that line will be configured as an output; if zero, the line will be configured as an input.  For example: setting iomode to 0 (binary: 00000000) would configure all of the I/O lines as inputs.  Setting iomode to 255 (binary: 11111111) would configure all of the I/O lines as outputs.  Setting iomode to 240 (binary: 11110000) would configure lines D0-D3 as inputs and lines D4-D7 as outputs.  Setting iomode to 15 (binary: 00001111) would configure lines D0-D3 as outputs and lines D4-D7 as inputs.  A zero is returned if the initialization and configuration of the UM245R device was successful.  This command should be used in lieu of the USB245(device) command (described above) if you require an I/O directionality the differs from the default configuration.
data = USB245( device, 0, 0 ) Calling USB245(device, 0, 0) using the device handle followed by two parameters (each set to zero) returns the current status of the 8-bit bidirectional I/O port on the UM245R device (i.e., digital lines D0 through D7).  Reading the FTDI USB device is implemented via a call to the FT_GetBitMode library function.  Benchmark testing (see Figure 1 above) reveals that the latency of this read operation is somewhere in the range of 4 (± 0.008) msec; reliable enough for most applications in behavioral research (e.g., reaction time assessments).
status = USB245( device, 1, data) The output lines of the 8-bit directional I/O port on the UM245R USB device can be updated by calling USB245() with three input parameters: the first parameter must be the device handle (supplied by the initial call to USB245(), followed by a second parameter set to 1, and a third parameter containing the data value to be transmitted tot he USB device.  The USB write latency is approx. 2 msec.



The following MATLAB command snippet demonstrates how to use the USB245() extension:

% create a USB245 persistent interface object
clear USB245;          % delete any previous copies of USB245 from the MATLAB workspace
device = USB245();  % fetch handle to persistent USB245 interface object
%
% initialize the interface and UM245R device to the default I/O configuration
status = USB245(device);   % initialization success indicated by status=0
% let's try reading an 8-bit value from the UM245R device
data = USB245( device, 0, 0 );
%
% now, let's write a value of '128' to UM245T's digital output port
output = 128;
status=USB245( device, 1, output );
 

MATLAB Scripts to Simplify USB I/O

The code examples above reveal that using the USB245() mex extension is a bit awkward.  In an attempt to reduce this complexity, a set of MATLAB scripts has been developed to simplify USB I/O programming.

In order to have access to these scripts: download USB245.mex64 (for 64-bit MATLAB), config_ftdi.m, config_ftdi2.m, readUSB245.m and writeUSB245.m and move them to a directory in your MATLAB path.

MATLAB Simplified Script Usage

config_ftdi; Initializes the FTDI UM245R USB I/O device to the default configuration: i.e., D0-3=inputs, D4-7=outputs.  This command must be given prior to any attempts to use the readUSB245() or writeUSB245() scripts.  Global variable cogent.io.ftdiStatus = 0 if successful.
config_ftdi2( iomask ); Initialize the FTDI UM245R USB I/O device using a custom configuration specified by the 'iomask' parameter.  The iomask is an 8-bit number ranging from 0 (all bits off) to 255 (all bits on).  Each of these bits represents the "direcionality" (i.e., input vs. output) of one of the UM245R's I/O lines.  The least significant bit (bit 0) represents the directionality of the D0 line while the most significant bit (bit-7) represents the directionality of the D7 line.  If the bit representing a given I/O line is set to '1' then that line will be configured as an output; if zero, the line will be configured as an input.
data = readUSB245; This function reads and returns the current status of the UM245R device's 8-bit bidirectional I/O port.
writeUSB245( data ); This function writes the contents of data (range: 0-255) to the UM245 device's 8-bit bidirectional I/O port.

The following MATLAB code snippet demonstrates how to use the simplified m-file I/O scripts:

% initialize the UM245R interface
config_ftdi;
%confirm that the initialization was successful
global cogent;  %expose global variable structure
if (cogent.io.ftdiStatus == 0)
   display('UM245R initialization was a success!');
end
% write a value of 0 to the USB 8-bit bidirectional I/O bus
% to "reset" all of the output lines
writeUSB245( 0 );
%
% read the current state of the USB input port
data = readUSB245;

Parsing Individual Bits within an I/O Byte

When one reads an I/O port one is usually interested in the status of a single bit among the 8-bits returned by a call to readUSB245(). MATLAB provides a number of functions to deal with data on a 'bitwise' basis.  For example, the following lines of code show how to test the status of a single input line using the bitget() function:

% Read current value of the bidirectional I/O port
% Note that the value returned by readUSB245() is coerced into an 8-bit format using the uint8() function
clear all;
config_ftdi;
response = uint8( readUSB245 );
% Next, take some action if the least-significant-bit (representing the UM245R's D0 line) is currently at logical-0 level
if (bitget( response,1) == 0)
   display('Input is active')
end
% Take some action if the UM245R's D3 line is currently at logical-1 level
if (bitget( response,4) == 1)
   display('Input is active')
end

See also: bitset(), bitand(), bitor(), bitxor() for additional MATLAB bitwise operators

Where to Buy the UM245R Development Module
(You will also need a Type-A Male to Type-B Male USB cable   What's that?)

Mouser Electronics UM245R Catalog Page
DigiKey's UM245R Catalog Page

 

Fig. 5: Sample Setup for Testing the UM245R Hardware [Another sample circuit: 12vdc solenoid driver]

MATLAB Code for Exercising the Test Circuit

% load interface library and initialize the UM245R hardware
 % default configuration: DB0-DB3=inputs, DB4-DB7=outputs
 config_ftdi;
 %
 %turn-on the LED by making DB7 output line go "high"
 writeUSB245( 128 );
 %
 %turn-off the LED by making DB7 output line go "low"
 writeUSB245( 0 );
 %
 % read the state of the 8 bidirectional I/O lines (DB0-DB7)
 %note: data will reflect status of output as well as input lines
 data = readUSB245;
 %
 % after reading the USB I/O port
 % determine the state of the Test Switch connected to the DB0 input line
 if bitget(data, 1) == 0)
      display('The Test Switch is CLOSED')
 else
      display('The Test Switch is OPEN')
 end

64-Bit Benchmark Results



Figure 6.

Figure 7.


64-Bit Benchmark Computer
: MATLAB 7.7 (R2008b); FTDI ftdibus.sys Version 2.08.14 driver; Windows 7 64-bit (SP1); Intel Core i7 Q72@ 1.60 GHz; 8 GB RAM;
Cogent 2000 mode (see top of page for 32-bit benchmark results).  Note: The 64-bit benchmark exhibits much shorter mean latency.


Last revised: 27 September 2019


Professor Schieber's Home Page - MATLAB for Psychologists Page