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 here.

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:
  • 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 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).
The Python wrappers in are intended to be the user level access to the device.

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 and can be run using:
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 )
            print d.read_counter()

    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 ...