Setting up and using NI USB-GPIB-HS in Raspberry Pi Linux

Intro

While GPIB interface is slowly replaced by USB, LAN and other less popular modern interfaces, lot of instrumentation are still rely on GPIB as industry standard. Majority of production systems and automated measurements setups using GPIB for decades already. All these usually require a host GPIB controller to run program and issue operations over the bus.

Using PC is easiest thing, especially Windows-based machines, as most of vendors already supply ready to use libraries and packages to interface their instruments via GPIB. But if you go little aside, using Linux-based OS, things get tricky very quick, especially for engineers who are not familiar of *nix environment and way of things. Often simple plugging GPIB adapter into system and expecting things to work cause havoc and countless hours wasted, resolving dependencies, compiling pieces of code, tweaking kernels and such.

Disclaimer

Redistribution and use of this article or any images or files referenced in it, in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  • Redistribution of article must retain the above copyright notice, this list of conditions, link to this page and the following disclaimer.
  • Redistribution of files in binary or source form must reproduce the above copyright notice, this list of conditions, link to this page, and the following disclaimer in the documentation and/or other materials provided with the distribution, for example Readme file.

All information posted here is hosted just for education purposes only and provided AS IS. In no event shall the author, National Instruments, Raspberry Pi foundation, or any other 3rd party be liable for any special, direct, indirect, or consequential damages or any damages whatsoever resulting from loss of use, data or profits, whether in an action of contract, negligence or other tortuous action, arising out of or in connection with the use or performance of information published here.

National Instruments GPIB-USB-HS dongle

First, let’s take a look on hardware interface which we will be using in this tutorial.
There are multiple versions of USB-GPIB interfaces from National Instruments, we use previous generation GPIB-USB-HS. There is already newer version available, GPIB-USB-HS+ for about same price ~600 USD new.

Features:

  • Custom ASIC provides maximum IEEE 488.2 performance
  • High-performance GPIB controller
  • No GPIB cable requirement for instrument connection
  • Transfer rates up to 1.8 MB/s (IEEE 488.1) and up to 7.9 MB/s (HS488)
  • License included for NI-488.2

While NI site lists Linux support, it’s declared only for RedHat, Scientific Linux and SUSE. If we want use it with something like Raspberry Pi with it’s Debian-based Linux system we are alone in the wild.


Image 1: NI GPIB USB adapter dongle

Very brief datasheet just covers basic installation and specification.


Image 2,3: NI GPIB USB adapter PCB components and closeup

Main micro-controller to interface USB side is Cypress CY7C68013A, which is EZ-USB® FX2LP™ USB Microcontroller High-Speed USB Peripheral Controller based on 8051.

GPIB side is served by own National Instruments ASIC, TNT5004-AB, which is GPIB Controller with PCI and Generic interfaces. It’s documentation is subject of NDA, but there is public datasheet for GPIB talker/listener only version TNT5002-AB, which brings light to most ASIC’s inner structure. Cypress CY7C1399BN is just 256-Kbit (32K x 8) SRAM to store realtime data during transfers. System clock is generated by 40 MHz generator.


Image 4: Adapter’s processor block diagram

There are also Texas Instruments TLC7733I and Maxim MAX804CSA supervisors, and few other small logic chips. No parts are populated on PCB’s bottom side.

For comparison purposes, here’s photo of older GPIB-USB-B adapter, which using Cypress FX and National Instruments TNT4882C-BT GPIB Controller chipset. Documentation for controller TNT4882*C* chip is also available only under NDA from NI, but talker/listener only version, TNT4882 without C have brief datasheet here


Image 5: Old USB 2.0 NI GPIB-USB-B adapter PCB photograph

Few extra photos of GPIB-USB-HS. Plastic cover is metallized on inner surfaces to aid EMI and shielding.


Image 6,7: Rear view of GPIB-USB-HS PCB and shielded enclosure case

Enough hardware, let’s dig into Linux world to set everything up and try talking some instruments.

Raspberry Pi setup

