def configure_node_1(): """ Configure the postive node of the IV sweep """ node_1_keithley.reset() node_1_keithley.source.func = node_1_keithley.source.OUTPUT_DCVOLTS node_1_keithley.sense = node_1_keithley.sense.SENSE_REMOTE node_1_keithley.source.offmode = node_1_keithley.source.OUTPUT_NORMAL node_1_keithley.source.off_function = node_1_keithley.source.OUTPUT_DCVOLTS # checking this with Sierra; probably needs to be 2.5 A at Isc node_1_keithley.source.offlimit_current = CURRENT_LIMIT node_1_keithley.source.offlimit_voltage = VOLTAGE_OFF_LIMIT node_1_keithley.source.range_current = CURRENT_LIMIT node_1_keithley.source.range_voltage = 40 node_1_keithley.measure.nplc = NPLC node_1_keithley.measure.range_voltage = 40 node_1_keithley.measure.autozero = node_1_keithley.measure.AUTOZERO_OFF node_1_keithley.measure.delay = MEASURE_DELAY node_1_keithley.nvbuffer1.clear() node_1_keithley.nvbuffer1.collectsourcevalues = 1 node_1_keithley.nvbuffer1.collecttimestamps = 1 node_1_keithley.nvbuffer1.fillmode = node_1_keithley.nvbuffer1.FILL_ONCE node_1_keithley.nvbuffer2.clear() node_1_keithley.nvbuffer2.collectsourcevalues = 1 node_1_keithley.nvbuffer2.collecttimestamps = 1 node_1_keithley.nvbuffer2.fillmode = node_1_keithley.nvbuffer1.FILL_ONCE node_1_keithley.tsplink.trigger1.clear() node_1_keithley.tsplink.trigger1.mode = node_1_keithley.tsplink.trigger1.TRIG_FALLING node_1_keithley.tsplink.trigger1.stimulus = smu2651a.trigger.timer1.event_id # node 1 trigger controls the overall sweep # timer 1 controls the pulse period node_1_keithley.trigger.timer1.count = VOLTAGE_STEPS - 1 node_1_keithley.trigger.timer1.delay = PULSE_PERIOD node_1_keithley.trigger.timer1.passthrough = True node_1_keithley.trigger.timer1.stimulus = node_1_keithley.trigger.ARMED_EVENT_ID node_1_keithley.trigger.timer1.clear() # timer 2 controls the pulse width node_1_keithley.trigger.timer2.count = 1 node_1_keithley.trigger.timer2.delay = PULSE_LENGTH - 3e-6 node_1_keithley.trigger.timer2.passthrough = False node_1_keithley.trigger.timer2.stimulus = node_1_keithley.trigger.SOURCE_COMPLETE_EVENT_ID node_1_keithley.trigger.timer2.clear() # configure sweep node_1_keithley.trigger.source_linear_voltage(VOLTAGE_START/2, VOLTAGE_STOP/2, VOLTAGE_STEPS) node_1_keithley.trigger.source_limit_current = CURRENT_LIMIT # update this line after Keithley issue #40 resolved node_1_keithley.trigger.measure_iv('node[1].smua.nvbuffer1', 'node[1].smua.nvbuffer2') node_1_keithley.trigger.measure_action = node_1_keithley.trigger.ENABLE # configure end of pulse state node_1_keithley.trigger.endpulse_action = node_1_keithley.trigger.SOURCE_IDLE node_1_keithley.trigger.endsweep_action = node_1_keithley.trigger.SOURCE_IDLE node_1_keithley.trigger.count = VOLTAGE_STEPS node_1_keithley.trigger.arm_stimulus = 0 node_1_keithley.trigger.source_stimulus = node_1_keithley.trigger.timer1.event_id node_1_keithley.trigger.measure_stimulus = 0 node_1_keithley.trigger.endpulse_stimulus = node_1_keithley.trigger.timer2.event_id node_1_keithley.trigger.source_action = node_1_keithley.trigger.ENABLE def configure_node_2(): """ Configure the negative node of the IV sweep. This node is responsible for compliance. """ node_2_keithley.reset() node_2_keithley.source.func = node_2_keithley.source.OUTPUT_DCVOLTS node_2_keithley.sense = node_2_keithley.sense.SENSE_REMOTE node_2_keithley.source.offmode = node_2_keithley.source.OUTPUT_NORMAL node_2_keithley.source.off_function = node_2_keithley.source.OUTPUT_DCVOLTS node_2_keithley.source.offlimit_current = 0.9 * CURRENT_LIMIT node_2_keithley.source.offlimit_voltage = VOLTAGE_OFF_LIMIT node_2_keithley.source.range_current = CURRENT_LIMIT node_2_keithley.source.range_voltage = 40 node_2_keithley.measure.nplc = NPLC node_2_keithley.measure.range_voltage = 40 node_2_keithley.measure.autozero = node_2_keithley.measure.AUTOZERO_OFF node_2_keithley.measure.delay = MEASURE_DELAY node_2_keithley.nvbuffer1.clear() node_2_keithley.nvbuffer1.collectsourcevalues = 1 node_2_keithley.nvbuffer1.collecttimestamps = 1 node_2_keithley.nvbuffer1.fillmode = node_2_keithley.nvbuffer1.FILL_ONCE node_2_keithley.nvbuffer2.clear() node_2_keithley.nvbuffer2.collectsourcevalues = 1 node_2_keithley.nvbuffer2.collecttimestamps = 1 node_2_keithley.nvbuffer2.fillmode = node_2_keithley.nvbuffer1.FILL_ONCE node_2_keithley.tsplink.trigger1.clear() node_2_keithley.tsplink.trigger1.mode = node_2_keithley.tsplink.trigger1.TRIG_FALLING # timer 1 controls the pulse width for node 2 node_2_keithley.trigger.timer1.count = 1 node_2_keithley.trigger.timer1.delay = PULSE_LENGTH - 3e-6 node_2_keithley.trigger.timer1.passthrough = False node_2_keithley.trigger.timer1.stimulus = node_2_keithley.trigger.SOURCE_COMPLETE_EVENT_ID node_2_keithley.trigger.timer1.clear() # configure sweep node_2_keithley.trigger.source_linear_voltage(-1*VOLTAGE_START/2, -1*VOLTAGE_STOP/2, VOLTAGE_STEPS) node_2_keithley.trigger.source_limit_current = 0.9*CURRENT_LIMIT # update this line after Keithley issue #40 resolved node_2_keithley.trigger.measure_iv('node[2].smua.nvbuffer1', 'node[2].smua.nvbuffer2') node_2_keithley.trigger.measure_action = node_2_keithley.trigger.ENABLE # configure end of pulse state node_2_keithley.trigger.endpulse_action = node_2_keithley.trigger.SOURCE_IDLE node_2_keithley.trigger.endsweep_action = node_2_keithley.trigger.SOURCE_IDLE node_2_keithley.trigger.count = VOLTAGE_STEPS node_2_keithley.trigger.arm_stimulus = 0 node_2_keithley.trigger.source_stimulus = node_2_keithley.tsplink.trigger1.event_id node_2_keithley.trigger.measure_stimulus = 0 node_2_keithley.trigger.endpulse_stimulus = node_2_keithley.trigger.timer1.event_id node_2_keithley.trigger.source_action = node_2_keithley.trigger.ENABLE if __name__ == '__main__': verboseFlag = False argCount = 0 try: opts, args = getopt.getopt(sys.argv[1:], "hv", ["help", "verbose"]) except getopt.GetoptError: usage() sys.exit(1) for o, a in opts: if o in ("-h", "--help"): usage() sys.exit(2) elif o in ("-v", "--verbose"): verboseFlag = True else: sys.stderr.write(__file__ + ': unrecognized command line option: {0}'.format(str(o))) sys.exit(1) # create physical Keithley 2651A object smu2651a = keithley2651a.keithley2651a() node_1_keithley = keithley2651a.keithley2651a(gpib_obj=smu2651a.keithley, node_number=1) node_2_keithley = keithley2651a.keithley2651a(gpib_obj=smu2651a.keithley, node_number=2) smu2651a.tsplink.reset() # add check for number of nodes configure_node_1() configure_node_2() sys.stdout.write('test-dark-iv.py: starting IV sweep\n') node_1_keithley.source.output = node_1_keithley.source.OUTPUT_ON node_2_keithley.source.output = node_2_keithley.source.OUTPUT_ON #node_1_keithley.status.operation_sweeping_enable() node_2_keithley.trigger.initiate() node_1_keithley.trigger.initiate() time.sleep(0.1) count = 0 while count < VOLTAGE_STEPS: count = count + 1 status_byte = int(float(node_1_keithley.status.condition.strip())) current_time = datetime.now().strftime('%H%M%S') sys.stdout.write(f'Time: {current_time} Node 1 status: {status_byte:08b}\n') time.sleep(2*PULSE_PERIOD) time.sleep(5) # safe the instrument node_1_keithley.source.output = node_1_keithley.source.OUTPUT_OFF node_2_keithley.source.output = node_2_keithley.source.OUTPUT_OFF sys.stdout.write('test-dark-iv.py: IV sweep complete\n') node_1_currents = node_2_keithley.get_buffer_data(1, VOLTAGE_STEPS, 'node[1].smua.nvbuffer1') node_1_voltages = node_1_keithley.get_buffer_data(1, VOLTAGE_STEPS, 'node[1].smua.nvbuffer2') node_2_currents = node_2_keithley.get_buffer_data(1, VOLTAGE_STEPS, 'node[2].smua.nvbuffer1') node_2_voltages = node_2_keithley.get_buffer_data(1, VOLTAGE_STEPS, 'node[2].smua.nvbuffer2') sys.stdout.write('Node 1 currents: {0}\n'.format(node_1_currents)) sys.stdout.write('Node 1 voltages: {0}\n'.format(node_1_voltages)) sys.stdout.write('Node 2 currents: {0}\n'.format(node_2_currents)) sys.stdout.write('Node 2 voltages: {0}\n'.format(node_2_voltages)) sys.exit(0)