The Cogent 2000 programming environment for developing near-realtime psychology experiments includes a facility for accessing low-level hardware using two methods: data = inportb( port_address) and outportb( port_address, data). In order to use these methods the user must first install a freeware Windows kernel-mode driver called UserPort.sys and then configure this driver using the UserPort.exe utility program. UserPort installation details can be found here.
After running a simple MATLAB benchmark (iotimer_inportb.m) using the inportb() and outportb() methods supplied with Cogent 2000 it was discovered that port I/O using these commands was EXTREMELY SLOW. Reading or writing a single byte to/from an I/O port takes 100 msec with either of these methods.
One approach to achieving faster I/O operations within the MATLAB/Cogent 2000 environment is to use the Data Acquisition Toolbox (DAQ). A simple benchmark (iotimer_daq.m) using the DAQ's getvalue() method to read the LPT1: status port revealed that port I/O operations on the order of 1-2 msec could be achieved. This is fast enough to poll a "button box" attached to the computer's printer port in a choice reaction time paradigm. However, this latency is still rather slow and the Data Acquisition Toolbox must be purchased separately over and above the cost of the MATLAB software supplied on the student edition CDROM.
In order to accomplish very fast port I/O using a NO COST extension to MATLAB, we have developed a Java class called IOReadWrite that uses native methods to access low-level hardware. Once installed, it then becomes simple to import the Java IOReadWrite() class into MATLAB and access its constituent methods for reading (IOReadWrite.read) and writing (IOReadWrite.write) to I/O port locations that have been previously authorized via the UserPort facility described above. A simple benchmark test (iotimer.m) reveals that port I/O latencies of approximately 0.06 msec can be achieved from within MATLAB using this approach.
The instructions for installing and testing IOReadWrite can be found
here.
The software (IOReadWrite.jar and usdportio.dll) can be found
here.
New Problem with UserPort.sys Driver
Discovered
(March 12, 2007)
Although the IOReadWrite Java class extension to MATLAB/Cogent 2000 demonstrates suitable speed for most psychology research applications, a new problem with employing the UserPort.sys driver was recently discovered in our labs. It turns out that UserPort.sys will only work for I/O addresses in the range from 0x000-0x3FF. This is the reason that the UserPort.exe configuration utility will not permit you to enter addresses outside of this range. This was not a problem on legacy computers using ISA I/O cards (i.e., old PC/AT I/O bus cards). However, if one installs a PCI-based I/O card the address assigned by the Windows' Plug 'n Play manager will almost always be in the upper range of the 64K port I/O space. PCI cards with such addresses can NOT be accessed via the UserPort.sys driver. A new approach was needed.
Upon searching the web for a freeware replacement for the UserPort.sys driver, two candidates were identified: PORTTALK and INPOUT32. The IOReadWrite MATLAB extension was successfully implemented and tested using both of these software packages. PORTTALK requires manual installation of the system level driver (just like UserPort) while INPOUT32 self-installs its kernel-level driver whenever its DLL is loaded into memory by an application. For this reason, INPOUT32 was selected for use in the enhanced version of the IOReadWrite MATLAB/Cogent 2000 extension.
The Enhanced IOReadWrite MATLAB I/O module can be found
here.
An alternative approach using a C++ mex-file is described
here
IOReadWrite()
MATLAB/Cogent 2000
Benchmark Results
Cogent 2000 inportb()
Benchmark (iotimer_inportb.m)
Collecting data from 100 consecutive LPT1 Status port reads
Total elapsed time = 10032 msec
Mean latency = 100.32 msec
Max observed = 101 msec
MATLAB Data
Acquisition Toolbox Benchmark (iotimer_daq.m)
Collecting data from 1000 consecutive LPT1 Status port reads
BENCHMARK RESULTS FOR DAQ I/O TEST
Total elapsed time = 1841 msec
Mean latency = 1.819 msec
Max observed = 3 msec
USD.IOReadWrite.read()
Benchmark (iotimer.m)
Collecting data from 10,000 consecutive LPT1 Status port reads
BENCHMARK RESULTS FOR IOReadWrite I/O TEST
Total elapsed time = 614 msec
Mean latency = 0.0608 msec
Max observed = 2 msec