All information below is tested on Raspberry Pi 1 model B rev 2, using on-board USB connection for GPIB dongle. Two Linux version were tested, RASPBIAN Debian Wheezy and RASPBIAN Debian Jessie. We already go through basic setup doing I2C stuff before, in this article. If you need to setup system from scratch on blank SD card, suggest to reference that article first.

Below we go step by step for whole process of getting GPIB-USB-HS working with Raspberry Pi system. Forum thread on EEVBlog.com from member bingo600 was a great help, and definitely saved loads of time and efforts. While he was using Beiming S82357 and Agilent 82357B, but idea behind flow is exactly same. If you have one of those, be sure to check out Agilent-version of this article

  1. Before we start installing stuff, highly recommended to update current packets. All commands below are issued under admin root rights, so if you don’t usually logon under root, you may need use sudo.
apt-get update
  1. Previously we had to build old headers to use with kernel 3.8.10, but it’s possible to use latest kernel by building kernel headers following rpi-source to build kernel headers for current kernel (follow the example)
wget https://raw.githubusercontent.com/notro/rpi-source/master/rpi-source -O /usr/bin/rpi-source && sudo chmod +x /usr/bin/rpi-source && /usr/bin/rpi-source -q --tag-update
2016-03-07 13:25:38 (4.12 MB/s) - /usr/bin/rpi-source saved [12424/12424]

Current version of kernel I used was 4.1.17+

pi@pi2:~ $ uname -a
Linux pi2.xdevs.com 4.1.17+ #838 Tue Feb 9 12:57:10 GMT 2016 armv6l GNU/Linux
  1. Now execute rpi-source to build headers for system’s kernel.
root@pi2:/repo/new_hdr# rpi-source
 *** gcc version check: OK
 *** Using: /usr/share/doc/raspberrypi-bootloader/changelog.Debian.gz
 *** Latest firmware revision: 3442862c10fab68c2e88d660d2e69c143bb1f00c
 *** Linux source commit: ca312f557513e057c456598528e663fe9d009498
 *** Download kernel source
 *** Unpack kernel source
 *** Create symlink: /root/linux
 *** Create /lib/modules/<ver>/{build,source} symlinks
 *** .config
 *** Module.symvers
 *** make modules_prepare
 *** Help: https://github.com/notro/rpi-source/wiki

This operation take about 5 minutes, so you can go make some coffee/tea to spare waiting.

  1. If you get error about gcc version mismatch like:
root@pi2:/# rpi-source
ERROR:
gcc version check: mismatch between gcc (4.9.2) and /proc/version (4.7.2)
Skip this check with --skip-gcc

Update gcc, but fetching package lists:

apt-get update

And now can install gcc 4.8

root@pi2:/# apt-get install -y gcc-4.8 g++-4.8
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following extra packages will be installed:
  cpp-4.8 libasan0 libgcc-4.8-dev libstdc++-4.8-dev
Suggested packages:
  gcc-4.8-locales gcc-4.8-doc libstdc++6-4.8-dbg libgcc1-dbg libgomp1-dbg
  libitm1-dbg libatomic1-dbg libasan0-dbg libtsan0-dbg libquadmath-dbg
  libstdc++-4.8-doc
The following NEW packages will be installed:
  cpp-4.8 g++-4.8 gcc-4.8 libasan0 libgcc-4.8-dev libstdc++-4.8-dev
0 upgraded, 6 newly installed, 0 to remove and 19 not upgraded.
Need to get 19.6 MB of archives.
After this operation, 58.0 MB of additional disk space will be used.
...

If installation completed successfully, now can setup gcc versions

update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 50
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50
$ gcc --version
root@pi2:/# gcc --version
gcc (Raspbian 4.8.4-1) 4.8.4
Copyright (C) 2013 Free Software Foundation, Inc.

Used gcc version can be changed by running

update-alternatives --config gcc

#4 Run *rpi-source* to get kernel stuff done. Now libraries and additional packages can be installed
root@pi2:/repo/new_hdr# apt-get install tk-dev
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following extra packages will be installed:
  libfontconfig1-dev libtcl8.6 libtk8.6 libxext-dev libxft-dev libxrender-dev
  libxss-dev libxss1 tcl tcl-dev tcl8.6 tcl8.6-dev tk tk8.6 tk8.6-dev
  x11proto-render-dev x11proto-scrnsaver-dev x11proto-xext-dev
