Posted Fri, 08 Dec 2023 15:55:07 GMT by Rupeliya, Yogesh
Hello there,
I am doing Four point measurements by using SMU 2636A with python. Earlier I was using Python 2.7 and I switched to Python 3.8. With 3.8 I am getting error -350 Queue full error which is showing in SMU's display. I tried to write function in Python for Queue error however still getting same error. Here I am attaching both Python files as a text as well as zip. Could you please help me in this situation?

Python 2.7 original file:

# *-* coding:utf-8 *-*

import visa
import numpy as np
import time
import os
import matplotlib.pyplot as plt

class Keithley2636A(object):
    
    def __init__(self):
        try:
            self.__device = visa.instrument('GPIB0::18')
        except:
            print 'Could not attach to Keithley!'
            
        self.__intTime = 1.0 # standart integration time 20ms = 1 plc
        self.__waitingTime = 0.0 # in ms --> minimum waiting time to measure after setting voltage
        self.__maxPower = 1.0 # in Watt
        self.__average = 1 # number of averages for each data point measurement
        
        self.__send(['reset()'])
        
    def __send(self, cmds):
        '''sends a list of commands to the device'''
        for cmd in cmds:
            self.__device.write(cmd)
        
    def init4pt(self):
        optns = []
        #optns.append('display.screen = display.SMUA')
        #optns.append('smua.source.func = smua.OUTPUT_DCAMPS') #current source
        #optns.append('smua.source.autorangei = smua.AUTORANGE_ON') #current source AutoRange
        #optns.append('display.smua.measure.func =  display.MEASURE_DCVOLTS')
        #optns.append('smua.sense = smua.SENSE_REMOTE') #4 wire measurement
        #optns.append('smua.measure.autorangev = smua.AUTORANGE_ON') #voltage measurement AutoRange
        #optns.append('smua.measure.nplc = %f' % self.__intTime) # integration time in Number of Power Line Cycles (range from 0.001 to 25) 25 MAYBE HAS A BUG
        
        optns.append('display.screen = display.SMUA_SMUB')
        optns.append('smua.source.func = smua.OUTPUT_DCVOLTS') #voltage source
        optns.append('smub.source.func = smub.OUTPUT_DCAMPS') #current source
        optns.append('smua.source.autorangev = smua.AUTORANGE_ON') #voltage source AutoRange
        optns.append('smub.source.autorangei = smua.AUTORANGE_ON') #current source AutoRange
        optns.append('display.smua.measure.func =  display.MEASURE_DCAMPS')
        optns.append('display.smub.measure.func =  display.MEASURE_DCVOLTS')
        optns.append('smua.sense = smub.SENSE_LOCAL') #2 wire measurement
        optns.append('smub.sense = smub.SENSE_LOCAL') #2 wire measurement
        optns.append('smua.measure.autorangei = smua.AUTORANGE_ON') #voltage measurement AutoRange
        optns.append('smub.measure.autorangev = smua.AUTORANGE_ON') #voltage measurement AutoRange
        optns.append('smua.measure.nplc = %f' % self.__intTime) # integration time in Number of Power Line Cycles (range from 0.001 to 25) 25 MAYBE HAS A BUG
        optns.append('smub.measure.nplc = %f' % self.__intTime) # integration time in Number of Power Line Cycles (range from 0.001 to 25) 25 MAYBE HAS A BUG
        self.__send(optns)
    
    def __getVoltageLimit(self, cur):
        '''calculates the voltage limit for current source to avoid too high powers in the DUT'''
        if cur == 0.0:
            #lim = 200.0 #only in interlock mode
            lim = 20.0
        else:
            lim = self.__maxPower / cur
            if np.abs(cur) < 0.1:
                #lim = np.clip(np.abs(lim), 0.02, 200.0) #only in interlock mode
                lim = np.clip(np.abs(lim), 0.02, 20.0)
            else:
                lim = np.clip(np.abs(lim), 0.02, 20.0)
        return lim
        
    def __getCurrentLimit(self, vol):
        '''calculates the current limit for voltage source to avoid too high powers in the DUT'''
        if vol == 0.0:
            lim = 1.5
        else:
            lim = self.__maxPower / vol
            if np.abs(vol) < 20.0:
                lim = np.clip(np.abs(lim), 100e-12, 1.5)
            else:
                lim = np.clip(np.abs(lim), 100e-12, 0.1)
        return lim
    
    def setCurrent(self, cur, cha): #cha = channel A/B
        '''sets the current source value for channel A/B'''
        optns = []
        optns.append('smu%s.source.limitv = %f' % (cha, self.__getVoltageLimit(cur)))
        optns.append('smu%s.source.leveli = %f' % (cha, cur))
        self.__send(optns)
        return True
    
    def setVoltage(self, vol, cha): #cha = channel A/B
        '''sets the voltage source value for channel A/B'''
        optns = []
        optns.append('smu%s.source.limiti = %f' % (cha, self.__getCurrentLimit(vol)))
        optns.append('smu%s.source.levelv = %f' % (cha, vol))
        self.__send(optns)
        return True
    
    def __measureCurrent(self, cha):
        '''measures the current on channel A/B'''
        optns = []
        optns.append('smu%s.measure.count = 1' % cha)
        optns.append('print(smu%s.measure.i())' % cha)
        self.__send(optns)
        return self.__device.read_values()[0]
    
    def getCurrent(self, cha): #cha = channel A/B
        cur = 0.0
        for i in range(self.__average):
            time.sleep(self.__waitingTime/1000.0)
            cur = cur + self.__measureCurrent(cha)
        return cur / self.__average, self.__checkCompliance(cha), True
    
    def __measureVoltage(self, cha):
        optns = []
        optns.append('smu%s.measure.count = 1' % cha)
        optns.append('print(smu%s.measure.v())' % cha)
        self.__send(optns)
        return self.__device.read_values()[0]
    
    def getVoltage(self, cha): #cha = channel A/B
        vol = 0.0
        for i in range(self.__average):
            time.sleep(self.__waitingTime/1000.0)
            vol = vol + self.__measureVoltage(cha)
        return vol / self.__average, self.__checkCompliance(cha), True

    def __measureCurVol(self, cha):
        optns = []
        optns.append('smu%s.measure.count = 1' % cha)
        optns.append('print(smu%s.measure.iv())' % cha)
        self.__send(optns)
        return self.__device.read_values()[0:2]

    def getCurVol(self, cha):
        res = self.__measureCurVol(cha)
        return res[0], res[1], True
        
    def setMaxPower(self, pwr):
        '''define the maximum power through the device'''
        self.__maxPower = pwr
    
    def setIntegrationTime(self, time):
        '''time in seconds; for 50Hz 1 plc = 20ms --> range time from 20µs to 500ms'''
        self.__intTime = time / 0.02
        
    def setNumberOfAverages(self, n):
        '''defines over how many measurements per point should be averaged'''
        self.__average = n
        
    def outputOn(self, cha): # cha = channel A/B
        '''turns the output on'''
        self.__send(['smu%s.source.output = smu%s.OUTPUT_ON' % (cha, cha)])
        
    def outputOff(self, cha): # cha = channel A/B
        '''turns the output off'''
        self.__send(['smu%s.source.output = smu%s.OUTPUT_OFF' % (cha, cha)])
        
    def __checkCompliance(self, cha):
        '''checks wheter the source is in compliance or not'''
        self.__send(['print(smu%s.source.compliance)' % cha])
        tmp = self.__device.read()
        if tmp == 'false':
            return False
        else:
            return True
        
