Skip to content

Commit a0c09a0

Browse files
authored
Merge pull request #620 from SaikiranGudla/ad353xr_support
Add support for AD353xr
2 parents 8cc0bb6 + f9ce56d commit a0c09a0

File tree

9 files changed

+447
-0
lines changed

9 files changed

+447
-0
lines changed

adi/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# SPDX short identifier: ADIBSD
44

55
from adi.ad2s1210 import ad2s1210
6+
from adi.ad353xr import ad353xr
67
from adi.ad405x import ad405x
78
from adi.ad469x import ad469x
89
from adi.ad579x import ad579x

adi/ad353xr.py

+269
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
# Copyright (C) 2025 Analog Devices, Inc.
2+
#
3+
# SPDX short identifier: ADIBSD
4+
5+
from adi.attribute import attribute
6+
from adi.context_manager import context_manager
7+
from adi.rx_tx import tx
8+
9+
10+
class ad353xr(tx, context_manager):
11+
""" AD353xr DAC """
12+
13+
_complex_data = False
14+
channel = [] # type: ignore
15+
_device_name = ""
16+
17+
def __init__(self, uri="", device_name=""):
18+
"""Constructor for AD353xr class."""
19+
context_manager.__init__(self, uri, self._device_name)
20+
21+
compatible_parts = ["ad3530r"]
22+
23+
self._ctrl = None
24+
25+
if not device_name:
26+
device_name = compatible_parts[0]
27+
else:
28+
if device_name not in compatible_parts:
29+
raise Exception(
30+
f"Not a compatible device: {device_name}. Supported device names "
31+
f"are: {','.join(compatible_parts)}"
32+
)
33+
34+
# Select the device matching device_name as working device
35+
for device in self._ctx.devices:
36+
if device.name == device_name:
37+
self._ctrl = device
38+
self._txdac = device
39+
break
40+
41+
if not self._ctrl:
42+
raise Exception("Error in selecting matching device")
43+
44+
if not self._txdac:
45+
raise Exception("Error in selecting matching device")
46+
47+
self._output_bits = []
48+
for ch in self._ctrl.channels:
49+
name = ch.id
50+
self._output_bits.append(ch.data_format.bits)
51+
self._tx_channel_names.append(name)
52+
self.channel.append(self._channel(self._ctrl, name))
53+
setattr(self, name, self._channel(self._ctrl, name))
54+
55+
tx.__init__(self)
56+
57+
@property
58+
def output_bits(self):
59+
"""AD353xr channel-wise number of output bits list"""
60+
return self._output_bits
61+
62+
### Add device attributes here ###
63+
64+
@property
65+
def sampling_frequency(self):
66+
"""AD353xr sampling frequency config"""
67+
return self._get_iio_dev_attr_str("sampling_frequency")
68+
69+
@sampling_frequency.setter
70+
def sampling_frequency(self, value):
71+
self._set_iio_dev_attr_str("sampling_frequency", value)
72+
73+
@property
74+
def all_ch_operating_mode_avail(self):
75+
"""AD353xr all channels operating mode available"""
76+
return self._get_iio_dev_attr_str("all_ch_operating_mode_available")
77+
78+
@property
79+
def all_ch_operating_mode(self):
80+
"""AD353xr all channels operating mode config"""
81+
return self._get_iio_dev_attr_str("all_ch_operating_mode")
82+
83+
@all_ch_operating_mode.setter
84+
def all_ch_operating_mode(self, value):
85+
if value in self.all_ch_operating_mode_avail:
86+
self._set_iio_dev_attr_str("all_ch_operating_mode", value)
87+
else:
88+
raise ValueError(
89+
"Error: Operating mode not supported \nUse one of: "
90+
+ str(self.all_ch_operating_mode_avail)
91+
)
92+
93+
@property
94+
def all_ch_input_registers(self):
95+
"""AD353xr all input registers config"""
96+
return self._get_iio_dev_attr_str("all_ch_input_registers")
97+
98+
@all_ch_input_registers.setter
99+
def all_ch_input_registers(self, value):
100+
self._set_iio_dev_attr_str("all_ch_input_registers", value)
101+
102+
@property
103+
def all_ch_raw(self):
104+
"""AD353xr all dac registers config"""
105+
return self._get_iio_dev_attr_str("all_ch_raw")
106+
107+
@all_ch_raw.setter
108+
def all_ch_raw(self, value):
109+
self._set_iio_dev_attr_str("all_ch_raw", value)
110+
111+
@property
112+
def reference_select_available(self):
113+
"""AD353xr reference voltage available"""
114+
return self._get_iio_dev_attr_str("reference_select_available")
115+
116+
@property
117+
def reference_select(self):
118+
"""AD353xr reference voltage config"""
119+
return self._get_iio_dev_attr_str("reference_select")
120+
121+
@reference_select.setter
122+
def reference_select(self, value):
123+
if value in self.reference_select_available:
124+
self._set_iio_dev_attr_str("reference_select", value)
125+
else:
126+
raise ValueError(
127+
"Error: Reference select not supported \nUse one of: "
128+
+ str(self.reference_select_available)
129+
)
130+
131+
@property
132+
def sw_ldac_trigger_avail(self):
133+
"""AD353xr sw_ldac_trigger available"""
134+
return self._get_iio_dev_attr_str("sw_ldac_trigger_available")
135+
136+
@property
137+
def sw_ldac_trigger(self):
138+
"""AD353xr software ldac trigger config"""
139+
return self._get_iio_dev_attr_str("sw_ldac_trigger")
140+
141+
@sw_ldac_trigger.setter
142+
def sw_ldac_trigger(self, value):
143+
if value in self.sw_ldac_trigger_avail:
144+
self._set_iio_dev_attr_str("sw_ldac_trigger", value)
145+
else:
146+
raise ValueError(
147+
"Error: Trigger value not supported \nUse one of: "
148+
+ str(self.sw_ldac_trigger_avail)
149+
)
150+
151+
@property
152+
def hw_ldac_trigger_avail(self):
153+
"""AD353xr hw_ldac_trigger available"""
154+
return self._get_iio_dev_attr_str("hw_ldac_trigger_available")
155+
156+
@property
157+
def hw_ldac_trigger(self):
158+
"""AD353xr hardware ldac trigger config"""
159+
return self._get_iio_dev_attr_str("hw_ldac_trigger")
160+
161+
@hw_ldac_trigger.setter
162+
def hw_ldac_trigger(self, value):
163+
if value in self.hw_ldac_trigger_avail:
164+
self._set_iio_dev_attr_str("hw_ldac_trigger", value)
165+
else:
166+
raise ValueError(
167+
"Error: Trigger value not supported \nUse one of: "
168+
+ str(self.hw_ldac_trigger_avail)
169+
)
170+
171+
@property
172+
def range_avail(self):
173+
"""AD353xr range available"""
174+
return self._get_iio_dev_attr_str("range_available")
175+
176+
@property
177+
def range(self):
178+
"""AD353xr range config"""
179+
return self._get_iio_dev_attr_str("range")
180+
181+
@range.setter
182+
def range(self, value):
183+
if value in self.range_avail:
184+
self._set_iio_dev_attr_str("range", value)
185+
else:
186+
raise ValueError(
187+
"Error: Range option not supported \nUse one of: "
188+
+ str(self.range_avail)
189+
)
190+
191+
@property
192+
def mux_out_select_avail(self):
193+
"""AD353xr mux_out_select available"""
194+
return self._get_iio_dev_attr_str("mux_out_select_available")
195+
196+
@property
197+
def mux_out_select(self):
198+
"""AD353xr mux out select"""
199+
return self._get_iio_dev_attr_str("mux_out_select")
200+
201+
@mux_out_select.setter
202+
def mux_out_select(self, value):
203+
if value in self.mux_out_select_avail:
204+
self._set_iio_dev_attr_str("mux_out_select", value)
205+
else:
206+
raise ValueError(
207+
"Error: Mux output option not supported \nUse one of: "
208+
+ str(self.mux_out_select_avail)
209+
)
210+
211+
############################################################################
212+
213+
class _channel(attribute):
214+
"""AD353xr channel"""
215+
216+
def __init__(self, ctrl, channel_name):
217+
self.name = channel_name
218+
self._ctrl = ctrl
219+
220+
### Add channel attributes here ###
221+
@property
222+
def input_register(self):
223+
"""AD353xr channel input register value"""
224+
return self._get_iio_attr(self.name, "input_register", True)
225+
226+
@input_register.setter
227+
def input_register(self, value):
228+
self._set_iio_attr(self.name, "input_register", True, str(int(value)))
229+
230+
@property
231+
def raw(self):
232+
"""AD353xr channel raw value"""
233+
return self._get_iio_attr(self.name, "raw", True)
234+
235+
@raw.setter
236+
def raw(self, value):
237+
self._set_iio_attr(self.name, "raw", True, str(int(value)))
238+
239+
@property
240+
def offset(self):
241+
"""AD353xr channel offset"""
242+
return self._get_iio_attr(self.name, "offset", True)
243+
244+
@property
245+
def scale(self):
246+
"""AD353xr channel scale"""
247+
return self._get_iio_attr(self.name, "scale", True)
248+
249+
@property
250+
def operating_mode_avail(self):
251+
"""AD353xr channel operating mode settings"""
252+
return self._get_iio_attr_str(self.name, "operating_mode_available", True)
253+
254+
@property
255+
def operating_mode(self):
256+
"""AD353xr channel operating mode"""
257+
return self._get_iio_attr_str(self.name, "operating_mode", True)
258+
259+
@operating_mode.setter
260+
def operating_mode(self, value):
261+
if value in self.operating_mode_avail:
262+
self._set_iio_attr(self.name, "operating_mode", True, value)
263+
else:
264+
raise ValueError(
265+
"Error: Operating mode not supported \nUse one of: "
266+
+ str(self.operating_mode_avail)
267+
)
268+
269+
#####################################################################

