Mex-File Plug-in for Fast MATLAB Port I/O Access
(32-bit MATLAB on 64-bit Windows XP, Vista, 7)


Prior to R2013a, the student version of MATLAB installed as a 32-bit application...even on 64-bit Windows.
This document describes how to setup and run the 64-bit inpoutx64.sys driver on 64-bit Windows and then access it via the IO32 mex file interface in a 32-bit MATLAB application.
A version of this software for 64-bit MATLAB on 64-bit Windows can be found here.
A version of this software for 32-bit Windows operating systems can be found here.

Windows Vista and Windows 7 (32-bit users) should note the Vista Installation Notes near the end of this document.

In order to accomplish very fast port I/O using a NO COST add-on to MATLAB, we have developed a C++ extension (mex-file) that uses native methods to access low-level hardware.  This 32-bit mex-file is named io32.mexw32.  It uses a freeware self-installing kernel-level system driver that is exported from a dynamic link library named inpout32a.dll. [Note: Self-installation of the driver requires that the MATLAB be run with Administrator privileges.  The driver must have been previously installed in order to support non-Administrator users].

To install this expanded capability: download the io32.mexw32 module and move it to a directory in your MATLAB path (e.g., c:\cog2000\Cogent2000v1.29\Toolbox in the case of the USD PSYC 770 standard Cogent 2000 installation specification).  Users of older versions of MATLAB 7 should rename io32.mexw32 to io32.dll (since 32-bit mex files used to use the .dll suffix rather than the more informative .mexw32 suffix currently in use).  Next, download the inpout32a.dll module and move it to the C:\windows\sysWOW64 directory.
 

io32() Command Usage Summary:

object = io32; Calling io32 with no input arguments from the MATLAB command window creates an instance of the io32 interface object and returns a pointer to its location.  This command must be issued first since the object pointer is a required input argument for all other calls to io32.  This io32 call will not work properly unless a return variable is specified (i.e., 'object' in the example to the left).
status = io32( object ); Calling io32() using one input argument and a single return variable causes the inpoutx64.sys kernel-level I/O driver to be extracted from inpout32a.dll and automatically installed (i.e., no manual driver installation is required).  object is the pointer to a previously created instance of io32 (see the step performed above); and, status is a variable returned from the function that describes whether the driver installation process was successful (0 = successful).  Subsequent attempts to perform port I/O using io32() will fail if a non-zero status value is returned here.  This step must be performed prior to any subsequent attempts to read or write I/O port data.
io32( object, address, data ); Calling io32() with three input parameters allows the user to output data to the specified I/O port address.  object is the pointer to a previously created io32 object (described above); address specifies the physical address of the destination I/O port (<64K); and, data represents the value (between 0-255) being output to the I/O port.
data = io32( object, address ); Calling io32() using two input arguments and one return variable allows the user to read the contents of the specified I/O port.  object is the pointer to a previously created instance of io32 (see above), address specifies the location of the I/O port being read; and, data contains the integer-format value returned after reading the I/O port.


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

%create an instance of the io32 object
ioObj = io32;
%
%initialize the inpoutx64 system driver
status = io32(ioObj);
%
%if status = 0, you are now ready to write and read to a hardware port
%let's try sending the value=1 to the parallel printer's output port (LPT1)
address = hex2dec('378');          %standard LPT1 output port address
data_out=1;                                
%sample data value
io32(ioObj,address,data_out);  
%output command
%
%now, let's read that value back into MATLAB
data_in=io32(ioObj,address);
%
%when finished with the io32 object it can be discarded via
%'clear all', 'clear mex', 'clear io32' or 'clear functions' command.


MATLAB Scripts to Simplify Port I/O

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

In order to have access to these scripts: download the io32.mexw32, config_io.m, inp.m and outp.m files and move them to a directory in your MATLAB path. In addition, download the inpout32a.dll module and move it to the C:\windows\sysWOW64 directory as previously described above.

MATLAB I/O Script Usage:

config_io; Installs the inpoutx64.sys driver required to access low-level hardware.  This command must be given prior to any attempts to use the custom inp() or outp() scripts.
outp( address, byte ); This function writes the 8-bit value passed in the variable named byte to the I/O port specified by address.
byte = inp( address ); This function read the I/O port location specified by address and returns the result of that operation.

A simple benchmark (iotimer_inp.m) reveals that I/O using these scripts is significantly slower than calling the io32() object directly (as demonstrated above).  Instead of being able to read a port with a latency of approximately 10 microseconds, using the inp() script yields a latency of approximately 40 microseconds. This is fast enough for many experimental psychology applications (such as scanning a button box, etc.).  Use direct calls to io32() if your application requires the shortest possible I/O latencies (e.g., updating an analog output stream).

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

