Using a Measurement Computing PMD-1608FS with Ubuntu Linux
A Measurement Computing PMD-1608FS.
This is something I had in a drawer for many years gathering dust. It is a useful device
for interfacing with the "real world" (of electrical signals) and provides 8 16-bit analog
inputs that can be sampled at 100k samples/second (the sampling is simultaneous on all 8
channels) as well as 8 digital i/o lines and a counter. It dates from around 2004 and I
suspect it is no longer available, although very similar devices probably are.
Eventually, I had a couple of applications for it. One was to measure the temperature of
a heatsink over a period of a few hours. The other was to control a stepper motor I had
bought off E-Bay (with the intention of making a movie film digitizer - haven't got very
far with that yet!)
As usual, the thing came with software for Windows. But I wanted to use it in Ubuntu Linux.
Same old story. Fortunately, most of the hard work involved had been done
by Warren Jasper at North Carolina State University. His code is (partially) used in what
follows, and it is licensed under GPL V2. Hence my code is also, in this case, licensed
under GPL V2. Warren Jasper's code can be found
The device is accessed as a USB HID device with user mode code. There is no specific
kernel driver component. A very slimmed down, PMD-1608 specific,
version of Warren Jasper's code is to
be found in pmd.c in the software described below.
It seems that one of the main markets for this device (and similar ones from Measurement
Computing) is in the field of experimental psychology! At least, most of the people using
these things under Linux seem to be using them for that sort of research.
This device is very much like a modern version of the DEC AR-11 interface I had on a
PDP-11/10 back in 1980.
The pmd1608FS and PMD1608Wrap Software
The software I wrote for the PMD-1608FS can be found here.
Documentation (generated by Epydoc) can be found here.
As with the code I wrote for controlling GPIB instruments, this software has two main parts:
The Python wrappers in PMD1608Wrap.py are intended to be the user level access to the
- A minimal C++ library: pmd1608FS.cpp.
This defines a PMD1608FS C++ class which
provides functions for: opening the device and reading calibration data specific to it (i.e.
specific to this exact instance, determined by its serial number), functions for digital i/o
a function to read an analog voltage from a specified channel, and functions to read and
reset the counter. This is compiled in to a .so shared object library.
- Python wrappers in PMD1608Wrap.py
that access the C++ library (or, strictly speaking, C wrappers for
various C++ class members) via C-types. This file defines a PMD1608 class which handles
interfacing with the device, and a Stepper class that may be useful for controlling
2-Y stepper motors (well - I have only tried it with one sort, so I'm not sure).
Before using the device, it is necessary to create a calibration table for it. This
is unique to a particular device and lets you read back volts with reasonable accuracy. The
raw sample values are not reliably related to volts without calibration.
Before calibrating (see below), create a directory called:
/usr/local/pmd1608fs and make sure everyone can write to it.
sudo mkdir /usr/local/pmd1608fs
sudo chmod a+rw /usr/local/pmd1608fs
To calibrate, first
wire the Cal Out terminal on the device to all the analog inputs (in parallel). Then
run the program calibrate (which is built from calibrate.cpp. This calls
PMD1608::calibrate() (defined in PMD1608FS.cpp which obtains
sample value versus calibration voltage data and finds the slope and intercept of
a best fit line through that. This data (for each channel) is saved to a file called:
caltab_(serial).cal. Serial is the serial number of the PMD-1608, which the software
reads from it. Calibration should probably be done every few months to maintain accuracy as
things drift. Although, maybe it isn't vital to do this.
Some examples of using the PMD-1608FS are given in PMD1608Wrap.py and can be run
This code is shown below.
if __name__ == '__main__':
if( False ):
d = PMD1608()
for i in range(0,8):
print d.read_channel( i, '1V' )
d.set_bit_out( 0 )
d.write_bit( 0, 0 )
for i in range(0,100):
d.write_bit( 0, 1 )
d.waitms( 100 )
d.write_bit( 0, 0 )
if( True ):
s = Stepper()
s.set_mode( 'full' )
for j in range(0,1):
for i in range(0,10):
aerr = s.goto_angle(37.5)
print 'Go to 37.5, error=', aerr, ' angle=', s.get_angle()
The first of the two examples reads analog data in the 1V range from all 8 channels.
It then sends 100 100ms long pulses out from digital i/o port 0, reading the counter
value after each pulse. If the DIO 0 terminal is connected to the counter in terminal,
the counter will count up to 100 over 10 seconds (approximately).
The second example puts a Muirhead-Vactric 23MR302 stepper motor through its paces. This
may well not be generally useful! Although looking at the code for the Stepper
class may give useful hints about adapting it to other, similar, situations.
The graph below (plotted with GPLOT/GTerm on an emulated CDC mainframe) shows data logged
by the PMD-1608 using this software, looking at a power supply heatsink cooling down. The
temperature was measured with an LM-35 based probe.
Temperature of a heatsink cooling down.
I hope this software might be of some use to people other than myself.
Feel free to do anything you like with it, although I'd be grateful if
you acknowledged where it came from if you do use it.
Go home ...