GPIB on Linux

Update 2015 June: additions for Ubuntu 14.04LTS (where a symbolic link is required), and for the NI-USB-B dongle (which needs firmware loading). See also: Using the National Instruments GPIB-USB-B on linux

Notes on how to use GPIB from python on Ubuntu 12.04LTS. Tested with National Instruments USB-GPIB device and a recently bought NI GPIB PCI-E card.

  • Get linux-gpib source from http://sourceforge.net/projects/linux-gpib/
  • Building the python bindings requires libboost-python (and maybe libboost-python-dev)
  • build linux-gpib by running: ./configure, make, sudo make install
  • edit /etc/gpib.conf to fit your hardware. The default config board_type = "ni_pci" seems to work with the NI PCI-E card. For the USB-GPIB device we need board_type = "ni_usb_b"
  • load the kernel module, for the PCI-E card this is sudo modprobe tnt4882, for the USB-dongle this is sudo modprobe ni_usb_gpib
  • On Ubuntu 14.04LTS the library that gpib_config is linked against is installed in a location where the binary doesn't find it. The fix is to add a symbolic link in /lib/
    /lib$ sudo ln -s /usr/local/lib/libgpib.so.0 libgpib.so.0
  • configure: sudo gpib_config --minor 0 this reads and parses /etc/gpib.conf so it needs to be re-done if something is changed in gpib.conf
  • If gpib_config fails, and you have the older/slower NI-USB-B dongle, then you need to first load the firmware. This seems to not be required with the newer NI-USB-HS (to be confirmed?). Firmware loading requires fxload and the firmware from http://linux-gpib.sourceforge.net/firmware/. Find out where your USB-dongle is with lsusb and then load the firmware with something like:
    fxload -D /proc/bus/usb/001/002 -I niusbb_firmware.hex -s niusbb_loader.hex where you replace /001/002 with the numbers for your USB device. Now gpib_config should work.
  • By default only members of the gpib-group can use gpib, and only root has access to /etc/gpib0. If we want normal users to use gpib, add them to the gpib group (on Ubuntu the graphical user&group editor is gnome-system-tools)
  • Test!
    note: If "import gpib" fails in python you might have forgotten to install libboost-python before building linux-gpib. Python bindings will not be built&installed unless you have libboost-python.

I have two devices, so I've configured them like this in gpib.conf

/* agilent mux/dmm */
device {
	minor = 0 /* first gpib-card/usb-dongle */
	name = "dmm"
	pad = 8 /* primary address, configure on instrument front-panel*/
	sad = 0 /* secondary address, always zero? */
}
/* kikusui psu controller */
device {
        minor = 0
        name = "kikusui"
        pad = 1
        sad = 0
}

And now we can try some python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import gpib
import time
dmm= gpib.find("dmm") # define in /etc/gpib.conf
kik= gpib.find("kikusui")
 
def query(handle, command, numbytes=100):
	gpib.write(handle,command)
	time.sleep(0.1)
	response = gpib.read(handle,numbytes)
	return response
 
print query(dmm,"*IDN?")
print query(kik,"*IDN?")
 
gpib.close(dmm)
gpib.close(kik)
 
# output:
# HEWLETT-PACKARD,34970A,0,13-2-2
# KIKUSUI ELECTRONICS CORP.,PIA4830,0,2.20