Suggested packages:
  libxext-doc tcl-doc tcl-tclreadline tcl8.6-doc tk-doc tk8.6-doc
The following packages will be REMOVED:
  tcl8.4 tcl8.4-dev tk8.4 tk8.4-dev
The following NEW packages will be installed:
  libfontconfig1-dev libtcl8.6 libtk8.6 libxext-dev libxft-dev libxrender-dev
  libxss-dev libxss1 tcl tcl-dev tcl8.6 tcl8.6-dev tk tk-dev tk8.6 tk8.6-dev
  x11proto-render-dev x11proto-scrnsaver-dev x11proto-xext-dev
0 upgraded, 19 newly installed, 4 to remove and 19 not upgraded.
Need to get 4,651 kB of archives.
After this operation, 6,192 kB of additional disk space will be used.
Do you want to continue? [Y/n] Y

Preinstall rest of the packages and libraries, to make sure dependency are met correctly.

apt-get install build-essential texinfo texi2html libcwidget-dev libncurses5-dev libx11-dev binutils-dev bison flex libusb-1.0-0 libusb-dev libmpfr-dev libexpat1-dev tofrodos subversion autoconf automake libtool
  1. Now install linux-gpib itself. Enter home directory and run next:
root@tin:/home/# mkdir linux-gpib  
root@tin:/home/# cd linux-gpib
root@tin:/home/linux-gpib# svn checkout svn://svn.code.sf.net/p/linux-gpib/code/trunk linux-gpib-code
A    linux-gpib-code/linux-gpib
A    linux-gpib-code/linux-gpib/test
A    linux-gpib-code/linux-gpib/test/runtest
...
...
A    trunk/linux-gpib/examples/ibtest.c
Checked out revision 1647.

Also may be worth to run ldconfig to link all installed libraries

  1. At this moment we have latest linux-gpib from SVN and ready to configure and install it.
root@tin:/home/linux-gpib# cd linux-gpib-code/linux-gpib/
root@tin:/home/linux-gpib/linux-gpib-code/linux-gpib# ./bootstrap
libtoolize: putting auxiliary files in `.'.
libtoolize: copying file `./ltmain.sh'
libtoolize: putting macros in AC_CONFIG_MACRO_DIR, `m4'.
libtoolize: copying file `m4/libtool.m4'
libtoolize: copying file `m4/ltoptions.m4'
libtoolize: copying file `m4/ltsugar.m4'
libtoolize: copying file `m4/ltversion.m4'
libtoolize: copying file `m4/lt~obsolete.m4'
configure.ac:102: installing `./compile'
configure.ac:39: installing `./config.guess'
configure.ac:39: installing `./config.sub'
configure.ac:20: installing `./install-sh'
configure.ac:20: installing `./missing'
examples/Makefile.am: installing `./depcomp'
...
...
  1. Now run ./configure in linux-gpib directory to prepare it for our system environment.
root@tin:/home/linux-gpib/linux-gpib-code/linux-gpib# ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... no
checking for mawk... mawk
checking whether make sets $(MAKE)... yes
checking whether to enable maintainer-specific portions of Makefiles... no
checking build system type... armv6l-unknown-linux-gnueabihf
checking host system type... armv6l-unknown-linux-gnueabihf
checking Linux kernel directory... ok
checking Linux kernel compile flags... Makefile:10: *** mixed implicit and normal rules: deprecated syntax OK
checking for gcc... gcc
  1. Compile and install linux-gpib
root@tin:/home/gpib/linux-gpib-3.2.21# make
make  all-recursive
make[1]: Entering directory '/home/gpib/linux-gpib-3.2.21'
Making all in include
make[2]: Entering directory '/home/gpib/linux-gpib-3.2.21/include'
make  all-am
make[3]: Entering directory '/home/gpib/linux-gpib-3.2.21/include'
make[3]: Nothing to be done for 'all-am'.
...
...
root@tin:/home/gpib/linux-gpib-3.2.21# make install

