Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Picoscope 3205 MSO support #4

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ Current version of the program was tested under Linux only. Later, I'll test it

## Supported AWG Models

As of January 30, 2019 the program supports the following models:
As of June 7, 2020 the program supports the following models:

* **BK Precision BK4075** One channel 25MHz AWG. Requires a RS-232 serial port for the connection to a PC. It is compatible with the SCPI 1992.0 standard.

* **RD JDS6600** Chinese generator which is widely sold on eBay and AliExpress. It connects to the PC as a USB serial port.

* **Feeltech FY6600** Another Chinese generator which is widely sold on eBay and AliExpress. It also connects to the PC as a USB serial port.

* **Picoscope 3000a series** A UK made USB scope that includes a basic function generator/AWG in some models. There is an API that needs downloading from Picotech, also their python wrappers are needed. Tested with the Picoscope 3205 MSO only but should work with other models.

## Program Structure
TBD

Expand Down Expand Up @@ -103,6 +105,10 @@ VXI-11 DESTROY_LINK, SCPI command: None

## Changelog

### 2020-06-07

* Support for the Picoscope 3205 MSO

### 2019-01-30

* The program supports Feeltech FY6600 AWG.
Expand All @@ -125,6 +131,8 @@ I'd like to add here more AWGs but it's impossible to have them all at the home

* **Nick Bryant (Dundarave on EEVblog Forum)** - Driver for Feeltech FY6600 AWG.

* **Mark Watson** - Driver for Picoscope 3205 MSO.

## Links

