Cannot get trigger to work
Closed this issue · 26 comments
I am using Picoscope 3406 D (uses p3000a sdk) I was able set a trigger and pickup a signal from my FPGA using the C code provided by pico tech.
I am trying to do the same in the Python code with the provided example
(test_ps3000.py). However, the code doesn't seem to pick up any trigger. In fact, it should wait a timeout period and do an auto-trigger, but that seems to be faulty as well. In the end, I am trying to set a trigger on Channel A, and read power from Channel B. Even if I just want to do both trigger and read from Channel A, I can't.
The call to ps.waitReady() just keeps on waiting.
Anything I'm missing or doing wrong?
Code:
import matplotlib.pyplot as plt
import numpy as np
import time
from picoscope import ps3000a
#SERIAL_NUM = 'AR911/011\x00'
#ps = ps3000a.PS3000a(SERIAL_NUM)
ps = ps3000a.PS3000a()
# now = time.strftime("%Y%m%d_%H%M%S")
# filename = "sweep_" + now + ".swp"
# output_file = open(filename, "wb")
c = 3e8
# rapid block mode
ps.setChannel(channel="A", coupling="DC", VRange=1)
#ps.setChannel(channel="B", coupling="AC", VRange=1) --> Commented out for now, but would need # #to get Channel B's readings
n_captures = 2300 * 3 # int(600 * 1.4)
sample_interval = 5 / 3e8
sample_duration = 1e3 * 2 / 3e8
ps.setSamplingInterval(sample_interval, sample_duration)
ps.setSimpleTrigger("A", threshold_V=0.1)
#ps.lib.ps3000SetTriggerChannelProperties(ps.handle, )
samples_per_segment = ps.memorySegments(n_captures)
ps.setNoOfCaptures(n_captures)
data = np.zeros((n_captures, samples_per_segment), dtype=np.int16)
t1 = time.time()
ps.runBlock()
ps.waitReady()
t2 = time.time()
print("Time to get sweep: " + str(t2 - t1))
ps.getDataRawBulk(data=data)
t3 = time.time()
print("Time to read data: " + str(t3 - t2))
plt.imshow(data[:, 0:ps.noSamples], aspect='auto', interpolation='none',
cmap=plt.cm.hot)
plt.colorbar()
plt.show()
ps.close()
I'm sorry, I haven't used the picoscope in a while.
I have a feeling that you want to call the function getDataV
.
Thanks for the response.
Are you suggesting to use getDataV in lieu of getDataRawBulk()? The test code (test_ps3000a.py) doesn't reach that far, it gets stuck waiting for a trigger.
Yeah, getDataRawBulk
doesn't seem like something you should be doing the first time you use the library.
Maybe we can make that a hidden function or something.
Okay I will try it, thanks
Sorry to bug you again, but I tried getDataV and still have the same issue. The issue arises before the code hits the data collection line (getDataV or getDataRawBulk). The issue is that the trigger is never picked up, even though I was able to do it in C code with the same hardware/pico setup.
Perhaps there is sample code that works for other picoscopes? Maybe that will point me to the right direction.
(see code in bold, ps.waitReady())
Updated code
import matplotlib.pyplot as plt
import numpy as np
import time
from picoscope import ps3000a
ps = ps3000a.PS3000a()
c = 3e8
#rapid block mode
print(ps.handle)
print(ps.getAllUnitInfo())
ps.setChannel(channel="A", coupling="DC", VRange=1)
ps.setChannel(channel="B", coupling="AC", VRange=1)
n_captures = 2300 * 3 # int(600 * 1.4)
sample_interval = 5 / 3e8
sample_duration = 1e3 * 2 / 3e8
ps.setSamplingInterval(sample_interval, sample_duration)
ps.setSimpleTrigger("A", threshold_V=0.1)
samples_per_segment = ps.memorySegments(n_captures)
ps.setNoOfCaptures(n_captures)
data = np.zeros((n_captures, samples_per_segment), dtype=np.int16)
t1 = time.time()
ps.runBlock()
**ps.waitReady()** # execution waits here for a trigger. The trigger has proven to get other code (C code #to trigger)
t2 = time.time()
print("Time to get sweep: " + str(t2 - t1))
ps.getDataV(channel = 'B', data=data)
t3 = time.time()
print("Time to read data: " + str(t3 - t2))
plt.imshow(data[:, 0:ps.noSamples], aspect='auto', interpolation='none',
cmap=plt.cm.hot)
plt.colorbar()
plt.show()
ps.close()
Can you show us your C code? Most of what our code does is make the C code "pythonic".
Also please use tripple backticks "```" to correctly format code.
Yes, I will upload it in my git and provide you with a link and explanation in a bit. It is basically from picotech itself.
The C code is able to pick up a trigger from my FPGA when invoked through ChipWhisperer.
Under https://github.com/hadisajj2/ps3000a/blob/master/ps3000acon.c. In the main function, select voltage ranges for channels A and B (or just one channel to see the trigger).
Then select 'T' (collectBlockTriggered).
Going into the function calls, you will arrive at the setTrigger function. Here, I override picotech's code and with one simple line:
ps3000aSetSimpleTrigger(unit->handle, 1, 0, 0, 2, 0, 5000);
It basically looks at channel A rising with a 5 second wait.
Like 684 under blockDataHandler is where the code waits for a trigger. Through my ChipWhisperer's GUI, I run the code on my FPGA and my picoscope picks up the voltage variation and the C code fires a trigger.
Your help is much appreciated.
Sorry for not being able to be of much help, but you need to recreate a much smaller sample code that shows the underlying issue.
Ideally, it would be only 10 lines long. For example, the python code you showed could obviate alot of the matplotlib calls as they aren't really necessary for reproducing your bug.
Are you actually trying to use Rapid Block Mode? If so, you actually need getDataRawBulk
. Sorry for the misdirection.
From what I remember, Rapid Block Mode is much harder to use. Try with normal acquisition first.
Look at https://github.com/colinoflynn/pico-python/blob/master/examples/sigGetBuiltIndemo.py
Ignore the AWG part if you want, but it uses simple acquisition which is much easier to use!
Okay thanks, I will produce a smaller C code shortly!
Thanks again. I have the C code below. I've omitted some of the struct details, but take my word that it works! Below should give you a rough pseudo-real code of what I'm trying to achieve. The code below correctly identifies a trigger. This is not really code I wrote, but I took Pico-tech's C SDK examples and tried my best to water it down to as few lines as possible.
....define Unit...
...set BOOL g_ready= false..
UNIT unit; // this holds unit information such as handle etc.
openDevice(&unit); //
setVoltages(&unit); // sets channel ranges , in this case only Channel A is set to a range of 200 mV
ps3000aSetSimpleTrigger(unit.handle, 1, 0, 0.2, 2, 0, 5000);
int16_t * buffers[PS3000A_MAX_CHANNEL_BUFFERS];
int32_t timeInterval;
int32_t sampleCount = BUFFER_SIZE;
int32_t maxSamples;
int32_t timeIndisposed;
PS3000A_RATIO_MODE ratioMode = PS3000A_RATIO_MODE_NONE;
buffers[0 * 2] = (int16_t*)calloc(sampleCount, sizeof(int16_t));
buffers[0 * 2 + 1] = (int16_t*)calloc(sampleCount, sizeof(int16_t));
ps3000aSetDataBuffers(unit.handle, (PS3000A_CHANNEL)0, buffers[0 * 2], buffers[0 * 2 + 1], sampleCount, 0, ratioMode);
/* Find the maximum number of samples and the time interval (in nanoseconds) */
while (ps3000aGetTimebase(unit.handle, timebase, sampleCount, &timeInterval, oversample, &maxSamples, 0))
{
timebase++;
}
/* Start the device collecting, then wait for completion*/
g_ready = FALSE;
ps3000aRunBlock(unit.handle, 0, sampleCount, timebase, oversample, &timeIndisposed, 0, callBackBlock, NULL); //callBackBlock merely checks to see if the pico_scope is not in "PICO_CANCELLED") state and sets g_ready = TRUE
printf("Waiting for trigger...Press a key to abort\n");
while (!g_ready && !_kbhit())
{
Sleep(0);
}
if (g_ready)
{
ps3000aGetValues(unit.handle, 0, (uint32_t*)&sampleCount, 1, ratioMode, 0, NULL);
}```
I would step through the python code, and see exactly what the program is sending to the ps3000aSetSimpleTrigger. you are sending in a hard number 5000, which may or may not be equal to 0.1V
Okay thanks, I will re-look into it. The 5000 is the trigger timeout, in the code above the voltage range is set to 1.0 V
so is the 0.2
the threshold that is being set by the c code?
your python examples had 0.1 set.
Yes, the C code sets it.
I changed it to 0.2 because it at time picking up noise and not a manual trigger from my end.
I really don't know. Sorry.
You can probably try an older version of the library, but I don't think it will make a big difference.
I assume you have access to the programming guide: https://www.picotech.com/download/manuals/PicoScope3000SeriesAApiProgrammersGuide.pdf
Just make sure to follow 3.7.1.1 Using block mode
as it is the most straightforward way to get connected to the scope.
try removing and just using the fact that you will have a single capture
samples_per_segment = ps.memorySegments(n_captures)
ps.setNoOfCaptures(n_captures)
Okay thanks. I will figure it out and post my solution. Once again thanks for all the help
I think your solution would make a great first example!
Those examples definitely need to be renamed as I don't even know what they do anymore ;)
Sorry to bug again, but I can't find, at least for ps3000a, anything except runBlock()? The pico sdk has
ps3000aRunStreaming, but the python code doesn't have a wrapper for this or am I missing something?
Well yes and no.
Based on the code, my understanding is that getDataV and/or getDataRaw collect data once you've told the oscilloscope how to collect data (e.g. start collecting streamed OR block). In the pico-api, this is like this:
ps3000aRunStreaming --> tells the oscilloscope to start collecting streamed data. Note you can still set triggers on channel.
ps3000aRunBlock --> tells the oscilloscope to start collecting Block data.
I understand that getDataV and getDataRaw are the equivalents (or at least somewhat equivalent) of
ps3000aGetValuesBulk
ps3000aGetStreamingLatestValues
If you take a look at picobase.py for ps3000a, getDataV says:
def getDataV(self, channel, numSamples=0, startIndex=0, downSampleRatio=1,
downSampleMode=0, segmentIndex=0, returnOverflow=False,
exceptOverflow=False, dataV=None, dataRaw=None,
dtype=np.float64):
Return the data as an array of voltage values.
it returns (dataV, overflow) if returnOverflow = True
else, it returns returns dataV
dataV is an array with size numSamplesReturned
overflow is a flag that is true when the signal was either too large
or too small to be properly digitized
if exceptOverflow is true, an IOError exception is raised on overflow
if returnOverflow is False. This allows you to detect overflows at
higher layers w/o complicated return trees. You cannot however read the
'good' data, you only get the exception information then.
No mention of telling the pico-scope to start collecting data, albeit there might be a trigger.
Perhaps I'm missing something fundamental here, I apologize if that is the case!
Block, Bulk, Streaming are all different modes. Stick to Block for the beginning.
The library we wrote isn't magic. it mostly just wraps the C library for python. The documentation is sparse because we expect you to read the picoscope programming guide. We don't add much magic, and most of the variable names are 'pythonified' C names.
You should be able to dive into the code, and notice that the function getDataV
mostly calls getDataRaw
and performs scaling. This is from the code itself, and not from the documentation (though the documentation should give you an indication that that is happening).
Finally, you should see 3 important calls in getDataRaw
:
You are in charge of following the other instructions to ensure that all function calls they describe are set.
Sorry for the late reply.
I got it to work for a simple trigger by removing ps.memorySegments(n_captures) and setting the number of captures, then using getDataRaw.
Great to hear! yeah the picoscope is definitely powerful, but kinda annoying to get working.
It is really optimized for high throughput applications!
Thanks for all your help!