Configuration for linux-gpib and interfacing

After everything successfully installed without errors, let’s connect GPIB-USB-HS adapter to Raspberry Pi and try to talk with it.

Make sure your Pi powered with good high-current USB cable and +5 VDC power supply with at least 1 Amp , as NI GPIB-USB-HS is taking some decent amount of power and with cheap USB cable connected to PC port it was causing unstable operation, LAN LEDs on Pi were blinking like crazy and nothing worked, as voltage drop too much.

Checking interface connection is simple, just run lsusb to see which devices are present on USB bus:

root@tin:/etc# lsusb
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp.
Bus 001 Device 004: ID 3923:709b National Instruments Corp. GPIB-USB-HS

Unlike old GPIB-USB-B, which need Cypress FX firmware upload after connection, GPIB-USB-HS does not need any firmware uploads and ready to work right from the box.
Let’s load kernel module with modprobe:

root@tin:/home/gpib/linux-gpib-3.2.21# modprobe ni_usb_gpib
root@tin:/home/gpib/linux-gpib-3.2.21#

Should be no error messages here. Can check if module was correctly used as well by lsmod.

root@tin:/home/gpib/linux-gpib-3.2.21# lsmod
Module                  Size  Used by
i2c_dev                 6970  0
i2c_bcm2708             5306  0
ni_usb_gpib            26063  0
gpib_common            31031  1 ni_usb_gpib

Now I tried using gpib_config tool to test operation, but got nasty error instead:

root@tin:/home/gpib/linux-gpib-3.2.21# gpib_config
failed to configure boardtype: ni_usb_gpib
failed to configure board
main: Invalid argument

Oops… After some amount of trial and error, and googling similar issues on web, answer is simple: this is due to actual driver called different name compared to kernel module.
In our case driver for NI GPIB-USB-HS need to be properly selected in interface block, so related configuration on /etc/gpib.conf should follow next example:

interface {
    minor       = 0             /* board index, minor = 0 uses /dev/gpib0, minor = 1 uses /dev/gpib1 */
    board_type  = "ni_usb_b"    /* type of interface board being used */
    name        = "violet"      /* optional name, allows you to get a board descriptor using ibfind() */
    pad         = 0             /* primary address of interface             */
    sad         = 0             /* secondary address of interface           */
    timeout     = T30s          /* timeout for commands */
    eos         = 0x0a          /* EOS Byte, 0xa is newline and 0xd is carriage return */
    set-reos    = yes           /* Terminate read if EOS */
    set-bin     = no            /* Compare EOS 8-bit */
    set-xeos    = no            /* Assert EOI whenever EOS byte is sent */
    set-eot     = yes           /* Assert EOI with last byte on writes */
    master      = yes           /* interface board is system controller */
}

You also may get error on RPI2, like shown below

root@raspberrypi ~/linux-gpib/linux-gpib-code/linux-gpib $ gpib_config: 
error while loading shared libraries:

To fix this, just execute command ldconfig before gpib_config.

Everything working well now:

root@tin:/home/gpib/linux-gpib-3.2.21# gpib_config
root@tin:/home/gpib/linux-gpib-3.2.21# 

No errors, yey! Let’s test how it works now.

You may want to add /usr/local/sbin/gpib_config into /etc/rc.local to have it executed automatically during Raspberry Pi boot. I did not do it, as I’m not always having GPIB dongle hooked to RPI, so that’s up to you.

Testing GPIB operation

To test I had NI GPIB-USB-HS connected to Keithley 2002 bench digital multimeter. Instrument is configured with GPIB Address = 10.

root@tin:/# ibtest
Do you wish to open a (d)evice or an interface (b)oard?
        (you probably want to open a device): d
enter primary gpib address for device you wish to open [0-30]: 10
trying to open pad = 10 on /dev/gpib0 ...
You can:
        w(a)it for an event
        ...
        ...
        (r)ead string
        perform (s)erial poll (device only)
        change (t)imeout on io operations
        request ser(v)ice (board only)
        (w)rite data string
