Skip to content

Commit b32edb8

Browse files
author
neil.hamilton
committed
Add ps6000aBlockMSODigitalTriggerExample.py for triggering on digital channels only
1 parent 577397d commit b32edb8

File tree

2 files changed

+238
-9
lines changed

2 files changed

+238
-9
lines changed

ps5000aExamples/ps5000aBlockAdvancedTriggerExample.py

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,29 +64,69 @@
6464
assert_pico_ok(status["maximumValue"])
6565

6666
# Set up an advanced trigger
67-
adcTriggerLevel = mV2adc(500, chARange, maxADC)
67+
adcTriggerLevelA = mV2adc(500, chARange, maxADC)
68+
adcTriggerLevelB = mV2adc(500, chARange, maxADC)
69+
adcTriggerLevelC = mV2adc(500, chARange, maxADC)
70+
adcTriggerLevelD = mV2adc(500, chARange, maxADC)
6871

69-
triggerProperties = ps.PS5000A_TRIGGER_CHANNEL_PROPERTIES_V2(adcTriggerLevel,
72+
triggerProperties = (ps.PS5000A_TRIGGER_CHANNEL_PROPERTIES_V2 * 4)()
73+
triggerProperties[0] = ps.PS5000A_TRIGGER_CHANNEL_PROPERTIES_V2(adcTriggerLevelA,
7074
10,
7175
0,
7276
10,
7377
ps.PS5000A_CHANNEL["PS5000A_CHANNEL_A"])
78+
79+
triggerProperties[1] = ps.PS5000A_TRIGGER_CHANNEL_PROPERTIES_V2(adcTriggerLevelB,
80+
10,
81+
0,
82+
10,
83+
ps.PS5000A_CHANNEL["PS5000A_CHANNEL_B"])
84+
85+
triggerProperties[2] = ps.PS5000A_TRIGGER_CHANNEL_PROPERTIES_V2(adcTriggerLevelC,
86+
10,
87+
0,
88+
10,
89+
ps.PS5000A_CHANNEL["PS5000A_CHANNEL_C"])
90+
91+
triggerProperties[3] = ps.PS5000A_TRIGGER_CHANNEL_PROPERTIES_V2(adcTriggerLevelD,
92+
10,
93+
0,
94+
10,
95+
ps.PS5000A_CHANNEL["PS5000A_CHANNEL_D"])
96+
7497

75-
status["setTriggerChannelPropertiesV2"] = ps.ps5000aSetTriggerChannelPropertiesV2(chandle, ctypes.byref(triggerProperties), 1, 0)
98+
status["setTriggerChannelPropertiesV2"] = ps.ps5000aSetTriggerChannelPropertiesV2(chandle, ctypes.byref(triggerProperties), 4, 0)
7699

77-
triggerConditions = ps.PS5000A_CONDITION(ps.PS5000A_CHANNEL["PS5000A_CHANNEL_A"],
100+
triggerConditionsA = ps.PS5000A_CONDITION(ps.PS5000A_CHANNEL["PS5000A_CHANNEL_A"],
101+
ps.PS5000A_TRIGGER_STATE["PS5000A_CONDITION_TRUE"])
102+
triggerConditionsB = ps.PS5000A_CONDITION(ps.PS5000A_CHANNEL["PS5000A_CHANNEL_B"],
103+
ps.PS5000A_TRIGGER_STATE["PS5000A_CONDITION_TRUE"])
104+
triggerConditionsC = ps.PS5000A_CONDITION(ps.PS5000A_CHANNEL["PS5000A_CHANNEL_C"],
105+
ps.PS5000A_TRIGGER_STATE["PS5000A_CONDITION_TRUE"])
106+
triggerConditionsD = ps.PS5000A_CONDITION(ps.PS5000A_CHANNEL["PS5000A_CHANNEL_D"],
78107
ps.PS5000A_TRIGGER_STATE["PS5000A_CONDITION_TRUE"])
79-
80108
clear = 1
81109
add = 2
82110

83-
status["setTriggerChannelConditionsV2"] = ps.ps5000aSetTriggerChannelConditionsV2(chandle, ctypes.byref(triggerConditions), 1, (clear + add))
111+
status["setTriggerChannelConditionsV2_A"] = ps.ps5000aSetTriggerChannelConditionsV2(chandle, ctypes.byref(triggerConditionsA), 1, (clear + add))
112+
status["setTriggerChannelConditionsV2_B"] = ps.ps5000aSetTriggerChannelConditionsV2(chandle, ctypes.byref(triggerConditionsB), 1, (add))
113+
status["setTriggerChannelConditionsV2_C"] = ps.ps5000aSetTriggerChannelConditionsV2(chandle, ctypes.byref(triggerConditionsC), 1, (add))
114+
status["setTriggerChannelConditionsV2_D"] = ps.ps5000aSetTriggerChannelConditionsV2(chandle, ctypes.byref(triggerConditionsD), 1, (add))
84115

85-
triggerDirections = ps.PS5000A_DIRECTION(ps.PS5000A_CHANNEL["PS5000A_CHANNEL_A"],
116+
triggerDirections = (ps.PS5000A_DIRECTION * 4)()
117+
triggerDirections[0] = ps.PS5000A_DIRECTION(ps.PS5000A_CHANNEL["PS5000A_CHANNEL_A"],
86118
ps.PS5000A_THRESHOLD_DIRECTION["PS5000A_RISING"],
87119
ps.PS5000A_THRESHOLD_MODE["PS5000A_LEVEL"])
88-
89-
status["setTriggerChannelDirections"] = ps.ps5000aSetTriggerChannelDirectionsV2(chandle, ctypes.byref(triggerDirections), 1)
120+
triggerDirections[1] = ps.PS5000A_DIRECTION(ps.PS5000A_CHANNEL["PS5000A_CHANNEL_B"],
121+
ps.PS5000A_THRESHOLD_DIRECTION["PS5000A_RISING"],
122+
ps.PS5000A_THRESHOLD_MODE["PS5000A_LEVEL"])
123+
triggerDirections[2] = ps.PS5000A_DIRECTION(ps.PS5000A_CHANNEL["PS5000A_CHANNEL_C"],
124+
ps.PS5000A_THRESHOLD_DIRECTION["PS5000A_RISING"],
125+
ps.PS5000A_THRESHOLD_MODE["PS5000A_LEVEL"])
126+
triggerDirections[3] = ps.PS5000A_DIRECTION(ps.PS5000A_CHANNEL["PS5000A_CHANNEL_D"],
127+
ps.PS5000A_THRESHOLD_DIRECTION["PS5000A_RISING"],
128+
ps.PS5000A_THRESHOLD_MODE["PS5000A_LEVEL"])
129+
status["setTriggerChannelDirections"] = ps.ps5000aSetTriggerChannelDirectionsV2(chandle, ctypes.byref(triggerDirections), 4)
90130

91131

92132
# Set number of pre and post trigger samples to be collected
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
#
2+
# Copyright (C) 2020-2024 Pico Technology Ltd. See LICENSE file for terms.
3+
#
4+
# PS6000 A MSO BLOCK MODE DIGITAL TRIGGER EXAMPLE
5+
# This example opens a 6000a driver device, sets up one analogue channel and one digital channel and a digital trigger then collects a block of data.
6+
# This data is then plotted as mV against time in ns.
7+
8+
import ctypes
9+
import numpy as np
10+
from picosdk.ps6000a import ps6000a as ps
11+
from picosdk.PicoDeviceEnums import picoEnum as enums
12+
import matplotlib.pyplot as plt
13+
from picosdk.functions import adc2mV, assert_pico_ok, splitMSODataFast
14+
15+
# Create chandle and status ready for use
16+
chandle = ctypes.c_int16()
17+
status = {}
18+
19+
# Open 6000 A series PicoScope
20+
# returns handle to chandle for use in future API functions
21+
resolution = enums.PICO_DEVICE_RESOLUTION["PICO_DR_8BIT"]
22+
status["openunit"] = ps.ps6000aOpenUnit(ctypes.byref(chandle), None, resolution)
23+
assert_pico_ok(status["openunit"])
24+
25+
# Set channel A on
26+
# handle = chandle
27+
channelA = enums.PICO_CHANNEL["PICO_CHANNEL_A"]
28+
coupling = enums.PICO_COUPLING["PICO_DC_50OHM"]
29+
channelRange = 5
30+
# analogueOffset = 0 V
31+
bandwidth = enums.PICO_BANDWIDTH_LIMITER["PICO_BW_FULL"]
32+
status["setChannelA"] = ps.ps6000aSetChannelOn(chandle, channelA, coupling, channelRange, 0, bandwidth)
33+
assert_pico_ok(status["setChannelA"])
34+
35+
# set channel B-H off
36+
for x in range (1, 7, 1):
37+
channel = x
38+
status["setChannel",x] = ps.ps6000aSetChannelOff(chandle,channel)
39+
assert_pico_ok(status["setChannel",x])
40+
41+
# set MSO pod 1 on
42+
# handle = chandle
43+
port = enums.PICO_CHANNEL["PICO_PORT0"]
44+
# logic level needs to be set individually for all digital channels/pins in the port
45+
pins = 8
46+
logicThresholdLevel = (ctypes.c_int16 * pins)(0)
47+
logicThresholdLevel[0] = 1000
48+
logicThresholdLevelLength = len(logicThresholdLevel)
49+
hysteresis = enums.PICO_DIGITAL_PORT_HYSTERESIS["PICO_LOW_50MV"]
50+
status["setDigitalPortOn"] = ps.ps6000aSetDigitalPortOn(chandle, port, ctypes.byref(logicThresholdLevel), logicThresholdLevelLength, hysteresis)
51+
assert_pico_ok(status["setDigitalPortOn"])
52+
53+
# Set MSO pod 2 off
54+
port2 = enums.PICO_CHANNEL["PICO_PORT1"]
55+
status["setDigitalPortOff"] = ps.ps6000aSetDigitalPortOff(chandle,port2)
56+
assert_pico_ok(status["setDigitalPortOff"])
57+
58+
# get max ADC value
59+
# handle = chandle
60+
minADC = ctypes.c_int16()
61+
maxADC = ctypes.c_int16()
62+
status["getAdcLimits"] = ps.ps6000aGetAdcLimits(chandle, resolution, ctypes.byref(minADC), ctypes.byref(maxADC))
63+
assert_pico_ok(status["getAdcLimits"])
64+
65+
# Set trigger on digital channel 0 Port 1 for rising logic level transition
66+
conditions = (struct.PICO_CONDITION * 1)()
67+
conditions = struct.PICO_CONDITION(enums.PICO_CHANNEL.PICO_PORT0 , enums.PICO_TRIGGER_STATE["PICO_CONDITION_TRUE"])
68+
nConditions = 1
69+
clear = enums.PICO_ACTION["PICO_CLEAR_ALL"]
70+
add = enums.PICO_ACTION["PICO_ADD"]
71+
action = clear|add
72+
status["setTriggerChannelConditions"] = ps.ps6000aSetTriggerChannelConditions(chandle, ctypes.byref(conditions),nConditions,action)
73+
assert_pico_ok(status["setTriggerChannelConditions"])
74+
75+
directions = (struct.PICO_DIGITAL_CHANNEL_DIRECTIONS * 1)()
76+
directions = stuct.PICO_DIGITAL_CHANNEL_DIRECTIONS(enums.PICO_PORT_DIGITAL_CHANNEL.PICO_PORT_DIGITAL_CHANNEL0,enums.PICO_DIGITAL_DIRECTION.PICO_DIGITAL_DIRECTION_RISING)
77+
nDirections = 1
78+
status["setTriggerDigitalPortProperties"] = ps.ps6000a.SetTriggerDigitalPortProperties(chandle,port,ctypes.byref(directions),nDirections)
79+
assert_pico_ok(status["setTriggerDigitalPortProperties"])
80+
81+
82+
# Set number of samples to be collected
83+
noOfPreTriggerSamples = 500000
84+
noOfPostTriggerSamples = 1000000
85+
nSamples = noOfPostTriggerSamples + noOfPreTriggerSamples
86+
87+
# Check timebase is valid
88+
# handle = chandle
89+
timebase = ctypes.c_uint32(1)
90+
timeInterval = ctypes.c_double(0)
91+
returnedMaxSamples=ctypes.c_uint64()
92+
#segment = 0
93+
status["getTimebase"] = ps.ps6000aGetTimebase(chandle, timebase, nSamples, ctypes.byref(timeInterval), ctypes.byref(returnedMaxSamples), 0)
94+
assert_pico_ok(status["getTimebase"])
95+
print("timebase = ", timebase.value)
96+
print("sample interval =", timeInterval.value, "ns")
97+
98+
# Create buffers
99+
bufferAMax = (ctypes.c_int16 * nSamples)()
100+
bufferAMin = (ctypes.c_int16 * nSamples)() # used for downsampling which isn't in the scope of this example
101+
102+
bufferDPort0Max = (ctypes.c_int16 * nSamples)()
103+
bufferDPort0Min = (ctypes.c_int16 * nSamples)()
104+
105+
# Set data buffers
106+
# handle = chandle
107+
# channel = channelA
108+
# bufferMax = bufferAMax
109+
# bufferMin = bufferAMin
110+
# nSamples = nSamples
111+
dataType = enums.PICO_DATA_TYPE["PICO_INT16_T"]
112+
waveform = 0
113+
downSampleMode = enums.PICO_RATIO_MODE["PICO_RATIO_MODE_RAW"]
114+
clear = enums.PICO_ACTION["PICO_CLEAR_ALL"]
115+
add = enums.PICO_ACTION["PICO_ADD"]
116+
action = clear|add # PICO_ACTION["PICO_CLEAR_WAVEFORM_CLEAR_ALL"] | PICO_ACTION["PICO_ADD"]
117+
status["setDataChABuffers"] = ps.ps6000aSetDataBuffers(chandle, channelA, ctypes.byref(bufferAMax), ctypes.byref(bufferAMin), nSamples, dataType, waveform, downSampleMode, action)
118+
assert_pico_ok(status["setDataChABuffers"])
119+
120+
status["setDataDP0Buffers"] = ps.ps6000aSetDataBuffers(chandle, port, ctypes.byref(bufferDPort0Max), ctypes.byref(bufferDPort0Min), nSamples, dataType, waveform, downSampleMode, action)
121+
assert_pico_ok(status["setDataDP0Buffers"])
122+
123+
# Run block capture
124+
# handle = chandle
125+
# timebase = timebase
126+
timeIndisposedMs = ctypes.c_double(0)
127+
# segmentIndex = 0
128+
# lpReady = None Using IsReady rather than a callback
129+
# pParameter = None
130+
status["runBlock"] = ps.ps6000aRunBlock(chandle, noOfPreTriggerSamples, noOfPostTriggerSamples, timebase, ctypes.byref(timeIndisposedMs), 0, None, None)
131+
assert_pico_ok(status["runBlock"])
132+
133+
# Check for data collection to finish using ps5000aIsReady
134+
ready = ctypes.c_int16(0)
135+
check = ctypes.c_int16(0)
136+
while ready.value == check.value:
137+
status["isReady"] = ps.ps6000aIsReady(chandle, ctypes.byref(ready))
138+
139+
# Get data from scope
140+
# handle = chandle
141+
# startIndex = 0
142+
noOfSamples = ctypes.c_uint64(nSamples)
143+
# downSampleRatio = 1
144+
# segmentIndex = 0
145+
overflow = ctypes.c_int16(0)
146+
status["getValues"] = ps.ps6000aGetValues(chandle, 0, ctypes.byref(noOfSamples), 1, downSampleMode, 0, ctypes.byref(overflow))
147+
assert_pico_ok(status["getValues"])
148+
149+
150+
151+
# convert ADC counts data to mV
152+
adc2mVChAMax = adc2mV(bufferAMax, channelRange, maxADC)
153+
154+
# Obtain binary for Digital Port 0
155+
# The tuple returned contains the channels in order (D7, D6, D5, ... D0).
156+
bufferDPort0 = splitMSODataFast(noOfSamples, bufferDPort0Max)
157+
158+
# Create time data
159+
time = np.linspace(0, (nSamples -1) * timeInterval.value * 1000000000, nSamples)
160+
161+
# plot data from channel A and B
162+
plt.figure(num='Channel A Data')
163+
plt.plot(time, adc2mVChAMax[:])
164+
plt.xlabel('Time (ns)')
165+
plt.ylabel('Voltage (mV)')
166+
plt.title('Channel A data')
167+
#plt.show()
168+
169+
# Plot the data from digital channels onto a graph
170+
plt.figure(num='Digital Port 0 Data')
171+
plt.title('Plot of Digital Port 0 digital channels vs. time')
172+
plt.plot(time, bufferDPort0[0], label='D7') # D7 is the first array in the tuple.
173+
plt.plot(time, bufferDPort0[1], label='D6')
174+
plt.plot(time, bufferDPort0[2], label='D5')
175+
plt.plot(time, bufferDPort0[3], label='D4')
176+
plt.plot(time, bufferDPort0[4], label='D3')
177+
plt.plot(time, bufferDPort0[5], label='D2')
178+
plt.plot(time, bufferDPort0[6], label='D1')
179+
plt.plot(time, bufferDPort0[7], label='D0') # D0 is the last array in the tuple.
180+
plt.xlabel('Time (ns)')
181+
plt.ylabel('Logic Level')
182+
plt.legend(loc="upper right")
183+
plt.show()
184+
185+
# Close the scope
186+
status["closeunit"] = ps.ps6000aCloseUnit(chandle)
187+
assert_pico_ok(status["closeunit"])
188+
189+
print(status)

0 commit comments

Comments
 (0)