1. [Siglent SDS1104X-E and SDS1204X-E: Bode plot with non-Siglent AWG](http://www.eevblog.com/forum/testgear/siglent-sds1104x-e-and-sds1204x-e-bode-plot-with-non-siglent-awg/) on EEVblog Forum.
Expand Down
3 changes: 3 additions & 0 deletions sds1004x_bode/awg_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
@author: 4x1md

Update of original file on Nov. 17 2018 by Dundarave to add entries needed for FY6600 support.
Update of original file on Jun. 7 2020 by Mark Watson to add entries needed for ps3000a support.
'''

from awgdrivers.dummy_awg import DummyAWG
from awgdrivers.jds6600 import JDS6600
from awgdrivers.bk4075 import BK4075
from awgdrivers.fy6600 import FY6600
from awgdrivers.ps3000a import ps3000a

class AwgFactory(object):

Expand All @@ -28,4 +30,5 @@ def get_class_by_name(self, short_name):
awg_factory.add_awg(JDS6600.SHORT_NAME, JDS6600)
awg_factory.add_awg(BK4075.SHORT_NAME, BK4075)
awg_factory.add_awg(FY6600.SHORT_NAME, FY6600)
awg_factory.add_awg(ps3000a.SHORT_NAME, ps3000a)

141 changes: 141 additions & 0 deletions sds1004x_bode/awgdrivers/ps3000a.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
'''
Created on Jun 7, 2020

@author: Mark Watson

Driver for Picoscope 3205MSO (3000a series)
'''

import ctypes
from picosdk.ps3000a import ps3000a as ps
import time
from picosdk.functions import assert_pico_ok

from base_awg import BaseAWG
import constants
from exceptions import UnknownChannelError

CHANNELS = (0, 1)
CHANNELS_ERROR = "ps3000a has only one channel."
WAVEFORM_COMMANDS = {
constants.SINE: ctypes.c_int16(0),
constants.SQUARE: ctypes.c_int16(1),
constants.PULSE: ctypes.c_int16(8), #TODO: what should this be?
constants.TRIANGLE: ctypes.c_int16(2)
}
# Output impedance of the AWG
R_IN = 600.0

class ps3000a(BaseAWG):
'''
Picoscope 3205MSO AWG driver
'''
SHORT_NAME = "ps3000a"

def __init__(self, *args):
self.connect()
self.initialize()

def connect(self):
# Gives the device a handle
self.chandle = ctypes.c_int16()

# Opens the device/s
status = {}
status["openunit"] = ps.ps3000aOpenUnit(ctypes.byref(self.chandle), None)

try:
assert_pico_ok(status["openunit"])
except:

# powerstate becomes the status number of openunit
powerstate = status["openunit"]

# If powerstate is the same as 282 then it will run this if statement
if powerstate == 282:
# Changes the power input to "PICO_POWER_SUPPLY_NOT_CONNECTED"
status["ChangePowerSource"] = ps.ps3000aChangePowerSource(self.chandle, 282)
# If the powerstate is the same as 286 then it will run this if statement
elif powerstate == 286:
# Changes the power input to "PICO_USB3_0_DEVICE_NON_USB3_0_PORT"
status["ChangePowerSource"] = ps.ps3000aChangePowerSource(self.chandle, 286)
else:
raise

assert_pico_ok(status["ChangePowerSource"])

def disconnect(self):
status = {}
status["close"] = ps.ps3000aCloseUnit(self.chandle)
assert_pico_ok(status["close"])

def initialize(self):
self.wavetype = ctypes.c_int16(0) #sine
self.frequency = 1; #1Hz
self.amplitude = 0.001; #0.001v
self.offsetVoltage = 0;
z = 50
self.v_out_coeff = z / (z + R_IN)
self.v_out_coeff = 1.0
self.onoff = False

def get_id(self):
return "ps3000a"

def enable_output(self, channel, on):
if channel is not None and channel not in CHANNELS:
raise UnknownChannelError(CHANNELS_ERROR)
sweepType = ctypes.c_int32(0)
triggertype = ctypes.c_int32(0)
triggerSource = ctypes.c_int32(0)
status = {}

amplitude = ctypes.c_uint32(int(round(self.amplitude*1000000/self.v_out_coeff)))
offsetVoltage = ctypes.c_int32(int(round(self.offsetVoltage*1000000/self.v_out_coeff)))
if on:
status["SetSigGenBuiltIn"] = ps.ps3000aSetSigGenBuiltIn(self.chandle, offsetVoltage, amplitude, self.wavetype, self.frequency, self.frequency, 0, 1, sweepType, 0, 0, 0, triggertype, triggerSource, 1)
assert_pico_ok(status["SetSigGenBuiltIn"])
self.onoff = True
else:
status["SetSigGenBuiltIn"] = ps.ps3000aSetSigGenBuiltIn(self.chandle, ctypes.c_int32(0), ctypes.c_uint32(0), self.wavetype, self.frequency, self.frequency, 0, 1, sweepType, 0, 0, 0, triggertype, triggerSource, 1)
assert_pico_ok(status["SetSigGenBuiltIn"])
self.onoff = False

def set_frequency(self, channel, freq):
if channel is not None and channel not in CHANNELS:
raise UnknownChannelError(CHANNELS_ERROR)
self.frequency = ctypes.c_float(freq)
self.enable_output(channel,self.onoff)

def set_phase(self, phase):
pass

def set_wave_type(self, channel, wave_type):
if channel is not None and channel not in CHANNELS:
raise UnknownChannelError(CHANNELS_ERROR)
self.wavetype = WAVEFORM_COMMANDS[wave_type]
self.enable_output(channel,self.onoff)

def set_amplitue(self, channel, amplitude): #BSWV specifies this in pk-pk
if channel is not None and channel not in CHANNELS:
raise UnknownChannelError(CHANNELS_ERROR)
self.amplitude = amplitude
self.enable_output(channel,self.onoff)

def set_offset(self, channel, offset):
if channel is not None and channel not in CHANNELS:
raise UnknownChannelError(CHANNELS_ERROR)
self.offsetVoltage = offset
self.enable_output(channel,self.onoff)

def set_load_impedance(self, channel, z):
if channel is not None and channel not in CHANNELS:
raise UnknownChannelError(CHANNELS_ERROR)
if z == constants.HI_Z:
v_out_coeff = 1
else:
v_out_coeff = z / (z + R_IN)
self.v_out_coeff = v_out_coeff
self.enable_output(channel,self.onoff)
pass