Posted Tue, 31 Dec 2024 13:45:59 GMT by Payne, Matt
Hi all. I am brand new to programming these instruments and can't figure out the best way to do this, so I'm looking for ideas from those more experienced than myself.

The situation:
In performing a response time test on a pneumatic valve, I need to synchronize the analog read of an NI DAQ device and the source output of a Keithley 2601B.

The setup:
The 2601B is being controlled over LAN by a LabVIEW program. A digital IO line from the 2601B is connected to the NI device (USB-6353) on a PFI line to act as a digital trigger to start the high-speed analog read. The steps are:
  1. NI: Set up a triggered analog read task triggered by this digital line.
  2. NI: Start task, wait for trigger.
  3. 2601B: Set source output level via TSP command (pre-canned VI, "smua.source.levelv = X").
  4. 2601B: Set source output on and set digital IO bit on in same command (modified VI, "digio.writebit(1,1)" and "smua.source.output = smua.OUTPUT_ON" sent in same TCP/IP command, separated by a return/line feed).
The problem:
Depending what order the commands in step 4 are written, there is an approximately 5ms difference in result which is way too much for this application. This suggests that even though the commands to turn on source output and turn on the digital line are sent at the same time, there's enough overhead in executing them that way to affect the result.

We need the digital line and the source output to go on at exactly the same time, or at least within maybe 1ms. I imagine there is an easy way to do this, I just am not familiar enough with all these commands to see it. Any ideas?
Posted Tue, 31 Dec 2024 15:27:51 GMT by C, Andrea
For sure, we can get the timing of the DIO and the sourcing more synchronized.
Is the 2601B doing anything else?  Any measuring?
Does the source level stay applied until you send new commands?

To have the best synchronization will require use of the trigger model.
Both the DIO output trigger and the source stimulus can be setup to use the same start event (or software assert).
With this approach you can get the synchronization to sub microsecond.
You can even deliberately time skew them if you wanted to trigger and then source a known amount of time later.

Before re-architecting the code for trigger model, you could most likely realize some time improvement by defining a function in the runtime memory of the 2601B.  Your LabVIEW code would need to use a VISA level write to call your function.  The function would issue the DIO, output on, etc like what you are doing now.  The time savings comes from requiring just a single bus command between LabVIEW and the 2601B.
The function execution would still sequentially carry out the lines of code.  But the command parsing from the bus is reduced to just once.
Posted Tue, 31 Dec 2024 20:38:37 GMT by Payne, Matt
Thanks for the quick reply! The 2601B won't be doing anything else during this test, just supplying power to the part under test. The source can stay on until explicitly commanded off, especially if it simplifies things.

The trigger model sounds like what we'd want and I've been trying to figure it out. I think I have something that works, but it's a little different than what I was planning. It seems I can't command "smua.trigger.initiate()" without the output already on. So I can't actually trigger the output turning on, but I can trigger the output going to a level by doing a 1 step sweep which will probably be OK, it just feels a little clunky.

Is there any way to actually simply trigger the output enable?
Posted Thu, 02 Jan 2025 17:22:35 GMT by C, Andrea
Hi Matt,
Those are great observations.
For either approach, as your "resting state" can you have the SMU output (the blue light) on, but have it forcing 0V?
Then when ready for testing, command the digital IO and the source level to change to a new level.

If I measure the time required to turn the smua.source.output on and off wiht the source level set to 3V, I'm getting about 8 msec for that operation.
When output is off, the SMU is still actively sourcing and limiting according to the output off mode and settings.
When output is then turned on, the new settings have to be applied, and you are seeing some overhead associated with that.

In contrast, if the output is already on but at 0V, then changing the source level to a different level requires much less time.

Combining this info about the source output and my prior suggestion about using a function to reduce bus traffic, I'm seeing less then 40usec from the DIO changing state and the start of the SMU source level changing.

Some TSP code to illustrate the concept:
function config_smu(v_src, iLimit)
    smua.source.func = smua.OUTPUT_DCVOLTS
    smua.source.limiti = iLimit
    smua.source.rangev = v_src
    smua.source.levelv = 0   -- this is the resting bias level as soon as output is turned on
    smua.measure.nplc = 1
    smua.measure.delay = smua.DELAY_AUTO
    smua.measure.delayfactor = 1.0
end  -- function

function speed_test(dio_line, v_src)
    -- to run the configured setup
    digio.writebit(dio_line, 0)  -- make digio low state
     smua.source.levelv = v_src
    digio.writebit(dio_line, 1)
end  -- function

-- test our function
reset()
errorqueue.clear()
digio_line = 1
config_smu(2.5, 0.1)  -- config for 2.5V and 100mA
smua.source.output = smua.OUTPUT_ON
for i = 1, 10 do
     --speed_test(v_src)
    speed_test(digio_line, 2.5)
    delay(100e-6)
    smua.source.levelv = 0
   
end
smua.source.output = smua.OUTPUT_OFF

