Skip to content

Using SMUs

William Wood edited this page Apr 24, 2023 · 38 revisions

Using SMUs

The standard functionality of SMUs in JISA is defined by the SMU interface. That is, every make/model of SMU in JISA (like K2450, K2600B etc) is considered to be an SMU with a standard set of functions that you can use on it.

This page serves to give a guide on what these are and how best to use them.

Contents

Connecting

As with any other instrument in JISA, you first need to connect to it before you can control it. As described on the "instrument basics" page, this is done by creating the relevant driver and supplying any address information it needs. For example, let's take a Keithley 2450 connected over GPIB on address 20:

Java

K2450 smu = new K2450(new GPIBAddress(0, 20));

Kotlin

val smu = K2450(GPIBAddress(0, 20))

Python

smu = K2450(GPIBAddress(0, 20))

From this point onwards, we will assume we have connected to an SMU and have assigned it to the variable smu.

Basics

SMU channels typically have an on/off switch. That is you can configure them to output a value but they won't actually output it until the channel has been turned on. You can control this in JISA by use of:

smu.turnOn();   // Enable output
smu.turnOff();  // Disable output

SMUs typically have two modes:

  • Source voltage (and measure current)
  • Source current (and measure voltage)

To configure an SMU to source some amount of voltage, simply call setVoltage():

smu.setVoltage(5.0); // Source 5 V

This will both change it to voltage-sourcing mode and set the source value to 5 Volts. Likewise for current (500 mA):

smu.setCurrent(500e-3); // Source 500 mA

If the channel is on this will change immediately. If it is off, then this value will only be output when turned on.

You can then request a measurement of either voltage or current by use of the getVoltage() and getCurrent() methods respectively:

Java

double voltage = smu.getVoltage();
double current = smu.getCurrent();

Kotlin

val voltage = smu.getVoltage()
val current = smu.getCurrent()

Python

voltage = smu.getVoltage()
current = smu.getCurrent()

Multiple Channels

If the SMU you are using has multiple channels, you can extract each channel out as its own SMU object by use of getChannel(...) like so:

Java

SMU channelA = smu.getChannel(0);
SMU channelB = smu.getChannel(1);

Kotlin

val channelA = smu.getChannel(0)
val channelB = smu.getChannel(1)

Python

channelA = smu.getChannel(0)
channelB = smu.getChannel(1)

You can now use all the standard SMU methods on these individual SMU objects to control their respective channel as if they were separate SMUs.

channelA.setVoltage(5.0);
channelB.setCurrent(15e-3);

channelA.turnOn();
channelB.turnOn();

double voltage = channelB.getVoltage();
double current = channelA.getCurrent();

Alternatively, you can use the generic MultiInstrument interface that MCSMU implements to extract individual channels, like so:

Java

// Check that this indeed does contain SMU channel sub-instruments
if (smu.contains(SMU.class)) {

  SMU channelA = smu.get(SMU.class, 0); // First sub-instrument that counts as an SMU
  SMU channelB = smu.get(SMU.class, 1); // Second sub-instrument that counts as an SMU

}

Kotlin

// Check that this indeed does contain SMU channel sub-instruments
if (SMU::class in smu) {

  val channelA = smu[SMU::class, 0] // First sub-instrument that counts as an SMU
  val channelB = smu[SMU::class, 1] // Second sub-instrument that counts as an SMU

}

Python

# Check that this indeed does contain SMU channel sub-instruments
if smu.contains(SMU):

  channelA = smu.get(SMU, 0) # First sub-instrument that counts as an SMU
  channelB = smu.get(SMU, 1) # Second sub-instrument that counts as an SMU
  

Range Configuration

You can configure the range that an SMU uses for both voltage and current by use of the setVoltageRange(...) and setCurrentRange(...) methods like so:

smu.setVoltageRange(20.0);   // 20 V range
smu.setCurrentRange(200e-3); // 200 mA range

This will pick the smallest range that contains the value you specify when only discrete options are available. You can configure both in one go by use of:

smu.setRanges(20.0, 200e-3);

To check what ranges are currently being used:

