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


Note: The software described below currently supports 32-bit versions of Windows (2000,/XP/Vista/7). 
A version of this software for 64-bit Windows can be found here.
A version for running 32-bit MATLAB on 64-bit Windows can be found here.

Windows Vista and 7 users should note the Vista Installation Notes near the end of this document.

In order to accomplish very fast digital 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 mex-file is named io32.dll.  It uses a freeware self-installing system driver named inpout32.dll. [Note: Self-installation of the driver requires that the MATLAB is 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.dll module and move it to a directory in your MATLAB path (e.g., c:\cog2000\Cogent2000v1.28\Toolbox in the case of the USD PSYC 770 standard Cogent 2000 installation specification).  MATLAB 7.5+ should rename io32.dll to io32.mexw32 to prevent the warning message every time the io32 module is loaded.  Next, download the inpout32.dll module and move it to the C:\windows\system32 directory (or any other directory that is on the computer's system PATH).

 

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 a kernel-level I/O driver named hwinterface.sys to be 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.  Auto-installation of the driver requires ADMINISTRATOR privileges.  Once the kernel-level driver is successfully installed (i.e., the first time the io32 command is run), subsequent users will not require admin privileges.
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 hwinterface.sys kernel-level I/O 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 (0x378)
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.dll, config_io.m, inp.m and outp.m files and move them to a directory in your MATLAB path. In addition, download the inpout32.dll module and move it to the C:\windows\system32 directory (or, C:\WINNT\system32 for Windows 2000 users) as previously described above.

MATLAB I/O Script Usage:

config_io; Installs the kernel-level 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 somewhat 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(), as described above, if your application requires the shortest possible I/O latencies.

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

% install and/or initialize the kernel-level I/O driver
config_io;
% optional step: verify that the driver was successfully installed/initialized
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/7, 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 inpout32.dll file to the C:\WINDOWS\SYSTEM32 directory.
4. Download the io32.dll, 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 INPOUT32 (hwinterface.sys) driver for Windows can be found here.

Last revised: 23 June 2013


Professor Schieber's Home Page - Previous Page