%initialize the inpoutx64 low-level I/O driver
config_io;
%optional step: verify that the inpoutx64 driver was successfully installed
global cogent;
if( cogent.io.status ~= 0 )
   error('inp/outp installation failed');
end

%write a value to the default LPT1 printer output port (at 0x378)
address = hex2dec('378');
byte = 99;
outp(address,byte);

%read back the value written to the printer port above
datum=inp(address);

Reaction Time Benchmark/Results

Since our lab uses low-level digital I/O to control stimuli and/or collect human response times with millisecond accuracy requirements, we developed a io32() timing benchmark that mimics a classic "reaction time" protocol.  This approach involved building a hardware-based Reaction Time Simulator that produces an output "response" precisely 200 msec after receiving a "stimulus" input from the system under test (see RT Simulator for additional details and a hardware schematic diagram). 

The temporal latency of the MATLAB io32() module was assessed by triggering the black box RT Simulator via the PC's Line Printer (LPT) Data Register bit-0 (connector pin 2) and monitoring the arrival time of the "response" from the RT Simulator via LPT Status Register bit-4 (connector pin 13).  See Printer Port for additional details about the PC's legacy printer port I/O interface.

The elapsed time recorded between the stimulus output and the response input given an "ideal system" would always be exactly 200 msec.  In order to characterize the latency behavior our real systems we collected "reaction times" for 200 consecutive trials (each separated by an intertrial interval of 200 msec).  The statistical results summarizing these tests performed on two different computers running MATLAB 2008b on Windows XP and Windows Vista are reported in Table 1 (below).  The standard deviations of the latency distributions were extremely small (worse case was 31 MICROSECONDS) and the range separating the shortest latency from the longest latency was a mere 0.147 msec (147 microseconds).  These results clearly indicate that low-level digital I/O implemented via MATLAB io32() on Windows-based computers is capable of the temporal precision needed to support the most demanding behavioral research protocols.

  Mean Standard Deviation Minimum Maximum Range
Windows XP Pro (SP3)
Dell Inspiron 600m; 1 GB RAM
Intel Pentium M @ 1.7 GHz
 
200.159 0.021 200.108 200.235 0.127
Windows Vista Business (SP2)
HP dc7900; 4 GB RAM
Intel Core Q9550 @ 2.83 GHz
200.066 0.031 200.010 200.152 0.147

Table 1.
Results of io32() benchmark latency tests using external 200 msec Reaction Time Simulator
(Statistics based on 200 consecutive trials.  All times reported in milliseconds)

Windows Vista and 7 Installation Notes

Although our lab does not yet have much experience with Windows Vista, we were able to successfully install the software described above using the procedure described below (using MATLAB 7.5.0-R2007b and MATLAB 7.7-R2008b):

1. Log in as a user with Administrator privileges.
2. Disable UAC (User Account Control).  An easy way to do this in Windows Vista is to: Start-Run-MSCONFIG. Select the Tools tab, scroll down to the option for "Disable UAC" and select it. Next, press the "Launch" button. You must then RESTART the system for this change to take effect.
3. Download and copy the inpout32a.dll file to the C:\windows\sysWOW64 directory.
4. Download the io32.mexw32, config_io.m, inp.m and outp,m files to a working directory of your choice. This directory will be added to your MATLAB path in step-6 below.
5. Start MATLAB in "Run as Administrator" mode (Right-click icon and select "Run as Administrator").
6. Add the directory containing the downloaded m-files to your MATLAB path via the File|Set Path|Add with Subfiles... menu command.
7. Run "config_io" from the MATLAB command window.  If there's no error message at this point, you've successfully installed the software.
8. Optional: If you need to re-enable UAC (User Account Control), follow the instructions in step-2 but select "Enable UAC" instead of "Disable UAC".

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 inp(address). 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 an input port at the specified address
% Note that the value returned by inp(address) is coerced into an 8-bit format using uint8
response = uint8( inp(address) );
% Take some action if the least-significant-bit is currently at logical-0 level
if (bitget( response,1) == 0)
   display('Input is active')
end

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


Additional information about the freeware INPOUTX64 driver for 64-bit Windows XP/Vista/7 can be found here.
Special thanks to Phil Gibbons (www.highrez.co.uk) for providing the signed 64-bit version of the inpoutx64.sys kernel-level driver.
Versions of this software for 32-bit Windows systems can be found here

Last revised: 3 May 2010


Professor Schieber's Home Page - Previous Page