double voltageRange = smu.getVoltageRange();
double currentRange = smu.getCurrentRange();

If you want the SMU to decide automatically which range to use, then enable auto-ranging like so:

smu.useAutoVoltageRange();
smu.useAutoCurrentRange();

or again, both at once:

smu.useAutoRanges();

To check whether auto-ranging is enabled:

boolean voltageAuto = smu.isVoltageRangeAuto(); // true or false
boolean currentAuto = smu.isCurrentRangeAuto(); // true or false

Compliance/Limit Configuration

SMUs provide a means of protection when sourcing voltage or current in the form of a "compliance limit". This is a limit placed on the uncontrolled quantity. For example, if sourcing voltage then the uncontrolled quantity is current. This is essntially designed to stop you frying your device under test.

To set a compliance limit, use the following methods:

smu.setVoltageLimit(5.0);    // 5 V voltage limit
smu.setCurrentLimit(100e-3); // 100 mA current limit

or both together:

smu.setLimits(5.0, 100e-3);

You can also check the compliance limit by use of:

double voltageLimit = smu.getVoltageLimit();
double currentLimit = smu.getCurrentLimit();

Integration Time

Another parameter that you may want to tune on your SMU is the integration time. This is essentially the amount of time over which the SMU performs a measurement. Longer integration times lead to more precise measurements since they effectively average over any random noise but, obviously, take longer.

To set the integration time, in seconds, use:

smu.setIntegrationTime(20e-3); // 20 ms

If only discrete options are available, the closest option is chosen.

You can also check the currently used integration time by use of:

double integrationTime = smu.getIntegrationTime();

Four-Probe/Four-Wire Measurements

An SMU provides you with two sets of terminals: "force" and "sense". This allows you to source with one whilst measuring with the other, allowing you to perform four-probe measurements. To enable or disable this functionality use:

smu.setFourProbeEnabled(true);  // Use four-wire measurements
smu.setFourProbeEnabled(false); // Use two-wire measurements

To check which it is using:

boolean fourProbe = smu.isFourProbeEnabled();

Front/Rear Terminal Selection

Some SMUs have terminals both on the front and on the back. To select which set to use, call the following:

smu.setTerminals(Terminals.FRONT) // Front
smu.setTerminals(Terminals.REAR)  // Rear

To check which terminals the SMU is using:

Terminals used = smu.getTerminals();

You can check what type of terminals are on the front and back (if any) by use of:

TType typeFront = smu.getTerminalType(Terminals.FRONT);
TType typeRear  = smu.getTerminalType(Terminals.REAR);

The possible types are:

TType.TRIAX   // Triaxial connectors
TType.PHOENIX // Phoenix connectors
TType.BNC     // BNC/Coaxial connectors
TType.BANANA  // Banana plug connectors
TType.NONE    // Terminals do not exist

Averaging/Filtering

Most SMUs offer some means of averaging over a certain sample number per measurement. In Keithley units this is often referred to as filtering. When averaging there are two parameters to consider: the average type and the average count.

For type all SMU drivers will allow you to specify either a regular mean or median or a moving mean or median, or no averaging. This can be chosen by use of:

smu.setAverageMode(AMode.NONE);
smu.setAverageMode(AMode.MEAN_REPEAT);
smu.setAverageMode(AMode.MEDIAN_REPEAT);
smu.setAverageMode(AMode.MEAN_MOVING);
smu.setAverageMode(AMode.MEDIAN_MOVING);

You can also check which mode is being used by use of:

AMode mode = smu.getAverageMode();

The averaging count is how many samples are used per measurement using the averaging mode (if the mode is set to AMode.NONE then no averaging will occur and only 1 sample will be used regardless). This can be set by use of:

smu.setAverageCount(15); // Average over 15 measurements
smu.setAverageCount(3);  // Average over 3 measurements

This value can be checked by use of:

int count = smu.getAverageCount();

To set both at once use:

smu.setAveraging(AMode.MEAN_REPEAT, 15);

Use as Voltmeter or Ammeter

You can use an SMU as simply a voltmeter or ammeter by setting it to source 0 of the opposite quantity. For example, to measure voltage, set the SMU to source 0 Amps:

smu.setCurrent(0.0);
smu.turnOn();

double voltage = smu.getVoltage(); // Voltage reading as voltmeter

You can also transform an SMU into a VMeter or IMeter object like so:

VMeter meter = smu.asVMeter();
IMeter meter = smu.asIMeter();

This will configure the SMU accordingly and return itself as a VMeter or IMeter object, so your code now only considers it to be a voltmeter or ammeter respectively (ie the returned meter object will only be able to measure voltage or current respectively).

Example

In this example, we want to sweep voltage on channel A of a Keithley 2600B series SMU (which has two channels). At each step we want to record the current being supplied by channel A and the voltage picked up by channel B.

Java

public class Main {

  public static void main(String[] args) throws Exception {

    // Connect to the SMU
    K2600B smu = new K2600B(new TCPIPAddress("192.168.0.2"));

    // Get both channels from it
    SMU channelA = smu.getChannel(0);
    SMU channelB = smu.getChannel(1);

    // Set them both to source 0 volts and amps respectively
    channelA.setVoltage(0.0);
    channelB.setCurrent(0.0);

    // Use auto ranging on both channels
    channelA.useAutoRanges();
    channelB.useAutoRanges();

    // Enable both channels
    channelA.turnOn();
    channelB.turnOn();

    // Loop through generated list of voltages
    for (double voltage : Range.linear(0, 60, 61)) {

      // Source voltage on channel A
      channelA.setVoltage(voltage);

      // Wait 0.5 seconds (delay time)
      Util.sleep(500);

      // Measure current on channel A and voltage on channel B
      double current = channelA.getCurrent();
      double voltage = channelB.getVoltage();

      // Output values to the terminal
      System.out.printf("I = %e A, V = %e V\n", current, voltage);

    }

    // Turn off both channels
    channelA.turnOff();
    channelB.turnOff();

  }

}

Kotlin

fun main() {

  // Connect to the SMU
  val smu = K2600B(TCPIPAddress("192.168.0.2"))

  // Get both channels from it
  val channelA = smu.getChannel(0)
  val channelB = smu.getChannel(1)

  // Set them both to source 0 volts and amps respectively
  channelA.voltage = 0.0
  channelB.current = 0.0

  // Use auto ranging on both channels
  channelA.useAutoRanges()
  channelB.useAutoRanges()

  // Enable both channels
  channelA.turnOn()
  channelB.turnOn()

  // Loop through generated list of voltages
  for (voltage in Range.linear(0, 60, 61)) {

    // Source voltage on channel A
    channelA.voltage = voltage

    // Wait 0.5 seconds (delay time)
    Util.sleep(500)

    // Measure current on channel A and voltage on channel B
    val current = channelA.current
    val voltage = channelB.voltage

    // Output values to the terminal
    println("I = %e A, V = %e V".format(current, voltage))

  }

  // Turn off both channels
  channelA.turnOff()
  channelB.turnOff()

}

Python

def main():

  # Connect to the SMU
  smu = K2600B(TCPIPAddress("192.168.0.2"))

  # Get both channels from it
  channelA = smu.getChannel(0)
  channelB = smu.getChannel(1)

  # Set them both to source 0 volts and amps respectively
  channelA.setVoltage(0.0)
  channelB.setCurrent(0.0)

  # Use auto ranging on both channels
  channelA.useAutoRanges()
  channelB.useAutoRanges()

  # Enable both channels
  channelA.turnOn()
  channelB.turnOn()

  # Loop through generated list of voltages
  for voltage in Range.linear(0, 60, 61):

    # Source voltage on channel A
    channelA.setVoltage(voltage)

    # Wait 0.5 seconds (delay time)
    Util.sleep(500)

    # Measure current on channel A and voltage on channel B
    current = channelA.getCurrent()
    voltage = channelB.getVoltage()

    # Output values to the terminal
    print("I = %e A, V = %e V" % (current, voltage))


  # Turn off both channels
  channelA.turnOff()
  channelB.turnOff()


main()
Clone this wiki locally