def test():
    tst = Keithley2636A()
    fileName = raw_input('file name: ')
    fl = os.listdir('./')
    n = 0
    Ival = []
    Vval = []
    while '%02.i_%s.dat' % (n, fileName) in fl:
        n = n+1
    f = open('%02.i_%s.dat' % (n, fileName), mode='w')
    f.write('V_setpoint/V\tI_measured/A\tV_measured/V\n')
    tst.init4pt()
    minI = input('Minimum Voltage in V: ')
    maxI = input('Maximum Voltage in V: ')
    stepI = input('Voltage steps in V: ')
    tst.outputOn('a')
    tst.setCurrent(0.0, 'b')
    tst.outputOn('b')
    print 'V_setpoint/V\tI_measured/A\tV_measured/V'
    r1 = np.arange(0.0, maxI, stepI)
    r2 = np.arange(maxI, minI, -stepI)
    r3 = np.arange(minI, 0.0+stepI, stepI)
    vLoop = np.append(r1, r2)
    vLoop = np.append(vLoop, r3)
    for v in vLoop:
        tst.setVoltage(v, 'a')
        time.sleep(1.0)
        resCur = tst.getCurrent('a')
        resVolt = tst.getVoltage('b')
        print '%g\t%g\t%g' % (v, resCur[0], resVolt[0])
        f.write('%g\t%g\t%g\n' % (v, resCur[0], resVolt[0]))
        Ival.append(resCur[0])
        Vval.append(resVolt[0])
    print 'end'
    tst.outputOff('a')
    tst.outputOff('b')
    f.close()
    plt.plot(Vval, Ival, 'ro')
    plt.show()
    