: w
enter a string to send to your device: *IDN?
sending string: *IDN?

gpib status is:
ibsta = 0x2100  < END CMPL >
iberr= 0

ibcnt = 6
You can:
        w(a)it for an event
        ...
        ...
        (r)ead string
        perform (s)erial poll (device only)
        change (t)imeout on io operations
        request ser(v)ice (board only)
        (w)rite data string
: r
enter maximum number of bytes to read [1024]: 1024
trying to read 1024 bytes from device...
received string: 'KEITHLEY INSTRUMENTS INC.,MODEL 2002,1167961,A09  /A02'
Number of bytes read: 57
gpib status is:
ibsta = 0x2100  < END CMPL >
iberr= 0

ibcnt = 57

Now we can confirm that interface is working, and data send/received correctly.

Python-application to talk GPIB from Raspberry Pi

It’s time to write some simple program to talk with our instruments over GPIB.
One of easy choices would be using Python, as this high-level language is very easy to write data-logging programs and format data, without worry much about low-level coding.

To use GPIB in Python we need to have python-dev library installed and working:

root@tin:/# apt-get install python-dev
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following extra packages will be installed:
  libssl-dev libssl-doc python2.7-dev
The following NEW packages will be installed:
  libssl-dev libssl-doc python-dev python2.7-dev
0 upgraded, 4 newly installed, 0 to remove and 0 not upgraded.
Need to get 2,699 kB/31.4 MB of archives.
After this operation, 41.4 MB of additional disk space will be used.
Do you want to continue [Y/n]? Y
....
Setting up python2.7-dev (2.7.3-6+deb7u2) ...
Setting up python-dev (2.7.3-4+deb7u1) ...

Python-dev library is needed to access GPIB module.
Now we can install python egg to include Gpib module with our python system environment:

root@tin:/home/linux-gpib-code/linux-gpib/language/python# python ./setup.py  install
running install
running build
running build_py
creating build
creating build/lib.linux-armv6l-2.7
copying Gpib.py -> build/lib.linux-armv6l-2.7
running build_ext
building 'gpib' extension
creating build/temp.linux-armv6l-2.7
gcc -pthread -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fPIC -I../../include -I/usr/include/python2.7 -c gpibinter.c -o build/temp.linux-armv6l-2.7/gpibinter.o
gcc -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-z,relro build/temp.linux-armv6l-2.7/gpibinter.o -L../../lib/.libs -lgpib -lpthread -o build/lib.linux-armv6l-2.7/gpib.so
running install_lib
copying build/lib.linux-armv6l-2.7/Gpib.py -> /usr/local/lib/python2.7/dist-packages
copying build/lib.linux-armv6l-2.7/gpib.so -> /usr/local/lib/python2.7/dist-packages
byte-compiling /usr/local/lib/python2.7/dist-packages/Gpib.py to Gpib.pyc
running install_egg_info
Writing /usr/local/lib/python2.7/dist-packages/gpib-1.0.egg-info

Simple Python test can help to check access, for multimeter sitting on GPIB bus with address 17. Test is simple sending IDN? request and reading back 100 bytes:

root@tin:/home/linux-gpib/linux-gpib-code/linux-gpib/language/python# python
Python 2.7.9 (default, Mar  8 2015, 00:52:26)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import Gpib
>>> inst = Gpib.Gpib(0,10) # Device address 10
>>> inst.write("*IDN?")
>>> inst.read(100) # read 100 bytes
'KEITHLEY INSTRUMENTS INC.,MODEL 2002,1167961,A09  /A02  \n'
>>> 

Hope this article help to use little, but mighty Raspberry Pi with industry standard GPIB instrumentation. Size and capabilities of small microcomputer, such as Raspberry Pi can make something wild possible, such as integrating it into old GPIB-interfaced instruments to bring modern computing power and interfacing, such as interactive web via LAN port or even having instrument on remote location, controlled thru Internet. No need big bulky computer with Windows tied to it.

