Skip to content

Instruments New

William Wood edited this page May 27, 2019 · 4 revisions

Instruments

JISA is an object-oriented (OO) library, especially when it comes to instruments. For this reason, if you are unfamiliar with OO (ie objects and classes), then please read the OO tutorial page here.

The basic idea of connecting to an instrument using JISA is that you create (or "instantiate") an object to represent it. The class of object you need to create depends on the make/model of the instrument. For example, a Keithley 236 is connected to by creating a K236 object whereas a LakeShore 336 needs a LS336 object. These are all referred to as Instrument objects.

When creating one of these objects you also need to provide it with an Address object to specify how the device is connected to the computer. The type of object here depends on the connection, for example if it's over GPIB then you need a GPIBAddress object whereas if it was over serial you'd need a SerialAddress object. You then give this as an argument when creating your Instrument object.

For example, connecting to a Keithley 236 over GPIB (address 24) and to a LakeShore 336 over serial (port 5):

Java

K236  smu = new K236(new GPIBAddress(24));
LS336 tc  = new LS336(new SerialAddress(5));

Kotlin

val smu = K236(GPIBAddress(24))
val tc  = LS336(SerialAddress(5))

Python

smu = K236(GPIBAddress(24))
tc  = LS336(SerialAddress(5))

We can then control these instruments using these objects:

smu.setVoltage(5.0);
smu.turnOn();

tc.setTargetTemperature(300.0);
tc.useAutoHeater();

Contents

  1. Connection Examples
  2. Instrument Classes
  3. Instrument Addresses
  4. Basic Instrument Functionality
  5. Exceptions when Connecting
  6. Instrument Interfaces
  7. Channels as Virtual Instruments

Connection Examples

Here's some examples of connecting to instruments, for a quick overview of what it should look like:

Java

// Keithley 2450 over TCP-IP at 192.168.0.5:
SMU k2450 = new K2450(new TCPIPAddress("192.168.0.5"));

// ITC503 over GPIB at address 24
MSTC itc503 = new ITC503(new GPIBAddress(24));

// Keithley 2200 over serial, port 4
DCPower k2200 = new K2200(new SerialAddress(4));

Kotlin

// Keithley 2450 over TCP-IP at 192.168.0.5:
val k2450 = K2450(TCPIPAddress("192.168.0.5"))

// ITC503 over GPIB at address 24
val itc503 = ITC503(GPIBAddress(24))

// Keithley 2200 over serial, port 4
val k2200 = K2200(SerialAddress(4))

Python

# Keithley 2450 over TCP-IP at 192.168.0.5:
k2450 = K2450(TCPIPAddress("192.168.0.5"))

# ITC503 over GPIB at address 24
itc503 = ITC503(GPIBAddress(24))

# Keithley 2200 over serial, port 4
k2200 = K2200(SerialAddress(4))

Instrument Classes

For reference, all supported instruments and their corresponding classes are listed below:

Model Type Class
Keithley 236 SMU (Single-Channel) K236
2400 Series SMU (Single-Channel) K2400
2450 SMU (Single-Channel) K2450
2600B Series SMU (Multi-Channel) K2600B
6430 SMU (Single-Channel) K6430
2200 DC Power Supply K2200
2182 Voltmeter K2182
Oxford Instruments ITC-503 Temperature Controller ITC503
IPS-120 Magnet Controller IPS120
ILM-200 He Level Meter ILM200
Lake Shore 336 Temperature Controller LS336
Stanford Research SR830 Lock-In Amplifier SR830
SR560 Voltage Pre-Amp SR560
Eurotherm 2408 Temperature Controller ET2408
Pico Technology USB-TC08 Thermometer (Multi-Channel) USBTC08

Instrument Addresses

To connect to an instrument, JISA needs to know where it is and how to talk to it. For example, it might be connected on address 20 over GPIB or it might be at 192.168.0.3 over TCP-IP.

To represent this, JISA uses Address objects. For each type of connection there is a relevant class. Below is listed all the available Address types in JISA. Parameters surrounded by [ ... ] are optional.

