Controlling instruments over GPIB with SCPI

Fri 17 April 2015 | tags: python

An electronics lab contains equipment that can usually be controlled through at least two means:

  1. the instrument's front panel
  2. the instrument's GPIB address

GPIB stands for General Purpose Interface Bus and provides a way of sending commands to the instrument. These commands are referred to as SCPI commands (Standard Commands for Programmable Instruments), which are often found listed in an instrument's programming manual. Every operation that can be performed via the instrument's front panel should have an equivalent SCPI command.

This post shows a brief Python script that talks to an Agilent E5270 DC parameteric measurement instrument and conducts a staircase sweep. To run it one needs a GPIB card on the controlling computer, the PyVISA package, Keysight IO Libraries Suite, and the GPIB address of the E5270. The script should also work with an HP4142, which has almost identical settings and SCPI commands.

Why Python?

Well, I personally do data analysis in Python (numpy/scipy/matplotlib modules and the Spyder IDE that is reminiscent of MATLAB; see Python(x,y) or WinPython), so it made sense for me to automate measurements in a language I'm already comfortable in. I find the file IO and string/data manipulation features of Python to be much easier to use and read than those available in other languages. Just by glancing at example code in an instrument programming manual written in C++ or Visual Basic makes me readily appreciative of the straightforwardness and readibility of Python code.

Useful links

Example Python script

"""
A sequence of commands to execute a staircase measurement of a 3-terminal
transistor (source/gate/drain terminals)

Assumed SMUs (source measure units) and their channels:
    two high-power SMUs on channels 2 and 4
    one medium-power SMU on channel 5

Biasing conditions:
    source on channel 2 is biased at a constant 0V.  
    drain on channel 4 is staircased from 0 to 10V by 0.1V.  
    gate on channel 5 is biased at a constant 3V.

See manual for a description of arguments passed to each SCPI command.
"""
import visa
import numpy as np
import matplotlib.pyplot as plt

# the GPIB card number on the local computer
card_address = 0
# the instrument's GPIB address
instrument_address = 17

rm = visa.ResourceManager()
m = rm.open_resource(
    'GPIB%d::%d::INSTR' % (card_address, instrument_address)
)

# -----------------
# instrument setup
# -----------------
# reset the instrument
m.write('*rst')

# set the measurement mode to staircase sweep
# specify the channels that should be measured
m.write('mm 2,2,4,5')

# configure the staircase on channel 4 (drain)
m.write('wv 4,1,0,0,10,101,1e-2')

# enable the output switches on channels 2,4,5
m.write('cn 2,4,5')

# set the bias of the constant channels 2/5 (source/gate)
m.write('dv 2,0,0,1e-2')
m.write('dv 5,0,3,1e-4')

# -----------------
# execute and close
# -----------------
# execute the measurement
m.write('xe')

# close all channels so they no longer are outputting voltage
m.write('cl')

# read the result from the output buffer
result = m.read()

While the measurement data is now held in the result variable, it needs to be processed. As-is, result is a string composed of comma-separated values. If this string were to be split by commas (i.e., result.split(',')) then the length of the resulting list would be 3 x len(staircase). One multiplies by 3 because for each point in the staircase sweep there are three channels measured whose values appear consecutively in the result string.

Example result string: NEI+0.00005E-09,NBI+0.00000E-09,NDI+0.00010E-09,NEI+0.00010E-09,NBI+0.00007E-09,NDI+0.00080E-09, ... (Notice how the second character's cycle starts over after the third group of values.)

In each comma-separated value there are three preceding characters. The first character is the status code. The second character is the letter code. There is a unique letter code for each channel in the E5270, so a mapping dictionary is referred to in order to figure out which channel corresponds to which letter code. The third character indicates the data type. See page 36 of the programming manual linked above.

Processing the result

# -----------------
# parsing data
# -----------------
# this is the letter code mapping dictionary
# (see page 37 of the programming manual)
CHANNELS = {
    'B': 'Is', # channel 2
    'D': 'Id', # channel 4
    'E': 'Ig', # channel 5
}

# split the CSV string so it can be iterated over
result = result.split(',')
currents = {
    'Id': [],
    'Is': [],
    'Ig': []
}

# iterate over the result list and store the values as floats
for entry in result:
    # get the terminal name by consulting the mapping dictionary
    terminal_name = CHANNELS[entry[1]]
    # convert the numerical portion of the string to a float
    value = float(entry[3:])
    # store value within the 'currents' dict
    currents[terminal_name].append(value)

# -----------------
# plotting
# -----------------
# create the independent variable (Vd) so the result can be plotted
Vd = np.linspace(0, 10, 101)

# plot the data
plt.figure(1)
plt.clf()
plt.plot(Vd, currents['Id'])
plt.figure(2)
plt.clf()
plt.semilogy(Vd, np.abs(currents['Ig']))

Suggestions

  • The PyVISA syntax used in the example code is for PyVISA version 1.5 and up (the syntax changed relative to previous versions; see Migrating from PyVISA < 1.5.)
  • Python can actually submit SCPI commands too fast for some instruments. In this case, it's useful to add a time.sleep() statement after each write() operation.
  • Use rm.list_resources() to print a list of visible instruments.

Closing

That concludes the quick introduction to instrument control via GPIB+SCPI. In a more complete instrument controller, I would send additional commands to change instrument settings such as integration time and store results in pandas DataFrames (or numpy arrays). Instead of a one-off script, it is often useful to create a class for a particular instrument that contains methods to perform many different types of measurements. This makes the instrument an importable library with a human-readable command set and avoids having to write/remember SCPI commands.

Comments !

social