# xDevs.com Python test GPIB app
# http://xdevs.com/guide/ni_gpib_rpi/
import sys
import Gpib
inst = Gpib.Gpib(0,10) # Instrument GPIB Address = 10
inst.write(":DISP:WIND:TEXT:DATA 'Raspberry Pi GPIB;)'")
inst.write(":DISP:WIND2:TEXT:DATA 'xdevs.com/guide/ni_gpib_rpi'")
inst.write(":DISP:WIND:TEXT:STAT ON")
inst.write(":DISP:WIND2:TEXT:STAT ON")


Image 8: Keithley 2002 DMM displaying python code result

Here’s another app example, to setup and read data from HP 3458A multimeter

# xDevs.com Python 10V test for 3458A
# https://xdevs.com/guide/ni_gpib_rpi/
# https://xdevs.com/article/hp3458a_gpib/
# https://xdevs.com/fix/hp3458a/
import sys
import Gpib
import time

inst = Gpib.Gpib(0,3, timeout=60) # 3458A GPIB Address = 3
inst.clear()

#Setup HP 3458A
inst.write("PRESET NORM")
inst.write("OFORMAT ASCII")
inst.write("DCV 10")
inst.write("TARM HOLD")
inst.write("TRIG AUTO")
inst.write("NPLC 200")
inst.write("AZERO ON")
inst.write("LFILTER ON")
inst.write("NRDGS 1,AUTO")
inst.write("MEM OFF")
inst.write("END ALWAYS")
inst.write("NDIG 9")

cnt = 0
tread = 2
temp = 38.5
inst.write("TEMP?")
temp = float(inst.read())
reflevel = 10.0000000
ppm = 0

with open('10v_3458_nplc200_mm.csv', 'a') as o:
    o.write("date;hp3458a;level;temp;ppm_level;\r\n")
    o.close()

while cnt <= 10000000:
    cnt+=1
    with open('10v_3458_nplc200_mm_08451_opt002.csv', 'a') as o:
        tread = tread - 1
        if (tread == 0):
            tread = 20
            inst.write("TARM SGL,1")
            inst.write("TEMP?")
            temp = inst.read()
        inst.write("TARM SGL,1")
        data = inst.read()
        ppm = ((float(data) / reflevel)-1)*1E6
        inst.write("DISP OFF, \"%3.3f ppm\"" % float(ppm))
        time.sleep(1)
        print time.strftime("%d/%m/%Y-%H:%M:%S;") + ("[%8d]: %2.8f , dev %4.4f ppm, T:%3.1f" % (cnt, float(data),float(ppm),float(temp) ) )
        o.write (time.strftime("%d/%m/%Y-%H:%M:%S;") + ("%16.8f;%16.8f;%3.1f;%4.3f;\r\n" % (float(data),float(reflevel),float(temp),float(ppm) ) ))
        o.close()

Additional interfaces, LXI via Python

One of our readers also mentioned possibility of using LXI-compatible instruments with Raspberry Pi.

To use this simple guideline can be followed. Create folder (for example /home/LXI).

mkdir /home/LXI

Enter directory and get SVN repository for python-vxi

svn checkout https://github.com/python-ivi/python-vxi11

Enter /home/LXI/python-vxi11/trunk directory

python setup.py install

Now python-vxi should be installed on your Raspberry Pi

Here’s example python app to talk with VXI instrument:

import vxi11
instr =  vxi11.Instrument("192.168.0.8")
print(instr.ask("*IDN?"))

In case of correct installation and connection reply can be as below:

Keithley Instruments Inc., Model 2636B, 1234567, 3.2.1

More information is available on github for python-vxi11 or Alex Forencich’s site
He also had created python-usbtmc for Python USB commnication with instruments, so check it out.

Article version:

  • Update 3/7/2016 using 4.1.17+ kernel with rebuilded headers. Thanks to feargus!
  • Initial article, using 3.8.10 kernel + downloaded headers, PDF-archived

If you have any comments and suggestions – feel free to join in comments!

Author: Illya Tsemenko
Published: Aug. 15, 2015, 7:23 p.m.
Modified: March 7, 2016, 4:02 p.m.

Comments