if __name__ == '__main__':
    test()



--------------------------------------------------------------------------------------------
Python 3.8 Transferred file :

import pyvisa
import time
import numpy as np
import os
import matplotlib.pyplot as plt
from queue import Queue

class Keithley2636A:
    def __init__(self, visa_address):
        self.rm = pyvisa.ResourceManager()
        self.instrument = self.rm.open_resource(visa_address)
        self.queue = Queue(maxsize=100)  # Set a larger value for the queue size
        
    def setup_measurement(self):
        # Configure the instrument for the 4-point probe measurement
        self.instrument.write("reset()")
        self.instrument.write("display.screen = pyvisa.constants.SMUA_SMUB")
        self.instrument.write("smua.source.func = smua.OUTPUT_DCVOLTS")
        self.instrument.write("smub.source.func = smub.OUTPUT_DCAMPS")
        self.instrument.write("smua.source.autorangev = smua.AUTORANGE_ON")
        self.instrument.write("smub.source.autorangei = smua.AUTORANGE_ON")
        self.instrument.write('display.smua.measure.func =  display.MEASURE_DCAMPS')
        self.instrument.write('display.smub.measure.func =  display.MEASURE_DCVOLTS')
        self.instrument.write("smua.sense = smua.SENSE_REMOTE")
        self.instrument.write("smub.sense = smub.SENSE_REMOTE")
        self.instrument.write('smua.sense = smub.SENSE_LOCAL')  # 2 wire measurement
        self.instrument.write('smub.sense = smub.SENSE_LOCAL')  # 2 wire measurement
        self.instrument.write('smua.measure.autorangei = smua.AUTORANGE_ON')  # voltage measurement AutoRange
        self.instrument.write('smub.measure.autorangev = smua.AUTORANGE_ON')  # voltage measurement AutoRange
        self.instrument.write("smua.source.output = smua.OUTPUT_OFF")
        self.instrument.write("smub.source.output = smub.OUTPUT_OFF")
        self.instrument.write("smua.measure.nplc = 1")  # Set NPLC value as needed
        self.instrument.write("smub.measure.nplc = 1")  # Set NPLC value as needed


    def __getVoltageLimit(self, cur):
        '''calculates the voltage limit for current source to avoid too high powers in the DUT'''
        if cur == 0.0:
            #lim = 200.0 #only in interlock mode
            lim = 20.0
        else:
            lim = 1.0 / cur
            if np.abs(cur) < 0.1:
                #lim = np.clip(np.abs(lim), 0.02, 200.0) #only in interlock mode
                lim = np.clip(np.abs(lim), 0.02, 20.0)
            else:
                lim = np.clip(np.abs(lim), 0.02, 20.0)
        return lim
    
    def __getCurrentLimit(self, vol):
        '''calculates the current limit for voltage source to avoid too high powers in the DUT'''
        if vol == 0.0:
            lim = 1.5
        else:
            lim = 1.0 / vol
            if np.abs(vol) < 20.0:
                lim = np.clip(np.abs(lim), 100e-12, 1.5)
            else:
                lim = np.clip(np.abs(lim), 100e-12, 0.1)
        return lim
    
    def set_voltage(self, voltage, cha):
        #self.instrument.write(f"smua.source.levelv = {voltage}")
        self.instrument.write('smu%s.source.limiti = %f' % (cha, self.__getCurrentLimit(voltage)))
        self.instrument.write('smu%s.source.levelv = %f' % (cha, voltage))
        time.sleep(0.1)
        # Put the measured value into the queue
        self.queue.put({'voltage': voltage, 'current': self.measure_current(cha), 'voltage_measurement': self.measure_voltage(cha)})
    
    def set_current(self, current, cha):
        #self.instrument.write(f"smub.source.leveli = {current}")
        self.instrument.write('smu%s.source.limitv = %f' % (cha, self.__getVoltageLimit(current)))
        self.instrument.write('smu%s.source.leveli = %f' % (cha, current))
        time.sleep(0.1)
    
    def turn_on_channels(self):
        self.instrument.write("smua.source.output = smua.OUTPUT_ON")
        self.instrument.write("smub.source.output = smub.OUTPUT_ON")
    
    def turn_off_channels(self):
        self.instrument.write("smua.source.output = smua.OUTPUT_OFF")
        self.set_current(0.0, 'B')
        self.instrument.write("smub.source.output = smub.OUTPUT_OFF")
        self.queue.queue.clear()  # Clear the queue when turning off channels
    
    def measure_current(self, cha):
        return float(self.instrument.query(f'print(smub.measure.i())'))
    
    def measure_voltage(self, cha):
        return float(self.instrument.query(f'print(smub.measure.v())'))
    
    def close(self):
        self.instrument.close()
        self.rm.close()