doc/source/devices/adi.ad353xr.rst

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
ad353xr
2+
=================
3+
4+
.. automodule:: adi.ad353xr
5+
:members:
6+
:undoc-members:
7+
:show-inheritance:

doc/source/devices/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Supported Devices
99

1010
adi.QuadMxFE_multi
1111
adi.ad2s1210
12+
adi.ad353xr
1213
adi.ad3552r
1314
adi.ad3552r_hs
1415
adi.ad4020

examples/ad353xr_example.py

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Copyright (C) 2025 Analog Devices, Inc.
2+
#
3+
# All rights reserved.
4+
#
5+
# Redistribution and use in source and binary forms, with or without modification,
6+
# are permitted provided that the following conditions are met:
7+
# - Redistributions of source code must retain the above copyright
8+
# notice, this list of conditions and the following disclaimer.
9+
# - Redistributions in binary form must reproduce the above copyright
10+
# notice, this list of conditions and the following disclaimer in
11+
# the documentation and/or other materials provided with the
12+
# distribution.
13+
# - Neither the name of Analog Devices, Inc. nor the names of its
14+
# contributors may be used to endorse or promote products derived
15+
# from this software without specific prior written permission.
16+
# - The use of this software may or may not infringe the patent rights
17+
# of one or more patent holders. This license does not release you
18+
# from the requirement that you obtain separate licenses from these
19+
# patent holders to use this software.
20+
# - Use of the software either in source or binary form, must be run
21+
# on or directly connected to an Analog Devices Inc. component.
22+
#
23+
# THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
24+
# INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
25+
# PARTICULAR PURPOSE ARE DISCLAIMED.
26+
#
27+
# IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, INTELLECTUAL PROPERTY
29+
# RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30+
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31+
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
32+
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33+
34+
import argparse
35+
36+
from adi.ad353xr import ad353xr
37+
38+
39+
def main():
40+
# Set up argument parser
41+
parser = argparse.ArgumentParser(description="AD353XR Example Script")
42+
parser.add_argument(
43+
"--uri",
44+
type=str,
45+
help="The URI for the AD353XR device",
46+
default="serial:COM7,230400,8n1",
47+
)
48+
parser.add_argument(
49+
"--device_name",
50+
type=str,
51+
choices=["ad3530r"],
52+
help="The device name (Supported devices are ad3530r)",
53+
default="ad3530r",
54+
)
55+
56+
# Parse arguments
57+
args = parser.parse_args()
58+
59+
# Set up AD3530R
60+
ad3530r_dev = ad353xr(uri=args.uri, device_name=args.device_name)
61+
ad3530r_dev.all_ch_operating_mode = "normal_operation"
62+
63+
ad3530r_dev.reference_select = "internal_ref"
64+
65+
# Configure channel 0
66+
chn_num = 0
67+
ad3530r_chan = ad3530r_dev.channel[chn_num]
68+
69+
# Update dac output for channel 0 instantaneously using the 'raw' attribute
70+
ad3530r_chan.raw = 25000
71+
72+
# Update dac output for channel 0 using software LDAC operation
73+
ad3530r_chan.input_register = 5000
74+
ad3530r_dev.sw_ldac_trigger = "ldac_trigger"
75+
76+
# Update dac output of channel 0 using hardware LDAC operation
77+
ad3530r_chan.input_register = 40000
78+
ad3530r_dev.hw_ldac_trigger = "ldac_trigger"
79+
80+
# Set mux value to "vout0" to monitor vout0 value on the mux_out pin
81+
ad3530r_dev.mux_out_select = "VOUT0"
82+
83+
# Set 0 to 2Vref as output range
84+
ad3530r_dev.range = "0_to_2VREF"
85+
86+
# Determine output voltage using scale and offset
87+
raw = int(ad3530r_chan.raw)
88+
scale = float(ad3530r_chan.scale)
89+
offset = int(ad3530r_chan.offset)
90+
print(f"Channel{chn_num} voltage in Volts: {(raw + offset) * scale/1000}")
91+
92+
93+
if __name__ == "__main__":
94+
main()

supported_parts.md

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
### Currently supported hardware
1313
- AD2S1210
14+
- AD353XR (AD3530R)
1415
- AD3552r (AD3542r)
1516
- AD3552r-hs (AD3551r, AD3541r, AD3542r)
1617
- AD4000 (AD4004, AD4008)

0 commit comments

Comments
 (0)