diff --git a/adi/__init__.py b/adi/__init__.py index 341ba0e73..779ca88dc 100644 --- a/adi/__init__.py +++ b/adi/__init__.py @@ -36,6 +36,7 @@ from adi.ad7689 import ad7689 from adi.ad7746 import ad7746 from adi.ad7768 import ad7768, ad7768_4 +from adi.ad7768_1 import ad7768_1 from adi.ad7799 import ad7799 from adi.ad9081 import ad9081 from adi.ad9081_mc import QuadMxFE, ad9081_mc diff --git a/adi/ad7768_1.py b/adi/ad7768_1.py new file mode 100644 index 000000000..a38f35fc7 --- /dev/null +++ b/adi/ad7768_1.py @@ -0,0 +1,117 @@ +# Copyright (C) 2025 Analog Devices, Inc. +# +# SPDX short identifier: ADIBSD +from decimal import Decimal + +import numpy as np + +from adi.attribute import attribute +from adi.context_manager import context_manager +from adi.rx_tx import rx + + +class ad7768_1(rx, context_manager): + + """ AD7768-1 1-channel, Dynamic Signal Analysis Sigma-Delta ADC """ + + _device_name = " " + _rx_data_type = np.int32 + + def __init__(self, uri="ip:analog.local", device_name=""): + """Initialize.""" + context_manager.__init__(self, uri, self._device_name) + + compatible_parts = ["ad7768-1", "adaq7767-1", "adaq7768-1", "adaq7769-1"] + + self._ctrl = None + + if not device_name: + device_name = compatible_parts[0] + else: + if device_name not in compatible_parts: + raise Exception(f"Not a compatible device: {device_name}") + + # Select the device matching device_name as working device + for device in self._ctx.devices: + if device.name == device_name: + self._ctrl = device + self._rxadc = device + break + + if not self._ctrl: + raise Exception("Error in selecting matching device") + + if not self._rxadc: + raise Exception("Error in selecting matching device") + + self._rx_channel_names = [] + self.channel = [] + for ch in self._ctrl.channels: + name = ch._id + self._rx_channel_names.append(name) + self.channel.append(self._channel(self._ctrl, name)) + + rx.__init__(self) + + @property + def sampling_frequency_available(self): + """Get available sampling frequencies.""" + return self._get_iio_dev_attr("sampling_frequency_available") + + @property + def sampling_frequency(self): + """Get sampling frequency.""" + return self._get_iio_dev_attr("sampling_frequency") + + @sampling_frequency.setter + def sampling_frequency(self, rate): + """Set sampling frequency.""" + if rate in self.sampling_frequency_available: + self._set_iio_dev_attr("sampling_frequency", rate) + else: + raise ValueError( + "Error: Sampling frequency not supported \nUse one of: " + + str(self.sampling_frequency_available) + ) + + @property + def common_mode_voltage_available(self): + """Get common mode voltage available.""" + return self._get_iio_dev_attr_str("common_mode_voltage_available") + + @property + def common_mode_voltage(self): + """Get common mode voltage.""" + return self._get_iio_dev_attr_str("common_mode_voltage") + + @common_mode_voltage.setter + def common_mode_voltage(self, rate): + """Set sampling frequency.""" + if rate in self.common_mode_voltage_available: + self._set_iio_dev_attr_str("common_mode_voltage", rate) + else: + raise ValueError( + "Error: Common mode voltage not supported \nUse one of: " + + str(self.common_mode_voltage_available) + ) + + class _channel(attribute): + """AD7768-1 channel""" + + def __init__(self, ctrl, channel_name): + self.name = channel_name + self._ctrl = ctrl + + @property + def value(self): + """AD7768-1 channel raw value""" + return self._get_iio_attr(self.name, "raw", False) + + @property + def scale(self): + """AD7768-1 channel scale.""" + return float(self._get_iio_attr_str(self.name, "scale", False)) + + @scale.setter + def scale(self, value): + self._set_iio_attr(self.name, "scale", False, str(Decimal(value).real)) diff --git a/doc/source/devices/adi.ad7768_1.rst b/doc/source/devices/adi.ad7768_1.rst new file mode 100644 index 000000000..4500bd392 --- /dev/null +++ b/doc/source/devices/adi.ad7768_1.rst @@ -0,0 +1,7 @@ +ad7768_1 +================= + +.. automodule:: adi.ad7768_1 + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/source/devices/index.rst b/doc/source/devices/index.rst index 4f0a9f790..e758c45e9 100644 --- a/doc/source/devices/index.rst +++ b/doc/source/devices/index.rst @@ -39,6 +39,7 @@ Supported Devices adi.ad7689 adi.ad7746 adi.ad7768 + adi.ad7768_1 adi.ad777x adi.ad7799 adi.ad9081 diff --git a/examples/ad7768_1_example.py b/examples/ad7768_1_example.py new file mode 100644 index 000000000..698425634 --- /dev/null +++ b/examples/ad7768_1_example.py @@ -0,0 +1,80 @@ +# Copyright (C) 2023 Analog Devices, Inc. +# +# SPDX short identifier: ADIBSD + +import sys +from time import sleep + +import matplotlib.pyplot as plt + +import adi + + +def display_settings(sampling_frequency, rx_enabled_channels, common_mode_voltage): + # def display_settings(sampling_frequency, rx_enabled_channels): + print("Sampling Frequency: ", sampling_frequency) + print("Enabled Channels: ", rx_enabled_channels) + print("Common mode voltage: ", common_mode_voltage) + + +# Optionally pass URI as command line argument, + +my_uri = sys.argv[1] if len(sys.argv) >= 2 else "ip:analog.local" +part_name = sys.argv[2].lower() if len(sys.argv) >= 3 else "adaq7768-1" + +print(f"URI: {my_uri}") +print(f"Selected device: {part_name}") + +# Initialize ADC depending on device name +if part_name == "ad7768-1": + my_adc = adi.ad7768_1(uri=my_uri) +elif part_name == "adaq7767-1": + my_adc = adi.adaq7767_1(uri=my_uri) +elif part_name == "adaq7768-1": + my_adc = adi.adaq7768_1(uri=my_uri) +elif part_name == "adaq7769-1": + my_adc = adi.adaq7769_1(uri=my_uri) +else: + raise ValueError(f"Unsupported device: {part_name}") + +my_adc = adi.ad7768_1(uri=my_uri) +my_adc.rx_buffer_size = 1024 + +my_adc.sampling_frequency = 8000 # Set Sample Rate + +my_adc.rx_output_type = "SI" # Choose output format: "SI" or "RAW" + +my_adc.common_mode_voltage = "(AVDD1-AVSS)/2" # mV # Set common mode voltage: (AVDD1-AVSS)/2 2V5 2V05 1V9 1V65 1V1 0V9 OFF + +# Verify settings: +display_settings( + my_adc.sampling_frequency, my_adc.rx_enabled_channels, my_adc.common_mode_voltage, +) + +# --- Live Plot Setup --- +plt.ion() # turn on interactive mode +fig, ax = plt.subplots(figsize=(10, 6)) # reasonable size for most monitors +(line,) = ax.plot([], [], label="voltage") +ax.set_xlabel("Data Point") +ax.set_ylabel("Millivolts" if my_adc.rx_output_type == "SI" else "ADC counts") +ax.legend(loc="upper right") +plt.show() + +# --- Live Update Loop --- +try: + while True: + data = my_adc.rx() + data = data[1:] # skip first sample + + line.set_xdata(range(len(data))) + line.set_ydata(data) + + ax.relim() + ax.autoscale_view() + + plt.pause(0.01) + +except KeyboardInterrupt: + print("Stopped by user.") + +del my_adc diff --git a/supported_parts.md b/supported_parts.md index 4138edacf..48f33daa1 100644 --- a/supported_parts.md +++ b/supported_parts.md @@ -96,6 +96,7 @@ - AD7291 - AD7490 - AD7768 +- AD7768-1 - AD7768-4 - AD7770 - AD7771 @@ -127,6 +128,9 @@ - ADAQ4216 - ADAQ4220 - ADAQ4224 +- ADAQ7767-1 +- ADAQ7768-1 +- ADAQ7769-1 - ADAQ8092 - ADAR1000 - ADF4030 diff --git a/test/emu/devices/ad7768-1.xml b/test/emu/devices/ad7768-1.xml new file mode 100644 index 000000000..fd25b0cc4 --- /dev/null +++ b/test/emu/devices/ad7768-1.xml @@ -0,0 +1 @@ +]> diff --git a/test/emu/devices/adaq7767-1.xml b/test/emu/devices/adaq7767-1.xml new file mode 100644 index 000000000..557bcbec3 --- /dev/null +++ b/test/emu/devices/adaq7767-1.xml @@ -0,0 +1 @@ +]> diff --git a/test/emu/devices/adaq7768-1.xml b/test/emu/devices/adaq7768-1.xml new file mode 100644 index 000000000..0e17ae7c0 --- /dev/null +++ b/test/emu/devices/adaq7768-1.xml @@ -0,0 +1 @@ +]> diff --git a/test/emu/devices/adaq7769-1.xml b/test/emu/devices/adaq7769-1.xml new file mode 100644 index 000000000..e4a16ef9c --- /dev/null +++ b/test/emu/devices/adaq7769-1.xml @@ -0,0 +1 @@ +]> diff --git a/test/emu/hardware_map.yml b/test/emu/hardware_map.yml index 416646088..6ecb7ec9b 100644 --- a/test/emu/hardware_map.yml +++ b/test/emu/hardware_map.yml @@ -582,6 +582,42 @@ ad7768: - data_devices: - iio:device0 +ad7768-1: + - ad7768-1 + - pyadi_iio_class_support: + - ad7768_1 + - emulate: + - filename: ad7768-1.xml + - data_devices: + - iio:device0 + +adaq7767-1: + - ad7768-1 + - pyadi_iio_class_support: + - ad7768-1 + - emulate: + - filename: adaq7767-1.xml + - data_devices: + - iio:device0 + +adaq7768-1: + - ad7768-1 + - pyadi_iio_class_support: + - ad7768-1 + - emulate: + - filename: adaq7768-1.xml + - data_devices: + - iio:device0 + +adaq7769-1: + - ad7768-1 + - pyadi_iio_class_support: + - ad7768-1 + - emulate: + - filename: adaq7769-1.xml + - data_devices: + - iio:device0 + ad7768-4: - ad7768-4 - pyadi_iio_class_support: diff --git a/test/test_ad7768_1.py b/test/test_ad7768_1.py new file mode 100644 index 000000000..b2d226a1b --- /dev/null +++ b/test/test_ad7768_1.py @@ -0,0 +1,52 @@ +import pytest + +import adi + +hardware = ["ad7768-1", "adaq7767-1", "adaq7768-1", "adaq7769-1"] +classname = "adi.ad7768_1" +######################################### +@pytest.mark.iio_hardware(hardware) +@pytest.mark.parametrize("classname", [(classname)]) +@pytest.mark.parametrize( + "attr, val", + [ + ( + "sampling_frequency", + [ + 8000, + 16000, + 32000, + 64000, + 128000, + 256000, + ], # End on a rate compatible with all power modes + ), + ( + "common_mode_voltage", + ["(AVDD1-AVSS)/2", "2V5", "2V05", "1V9", "1V65", "1V1", "0V9", "OFF"], + ), + ], +) +def test_ad7768_1_attr(test_attribute_multiple_values, iio_uri, classname, attr, val): + test_attribute_multiple_values(iio_uri, classname, attr, val, 0) + + +######################################### +@pytest.mark.iio_hardware(hardware, True) +@pytest.mark.parametrize("classname", [(classname)]) +@pytest.mark.parametrize("channel", [0]) +@pytest.mark.parametrize( + "param_set", + [ + dict(common_mode_voltage="(AVDD1-AVSS)/2"), + dict(common_mode_voltage="2V5"), + dict(common_mode_voltage="2V05"), + dict(common_mode_voltage="1V9"), + dict(common_mode_voltage="1V65"), + dict(common_mode_voltage="1V1"), + dict(common_mode_voltage="0V9"), + dict(common_mode_voltage="OFF"), + ], +) +def test_ad7768_1_rx_data(test_dma_rx, iio_uri, classname, channel, param_set): + test_dma_rx(iio_uri, classname, channel, param_set=param_set)