if __name__ == "__main__":
    # Configure the GPIB address for your Keithley 2636A
    visa_address = "GPIB0::18::INSTR"  # Adjust this address as needed

    keithley = Keithley2636A(visa_address)

    try:
        keithley.setup_measurement()
        measurement_name = input("Enter the measurement name:")

        minI = float(input('Minimum Voltage in V: '))
        maxI = float(input('Maximum Voltage in V: '))
        stepI = float(input('Voltage steps in V: '))
        cha = 'A'  # Define cha before using it
        
        r1 = np.arange(0.0, maxI, stepI)
        r2 = np.arange(maxI, minI, -stepI)
        r3 = np.arange(minI, 0.0 + stepI, stepI)
        vLoop = np.append(r1, r2)
        vLoop = np.append(vLoop, r3)
        voltage_list = np.arange(minI, maxI, stepI)  # Set your desired voltage range

        current_list = []
        v_list = []

        keithley.turn_on_channels()
        print(f"Step Voltage/V \t Measured Current/A \t  Measured Voltage/V")

        for voltage in vLoop:
            keithley.set_voltage(voltage, cha)
            time.sleep(1.0)
            # Add the measured values to the queue
            keithley.queue.put({'voltage': voltage, 'current': keithley.measure_current(cha), 'voltage_measurement': keithley.measure_voltage(cha)})
            current_list.append(keithley.queue.get()['current'])
            v_list.append(keithley.queue.get()['voltage_measurement'])
            current = keithley.measure_current(cha)
            current_list.append(current)
            v = keithley.measure_voltage(cha)
            v_list.append(v)

            print(f"{round(voltage, 1)} V  {current} A \t  {v} V")
    
        keithley.turn_off_channels()
    finally:
        keithley.close()

Thank you in advance.
Posted Wed, 13 Dec 2023 13:13:24 GMT by C, Andrea
Can you set break points and/or single step your code to identify which line causes an error?
And what is the error?
Queue Full means you have a lot of errors.
Try errorqueue.clear() at start of code.

If it worked well with older Python, then probably just a syntax issue/mistake in the conversion.
The SMU has no awareness of what is sending the commands.

You must be signed in to post in this forum.