10 thoughts on “GPIB on Linux”

  1. Hello!
    Great notes! I shall try them very soon 🙂
    One thing I am wondering about - do I need to install NI-VISA for Linux before I start?

    Or this method does not utilize VISA? Just directly GPIB communication?

  2. This is just "raw" simple GPIB commands in ASCII format.

    I think VISA is a software layer on top of that - but I haven't used it on linux.

  3. Note to self:
    it seems that on some installs (Ubuntu 14.04LTS in particular) the library is installed into /usr/local/lib, but gpib_config or the python bindings are unable to find the library.

    The quick fix is to add a symbolic link to the library from /lib/

  4. for ubuntu /proc/bus/usb does not exist, we use this instead:
    sudo fxload -D /dev/bus/usb/006/003 -I niusbb_firmware.hex -s niusbb_loader.hex

  5. I'm trying to install the library GPIB under UBUNTU 14.04.
    There are problems with the kernel? Following roughly the same procedure with Debian in the end everything worked fine. Now if I connect the cable USB-GPIO of NI to a PC and to an instrument, using an example written in C provided by NI to research how many devices are connected to the GPIB cable, the sw is able to detect the number of devices present but when he has to write a string that is the instrument Name the code goes wrong.
    Any suggestions or help is appreciated
    Many Thanks

    1. please post your code and the output you get, maybe on github/gist or pastebin or something?
      I would suggest using python for initial testing as it so much faster to debug and develop compared to C.
      I think I have some machines running 14.04LTS with gpib running where I followed roughly these steps - so it should work.

      1. My request is due to some messages during the ./configure:

        checking Linux kernel compile flags... WARNING: could not open /home/invito/linux-gpib-4.0.2/util/linux_flags/fake.c: Invalid argument
        ok

        during the make phase:

        make -C /lib/modules/3.19.0-47-generic/build/ V=1 modules\
        CC="gcc -I/home/invito/linux-gpib-4.0.2 -I/home/invito/linux-gpib-4.0.2/drivers/gpib/include -I/home/invito/linux-gpib-4.0.2/include" \
        CONFIG_GPIB_ISA="no" \
        SUBDIRS="/home/invito/linux-gpib-4.0.2/drivers/gpib"
        make[4]: Entering directory `/usr/src/linux-headers-3.19.0-47-generic'
        test -e include/generated/autoconf.h -a -e include/config/auto.conf || ( \
        echo >&2; \
        echo >&2 " ERROR: Kernel configuration is invalid."; \
        echo >&2 " include/generated/autoconf.h or include/config/auto.conf are missing.";\
        echo >&2 " Run 'make oldconfig && make prepare' on kernel src to fix it."; \
        echo >&2 ; \
        /bin/false)

        and during the sudo make install:
        Can't read private key
        mkdir -p /lib/modules/3.19.0-47-generic/gpib/ni_usb ; cp /home/invito/linux-gpib-4.0.2/drivers/gpib/ni_usb/ni_usb_gpib.ko /lib/modules/3.19.0-47-generic/gpib/ni_usb ; true /lib/modules/3.19.0-47-generic/gpib/ni_usb/ni_usb_gpib.ko ; perl ./scripts/sign-file "sha512" ./signing_key.priv ./signing_key.x509 /lib/modules/3.19.0-47-generic/gpib/ni_usb/ni_usb_gpib.ko || true ; true /lib/modules/3.19.0-47-generic/gpib/ni_usb/ni_usb_gpib.ko
        Can't read private key
        mkdir -p /lib/modules/3.19.0-47-generic/gpib/sys ; cp /home/invito/linux-gpib-4.0.2/drivers/gpib/sys/gpib_common.ko /lib/modules/3.19.0-47-generic/gpib/sys ; true /lib/modules/3.19.0-47-generic/gpib/sys/gpib_common.ko ; perl ./scripts/sign-file "sha512" ./signing_key.priv ./signing_key.x509 /lib/modules/3.19.0-47-generic/gpib/sys/gpib_common.ko || true ; true /lib/modules/3.19.0-47-generic/gpib/sys/gpib_common.ko
        Can't read private key
        (this is reported severals times)

        PS: I'm not able to program in python but I was using and example
        provided by NI :
        /* Filename - Findinstruments.c
        *
        * This sample application initializes the bus and the GPIB interface
        * board so that the GPIB board is Controller-In-Charge (CIC). It
        * then proceeds to find all the instruments on the GPIB bus and
        * print the PAD (Primary Address) and SAD (Secondary Address) of
        * each instrument.
        *
        */

        #include
        #include
        #include
        //#include

        /*
        * Include the WINDOWS.H and DECL-32.H files. The standard Windows
        * header file, WINDOWS.H, contains definitions used by DECL-32.H and
        * DECL-32.H contains prototypes for the GPIB routines and constants.
        */
        //#include
        #include "ib.h"

        #define GPIB0 0 // Board handle

        int Num_Instruments, // Number of instruments on GPIB
        PAD, // Primary address
        // SAD, // Secondary address
        loop; // Loop counter
        Addr4882_t Instruments[32], // Array of primary addresses
        Result[31]; // Array of listen addresses
        char ErrorMnemonic[21][5] = {"EDVR", "ECIC", "ENOL", "EADR", "EARG",
        "ESAC", "EABO", "ENEB", "EDMA", "",
        "EOIP", "ECAP", "EFSO", "", "EBUS",
        "ESTB", "ESRQ", "", "", "", "ETAB"};

        void GPIBCleanup(int ud, char* ErrorMsg);

        int main(void) {

        /*
        * Your board needs to be the Controller-In-Charge in order to find
        * all instrument on the GPIB. To accomplish this, the function
        * SendIFC is called. If the error bit ERR is set in ibsta, call
        * GPIBCleanup with an error message.
        */

        SendIFC(GPIB0);
        if (ibsta & ERR)
        {
        GPIBCleanup(GPIB0, "Unable to open board");
        return 1;
        }

        /*
        * Create an array containing all valid GPIB primary addresses,
        * except for primary address 0. Your GPIB interface board is at
        * address 0 by default. This array (Instruments) will be given to
        * the function FindLstn to find all instruments. The constant
        * NOADDR, defined in DECL-32.H, signifies the end of the array.
        */

        for (loop = 0; loop < 30; loop++) {
        Instruments[loop] = (Addr4882_t)(loop + 1);
        }
        Instruments[30] = NOADDR;

        /*
        * Print message to tell user that the program is searching for all
        * active listeners. Find all of the instruments on the bus. Store
        * the instrument addresses in the array Result. Note, the
        * instruments must be powered on and connected with a GPIB cable in
        * order for FindLstn to detect them. If the error bit ERR is set in
        * ibsta, call GPIBCleanup with an error message.
        */

        printf("Finding all instruments on the bus...\n\n");

        FindLstn(GPIB0, Instruments, Result, 31);
        if (ibsta & ERR)
        {
        GPIBCleanup(GPIB0, "Unable to issue FindLstn call");
        return 1;
        }

        /*
        * ibcntl contains the actual number of addresses stored in the
        * Result array. Assign the value of ibcntl to the variable
        * Num_Instruments. Print the number of instruments found.
        */

        Num_Instruments = ibcntl;

        printf("Number of instruments found = %d\n\n", Num_Instruments);

        /*
        * The Result array contains the addresses of all the instruments
        * found by FindLstn. Use the constant NOADDR, as defined in
        * DECL-32.H, to signify the end of the array.
        */

        Result[Num_Instruments] = NOADDR;

        /*
        * Print out each instrument's PAD and SAD, one at a time.
        *
        * Establish a FOR loop to print out the information. The variable
        * LOOP will serve as a counter for the FOR loop and as the index
        * to the array Result.
        */

        for (loop = 0; loop < Num_Instruments; loop++)
        {

        /*
        * The low byte of the instrument address is the primary
        * address. Assign the variable PAD the primary address of the
        * instrument. The macro GetPAD, defined in DECL-32.H, returns
        * the low byte of the instrument address.
        */

        PAD = GetPAD(Result[loop]);

        /*
        * The high byte of the instrument address is the secondary
        * address. Assign the variable SAD the primary address of the
        * instrument. The macro GetSAD, defined in DECL-32.H, returns
        * the high byte of the instrument address.
        */

        SAD = GetSAD(Result[loop]);

        if (SAD == NO_SAD)
        {
        printf("The instrument at Result[%d]: PAD = %d SAD = NONE\n",
        loop, PAD);
        }
        else
        {
        printf("The instrument at Result[%d]: PAD = %d SAD = %d\n",
        loop, PAD, SAD);
        }

        } /* End of FOR loop */

        /* Take the board offline. */

        ibonl (GPIB0, 0);

        return 0;

        }

        /*
        * After each GPIB call, the application checks whether the call
        * succeeded. If an NI-488.2 call fails, the GPIB driver sets the
        * corresponding bit in the global status variable. If the call
        * failed, this procedure prints an error message, takes the board
        * offline and exits.
        */
        void GPIBCleanup(int ud, char* ErrorMsg)
        {
        printf("Error : %s\nibsta = 0x%x iberr = %d (%s)\n",
        ErrorMsg, ibsta, iberr, ErrorMnemonic[iberr]);
        printf("Cleanup: Taking board offline\n");
        ibonl (ud, 0);

        Thanks for your support

        1. The error is:

          Finding all instruments on the bus...

          Number of instruments found = 1

          The instrument at Result[0]: PAD = 19 SAD = 96
          libgpib: failed to mark device as closed!

  6. I do net get the "fxload" command to work.

    This is my error message when i try to link:
    niusbb_loader.hex: unable to open for input.

    Problem is that if I try to get gpib_config to run, it starts the process but nothing happens. I let it work for about 3 hours but nothing changed its still in the process and nothing happens.

    I'm Using Ubuntu 12.04_LTS and i changed the "/proc/..." to "/dev/..." as mentioned in the comments. Any Idea why this is the case?

    TIA

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.