Connection Type Address Class Comments
GPIB GPIBAddress(board, address)
GPIBAddress(address) Assume first GPIB board
Example GPIBAddress(0, 24) Board 0, Address 24
Serial SerialAddress(portNumber)
Example SerialAddress(3) COM port 3
USB-TMC USBAddress(board, vID, pID, sNo)
USBAddress(vID, pID, sNo) Assume first USB board
Example USBAddress(0x05E6, 0x2450, "5EA2")
TCP-IP (VXI-11) TCPIPAddress(board, host)
TCPIPAddress(host) Assume first NIC
Example TCPIPAddress("192.168.0.2") First NIC, IP Address
TCP-IP (Raw) TCPIPSocketAddress(board, host, port)
TCPIPSocketAddress(host, port) Assume first NIC
Example TCPIPSocketAddress("192.168.0.2", 7777) 192.168.0.2 port 7777
Modbus RTU ModbusAddress(port, unit)
Example ModbusAddress(3, 12) COM Port 3, Unit 12
VISA ID StrAddress(visaResourceID) Convert from VISA address
Example StrAddress("GPIB0::12::INSTR") GPIB board 0, address 12

Basic Instrument Functionality

While different instruments will obviously have different functions, they do all share a few. These are:

instrument.getIDN();                 // Returns an identifying string
instrument.getAddress();             // Returns the address object used to connect
instrument.setTimeout(milliseconds); // Sets the timeout in milliseconds
instrument.close();                  // Closes the connection to the instrument

The close() method on each instrument will be automatically called when the object is no-longer being used (or if the program terminates normally) so you won't normally need to use it.

Exceptions when Connecting

Connecting to an instrument can throw an exception. This will happen if something goes wrong with the connection. The most common example is if there is nothing to connect to, but other examples include using the wrong class to connect to an instrument or the connection breaking down before connection is fully established.

It is therefore advisable that you connect to your instrument within a try...catch (or try...except) block in your code. You could then use the GUI package to display an error message in the catch block and then exit the program. For example:

Java

K2450 keithley;

try {

  // Attempt to connect
  keithley = new K2450(new GPIBAddress(0, 20))

} catch (Exception e) {

  // If it fails, show an error message and exit
  GUI.errorAlert("Connection Error", e.getMessage());
  System.exit(1);

}

Kotlin

var keithley: K2450

try {

  keithley = K2450(GPIBAddress(0, 20))

} catch (e: Exception) {

  GUI.errorAlert("Connection Error", e.message);
  exitProcess(1);

}

Python

try:
  keithley = K2450(GPIBAddress(0, 20))

except Exception as e:
  GUI.errorAlert("Connection Error", e.getMessage())
  quit()

Instrument Interfaces

Whilst each make/model of instrument is represented in JISA with its own class, these classes are further organised around a set of interfaces corresponding to the type of instrument it controls. In general, an interface is like a class but all of its functions have no code in them. You can then create a class that "implements" your interface and as a result will be required to have all the functions that the interface has.