A screen shot from the scope is attached.
Posted Thu, 02 Jan 2025 20:25:05 GMT by Payne, Matt
Very interesting, and thank you for going through all the effort to try that out! I'm going to try and customize your example and see what I get because using the LabVIEW VI's to set up a remote trigger model, I still get a consistent 3ms delay between the digital output line turning on and the source output changing according to an oscilloscope. This is the equivalent set of commands:
smua.source.output = smua.OUTPUT_ON
smua.trigger.arm.count = 1 
smua.trigger.arm.stimulus = 0 
smua.trigger.source.stimulus = smua.trigger.ARMED_EVENT_ID 
digio.trigger[1].mode = digio.TRIG_RISINGM 
digio.trigger[1].stimulus = smua.trigger.ARMED_EVENT_ID 
digio.trigger[1].pulsewidth = 1.000000 
smua.trigger.source.action = 1 
smua.trigger.source.linearv(10.000000, 10.000000, 1) 
smua.trigger.source.limitv = 10.000000 
smua.source.delay = 1.000000
smua.trigger.autoclear = smua.ENABLE 
smua.trigger.initiate()
smua.trigger.arm.set()
waitcomplete()
smua.abort()
This results in a 1 second pulse of both the source output (at 10V) and the digital line which works perfectly with the rest of the test machine, but I always get a 3ms delay which is just too much. 40µs though would be great!

As for my previous question about triggering the actual source output going on or off, I think you make a good point that that is not the way to do it. That's just an old method we used on a previous machine that was driving parts with a simple op amp with a disable line, so we'd trigger the analog read off the signal to turn the op amp on or off. An SMU is a very different device, so it doesn't really make sense to do it that way.

In fact, all we really need to control here is the timing of setting the output level and the turning on of the digital line. If doing an off-response time test, we'd have the SMU already sourcing a voltage, so we'd just need to execute a synchronized digital line on and source voltage level to 0. If doing on response, the source output level would already be commanded to 0 so we'd just need to set the level to the test voltage and turn on the digital line, again at the same time. I don't think we need to control any of the previous state with this function, and actually would prefer not to so I don't have to change what I'm doing before.

So I am going to try and customize your example to execute a function that simply sets a voltage level and turns on the digital line and see what sort of timing I get there. Thank you again!
Posted Thu, 02 Jan 2025 21:30:27 GMT by Payne, Matt
Quick update, it seems that 3ms may just be the time it takes to set the voltage. Depending what order I put "smua.source.levelv = " and "digio.writebit()" in my function, I get different results. If I set the level first, the output comes on about 270µs later. If I set the output bit first, the source voltage doesn't rise until about 3ms later. So doing the former, we end up improving our results by about a quarter of a millisecond, but short of configuring the NI device for analog triggering, this looks like the best way.
Posted Fri, 03 Jan 2025 14:48:19 GMT by Payne, Matt
Another update, I was able to improve the delay to about 80-90µs by manually setting the source range. Interestingly, it also seems to be the same delay no matter which order the function is written, DIO then source or source then DIO. Either way the source level is set about 87µs after the DIO line turns on. This is very acceptable!

My function is:
function response_test(dio_line,v_test,delay_s)
    digio.writebit(dio_line,1)
    smua.source.levelv = v_test
    delay(delay_s)
    digio.writebit(dio_line,0)
end

So to a 5V, 500ms test, the execution would be:
smua.source.rangev = 6
smua.soruce.output = smua.OUTPUT_ON
response_test(1,5,0.5)
waitcomplete() --not sure if I actually need this anymore
smua.source.autorangev = 1

Thanks again for your help, and if there are any further recommendations, I'm always open to improving!
Posted Fri, 03 Jan 2025 15:59:05 GMT by C, Andrea
Great progress.  Let me give you some trigger model sample code to illustrate the very tight timing you can achieve.

Attached is a scope capture.
The digital IO have pull up resistors so will be at 5V or logic HI by default.  Looks like you want a rising edge trigger for your DAC board, so you've been using a mode command to change the DIO state.  The scope capture starts at that occurrence.

Subsequently, when the trigger model task is started, the DIO goes to 5V and the SMU goes to 10V.
function config_smu(v_src, iLimit)
    smua.source.func = smua.OUTPUT_DCVOLTS
    smua.source.limiti = iLimit
    smua.source.rangev = v_src
    smua.source.levelv = 0   -- this is the resting bias level as soon as output is turned on
    smua.measure.nplc = 1
    smua.measure.delay = smua.DELAY_AUTO
    smua.measure.delayfactor = 1.0
end  -- function

function config_dio()
    digio.trigger[1].mode = digio.TRIG_RISINGM
    digio.trigger[1].stimulus = smua.trigger.ARMED_EVENT_ID
    digio.trigger[1].pulsewidth = 1.000000
end  -- function

function config_trigger_model()
    smua.trigger.arm.count = 1
    smua.trigger.arm.stimulus = 0
    smua.trigger.source.stimulus = smua.trigger.ARMED_EVENT_ID
    smua.trigger.source.action = 1
    --smua.trigger.source.linearv(10.000000, 10.000000, 1)
    smua.trigger.source.listv({10})   -- single point list sweep is another way
    smua.trigger.source.limiti = 0.1
    --smua.source.delay = 1.000000
    smua.trigger.autoclear = smua.ENABLE
    smua.trigger.count = 1   -- set this equal to number of sweep or list points
    smua.trigger.endpulse.action = smua.SOURCE_HOLD
    smua.trigger.endsweep.action = smua.SOURCE_HOLD
end  -- function
​​​​​​​
-- **************************************************
-- use the functions
reset()
errorqueue.clear()
config_smu(10, 0.1)
config_dio()
config_trigger_model()
smua.source.output = smua.OUTPUT_ON

delay(0.5)  -- not needed....just allows us to see the dio setup of getting to LO state
smua.trigger.initiate()
delay(1.25)  -- not needed...just delay a bit before setting the SMU source level back to zero
smua.source.levelv = 0

 
Posted Fri, 03 Jan 2025 16:00:49 GMT by C, Andrea
Attached is a document that describes how to make use of the TSP functions and scripts from LabVIEW.
The LV driver for 2600x has a Load Script VI.

You must be signed in to post in this forum.