Skip to content

Commit e0fe6ee

Browse files
committed
Add dynamic channels to constructor, and add checks in add_device to enforce it.
This will allow the maximum clock rate to be determined.
1 parent fe811ef commit e0fe6ee

File tree

1 file changed

+39
-10
lines changed

1 file changed

+39
-10
lines changed

labscript_devices/AD9959DDSSweeper/labscript_devices.py

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class AD9959DDSSweeper(IntermediateDevice):
5454
}
5555
)
5656

57-
def __init__(self, name, parent_device, com_port,
57+
def __init__(self, name, parent_device, com_port, dynamic_channels,
5858
pico_board='pico1', sweep_mode=0,
5959
ref_clock_external=0, ref_clock_frequency=125e6, pll_mult=4, **kwargs):
6060
'''Labscript device class for AD9959 eval board controlled by a Raspberry Pi Pico running the DDS Sweeper firmware (https://github.com/QTC-UMD/dds-sweeper).
@@ -67,6 +67,8 @@ def __init__(self, name, parent_device, com_port,
6767
Pseudoclock clockline used to clock DDS parameter changes.
6868
com_port (str): COM port assigned to the AD9959DDSSweeper by the OS.
6969
On Windows, takes the form of `COMd` where `d` is an integer.
70+
dynamic_channels (int): number of dynamic DDS channels that will be added.
71+
This must be specified in the constructor so that update rates can be calculated correctly.
7072
pico_board (str): The version of pico board used, pico1 or pico2.
7173
sweep_mode (int):
7274
The DDS Sweeper firmware can set the DDS outputs in either fixed steps or sweeps of the amplitude, frequency, or phase.
@@ -75,7 +77,6 @@ def __init__(self, name, parent_device, com_port,
7577
ref_clock_frequency (float): Frequency of the reference clock. If ref_clock_external is 0, the Pi Pico system clock will be set to this frequency. If the PLL is used, ref_clock_frequency * pll_mult must be between 100 MHz and 500 MHz. If the PLL is not used, ref_clock_frequency must be less than 500 MHz.
7678
pll_mult: the AD9959 has a PLL to multiply the reference clock frequency. Allowed values are 1 or 4-20.
7779
'''
78-
IntermediateDevice.__init__(self, name, parent_device, **kwargs)
7980
self.BLACS_connection = '%s' % com_port
8081

8182
if pico_board in self.allowed_boards:
@@ -97,27 +98,55 @@ def __init__(self, name, parent_device, com_port,
9798
self.dds_clock = ref_clock_frequency * pll_mult
9899
self.clk_scale = 2**32 / self.dds_clock
99100

101+
# Store number of dynamic channels
102+
if dynamic_channels > 4:
103+
raise ValueError('AD9959DDSSweeper only supports up to 4 total channels, dynamic channels must be 4 or less.')
104+
self.dynamic_channels = dynamic_channels
105+
106+
IntermediateDevice.__init__(self, name, parent_device, **kwargs)
107+
100108
@property
101109
def clock_limit(self):
102110
'''Dynamically computs clock limit based off of number of dynamic
103111
channels and reference clock frequency.'''
104-
num_dyn_chans = sum(isinstance(child, DDS) for child in self.child_devices)
105-
if num_dyn_chans == 0:
106-
# Set to worst case
107-
# 4 channels, step mode, default 125 MHz pico ref clk
108-
return 100000
112+
if self.dynamic_channels == 0:
113+
# No clock limit
114+
return None
109115

110116
if self.sweep_mode > 0:
111117
mode = 'sweeps'
112118
else:
113119
mode = 'steps'
114120
try:
115-
cycles_per_instruction = self.cycles_per_instruction_map[mode][num_dyn_chans - 1]
121+
cycles_per_instruction = self.cycles_per_instruction_map[mode][self.dynamic_channels - 1]
116122
except (KeyError, IndexError):
117-
raise LabscriptError(f'Unsupported mode or number of channels: {mode}, {num_dyn_chans}')
123+
raise LabscriptError(f'Unsupported mode or number of channels: {mode}, {self.dynamic_channels}')
118124

119125
return self.ref_clock_frequency / cycles_per_instruction
120-
126+
127+
def add_device(self, device):
128+
"""Confirms channel specified is valid before adding
129+
130+
Validity checks include channel name and static/dynamic status.
131+
Dynamic channels must be specified before static channels.
132+
Args:
133+
device(): Device to attach. Must be a DDS or a StaticDDS.
134+
Allowed connections are a string of the form `channel X`.
135+
"""
136+
conn = device.connection
137+
chan = int(conn.split('channel ')[-1])
138+
139+
if isinstance(device, StaticDDS):
140+
if chan < self.dynamic_channels:
141+
raise LabscriptError(f'Channel {chan} configured as dynamic channel, can not create StaticDDS.')
142+
elif chan >= 4:
143+
raise LabscriptError('AD9959DDSSweeper only supports 4 channels')
144+
elif isinstance(device, DDS):
145+
if chan >= self.dynamic_channels:
146+
raise LabscriptError(f'Channel {chan} not configured as dynamic channel, can not create DDS.')
147+
148+
super().add_device(device)
149+
121150
def get_default_unit_conversion_classes(self, device):
122151
"""Child devices call this during their __init__ (with themselves
123152
as the argument) to check if there are certain unit calibration

0 commit comments

Comments
 (0)