In the context of JISA, this is used to define what standard functions Instrument objects should have based on what type of instrument they control. For example, the K2450 and K236 classes both implement the SMU interface (since they're both SMUs). This means that when we create K2450 and K236 objects:

K2450 smu1 = new K2450(new GPIBAddress(17));
K236  smu2 = new K236(new GPIBAddress(20));

We no-longer have to think about them as K2450 or K236 objects, but simply as SMU objects:

SMU smu1 = new K2450(new GPIBAddress(17));
SMU smu2 = new K236(new GPIBAddress(20));

The obvious advantage of this is that you can write code to perform a measurement without needing to know what make/model of instrument you're using, just the type, for instance with two SMUs:

void doMeasurement(SMU smu1, SMU smu2) {

  smu1.setCurrent(0.0);
  smu2.setCurrent(0.0);

  smu1.turnOn();
  smu2.turnOn();

  for (double I : Util.makeLinearArray(0.0, 50e-3, 11)) {

    smu1.setCurrent(I);

    double V          = smu2.getVoltage();
    double resistance = V / I;

    System.out.println(resistance);

  }

}

So now we can run this measurement with any two SMUs, since we know that whatever the make/model they will have the standard functions that we used in doMeasurement(...). For example using a Keithley 2450 and a Keithley 236:

SMU smu1 = new K2450(new GPIBAddress(17));
SMU smu2 = new K236(new GPIBAddress(20));

doMeasurement(smu1, smu2);

or if we wanted to run it using the two channels on a Keithley 2600B instead (more on this in the next section):

MCMSU smu  = new K2600B(new TCPIPAddress("192.168.0.5"));
SMU   smu1 = smu.getChannel(0);
SMU   smu2 = smu.getChannel(1);

doMeasurement(smu1, smu2);

Both will result in the same measurement being performed but on different SMUs.

Below are listed all the instrument type interfaces:

Interface Description
TMeter Thermometer
MSTMeter Multi-Sensor Thermometer
VMeter Voltmeter
IMeter Ammeter
VSource Voltage Source
ISource Current Source
IVMeter Multimeter
IVSource Voltage/Current Source
SMU Source-Measure Unit
MCSMU Multi-Channel SMU
TC Temperature Controller
MSTC Multi-Sensor TC
MSMOTC Multi-Sensor + Multi-Output TC
LockIn Lock-In Amplifier
DPLockIn Dual-Phase Lock-In Amplifier
DCPower DC Power Supply
VPreAmp Voltage Pre-Amplifier

Some of these extend from each other. For instance IVMeter is IMeter and VMeter combined, and SMU is IVMeter and IVSource combined.

For this result, an SMU object will be considered to be a valid VMeter, IMeter, VSource, ISource, IVMeter or IVSource as well as just an SMU. So if you wrote some code that required a voltmeter (VMeter), you can stick in an SMU (SMU) to act as one instead.

Likewise, temperature controllers are considered to be thermometers with extra functionality. Therefore, a TC/MSTC/MSMOTC can be considered to be a valid TMeter object (since the functionality of a TMeter is a sub-set of that of a TC).

Channels as Virtual Instruments

To further this theme of interchangeability, multi-channel interfaces (like MCSMU, MSTMeter, MSTC etc) can be considered to be collections of their single-sensor counterparts. For example, an MCSMU with 2 channels can be considered to be a collection of 2 single-channel SMU objects. This is how you generally should treat multiple channels in JISA. For instance, if we take the Keithley 2600B SMU (which has 2 channels), we can extract each as its own SMU object like so:

MCSMU mcsmu    = new K2600B(new TCPIPAddress("192.168.0.2"));
SMU   channelA = mcsmu.getChannel(0);
SMU   channelB = mcsmu.getChannel(1);

This can also be done with multi-output temperature controllers, splitting each PID output controller into individual TC objects and for MSTC and MSMOTC objects you can extract each temperature sensor as a TMeter object.

MSMOTC  tc     = new LS336(new SerialAddress(6));
TC      base   = tc.getOutput(0);
TC      stage  = tc.getOutput(1);

TMeter  sample = tc.getSensor(2);
TMeter  arm    = tc.getSensor(3);

These individual virtual instruments will now control their respective channel as if you were giving the relevant channel-specific commands to the multi-channel instrument object itself.

For example:

channelA.setVoltage(15.5);
channelB.setCurrent(50e-3);

// == is the same as ==

mcsmu.setVoltage(0, 15.5);
mcmsu.setCurrent(1, 50e-3);

This lets you generalise your program so that it can be used with whatever combination of SMU channels the user wants. (ie two separate SMUs can be swapped out for a single 2-channel SMU and your code won't need to change).

It is recommended that you always interact with multi-channel instruments this way. Not only does it make your code more readable, but it also makes it easier to swap out instruments further down the road.

More specific information about this can be found on the relevant instrument type page.

Clone this wiki locally