From 76e26b55a777d8187243fcc8d4619ef6d628f596 Mon Sep 17 00:00:00 2001 From: MPhalke Date: Thu, 20 Apr 2023 11:00:36 +0530 Subject: [PATCH] ad77681 pyadi-iio support Implemented ad7768-1 pyadi-iio device driver class and example script Signed-off-by: MPhalke --- adi/__init__.py | 1 + adi/ad7768_1.py | 140 ++++++++++++++++++++++++++++ doc/source/devices/adi.ad7768_1.rst | 7 ++ doc/source/devices/index.rst | 1 + examples/ad7768_1_example.py | 81 ++++++++++++++++ supported_parts.md | 1 + test/emu/devices/ad7768_1.xml | 1 + test/emu/hardware_map.yml | 9 ++ test/test_ad7768_1.py | 11 +++ 9 files changed, 252 insertions(+) create mode 100644 adi/ad7768_1.py create mode 100644 doc/source/devices/adi.ad7768_1.rst create mode 100644 examples/ad7768_1_example.py create mode 100644 test/emu/devices/ad7768_1.xml create mode 100644 test/test_ad7768_1.py diff --git a/adi/__init__.py b/adi/__init__.py index 0cb356152..318826343 100644 --- a/adi/__init__.py +++ b/adi/__init__.py @@ -21,6 +21,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..15f4db596 --- /dev/null +++ b/adi/ad7768_1.py @@ -0,0 +1,140 @@ +# Copyright (C) 2020-2023 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 ADC """ + + _complex_data = False + channel = [] # type: ignore + _device_name = "" + + def __init__(self, uri="", device_name=""): + """Constructor for ad7768_1 class.""" + context_manager.__init__(self, uri, self._device_name) + + compatible_parts = ["ad7768-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") + + 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(self): + """Get sampling frequency.""" + return self._get_iio_dev_attr("sampling_frequency") + + @sampling_frequency.setter + def sampling_frequency(self, rate): + """Set sampling frequency.""" + self._set_iio_dev_attr("sampling_frequency", rate) + + class _channel(attribute): + + """ ad7768-1 channel """ + + def __init__(self, ctrl, channel_name): + self.name = channel_name + self._ctrl = ctrl + + @property + def raw(self): + """Get channel raw value.""" + return self._get_iio_attr(self.name, "raw", False) + + @property + def scale(self): + """Get channel scale.""" + return self._get_iio_attr(self.name, "scale", False) + + @scale.setter + def scale(self, value): + """Set channel scale.""" + self._set_iio_attr(self.name, "scale", False, Decimal(value).real) + + @property + def offset(self): + """Get channel offset.""" + return self._get_iio_attr(self.name, "offset", False) + + @offset.setter + def offset(self, value): + """Set channel offset.""" + self._set_iio_attr(self.name, "offset", False, value) + + @property + def filter_low_pass_3db_frequency_avail(self): + """Get available low pass filter 3db frequencies.""" + return self._get_iio_attr_str( + self.name, "filter_low_pass_3db_frequency_available", False + ) + + @property + def filter_low_pass_3db_frequency(self): + """Get low pass filter 3db frequency.""" + return self._get_iio_attr_str( + self.name, "filter_low_pass_3db_frequency", False + ) + + @filter_low_pass_3db_frequency.setter + def filter_low_pass_3db_frequency(self, freq): + """Set low pass filter 3db frequency.""" + if freq in self.filter_low_pass_3db_frequency_avail: + self._set_iio_attr( + self.name, "filter_low_pass_3db_frequency", False, freq + ) + else: + raise ValueError( + "Error: Low pass filter 3db frequency not supported \nUse one of: " + + str(self.filter_low_pass_3db_frequency_avail) + ) + + def to_volts(self, index, val): + """Converts raw value to SI.""" + _scale = self.channel[index].scale + + ret = None + + if isinstance(val, np.int16): + ret = val * _scale + + if isinstance(val, np.ndarray): + ret = [x * _scale for x in val] + + if ret is None: + raise Exception("Error in converting to actual voltage") + + return ret 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 51ca275ea..1ed40f7a8 100644 --- a/doc/source/devices/index.rst +++ b/doc/source/devices/index.rst @@ -26,6 +26,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..279a88acb --- /dev/null +++ b/examples/ad7768_1_example.py @@ -0,0 +1,81 @@ +# Copyright (C) 2023 Analog Devices, Inc. +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# - Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# - Neither the name of Analog Devices, Inc. nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# - The use of this software may or may not infringe the patent rights +# of one or more patent holders. This license does not release you +# from the requirement that you obtain separate licenses from these +# patent holders to use this software. +# - Use of the software either in source or binary form, must be run +# on or directly connected to an Analog Devices Inc. component. +# +# THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. +# +# IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, INTELLECTUAL PROPERTY +# RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import sys +from time import sleep + +import matplotlib.pyplot as plt +from adi import ad7768_1 + +# Optionally pass URI as command line argument, +# else use default ip:analog.local +my_uri = sys.argv[1] if len(sys.argv) >= 2 else "ip:analog.local" +print("uri: " + str(my_uri)) + +my_adc = ad7768_1(uri=my_uri) +my_adc.rx_buffer_size = 1024 + +# Set Sample Rate. Options are 1ksps to 256ksps, 1k* power of 2. +# Note that sample rate and power mode are not orthogonal - refer +# to datasheet. +my_adc.sampling_frequency = 8000 + +# Choose output format: +# my_adc.rx_output_type = "raw" +my_adc.rx_output_type = "SI" + +# Verify settings: +print("Sampling Frequency: ", my_adc.sampling_frequency) +print("Enabled Channels: ", my_adc.rx_enabled_channels) + + +plt.clf() +sleep(0.5) +data = my_adc.rx() +for ch in my_adc.rx_enabled_channels: + plt.plot(range(0, len(data[0])), data[ch], label="voltage" + str(ch)) +plt.xlabel("Data Point") +if my_adc.rx_output_type == "SI": + plt.ylabel("Millivolts") +else: + plt.ylabel("ADC counts") +plt.legend( + bbox_to_anchor=(0.0, 1.02, 1.0, 0.102), + loc="lower left", + ncol=4, + mode="expand", + borderaxespad=0.0, +) +plt.pause(0.01) + +del my_adc diff --git a/supported_parts.md b/supported_parts.md index c4d430d98..c9f48645a 100644 --- a/supported_parts.md +++ b/supported_parts.md @@ -72,6 +72,7 @@ - AD7291 - AD7768 - AD7768-4 +- AD7768-1 - AD7770 - AD7771 - AD7779 diff --git a/test/emu/devices/ad7768_1.xml b/test/emu/devices/ad7768_1.xml new file mode 100644 index 000000000..9c539fdc1 --- /dev/null +++ b/test/emu/devices/ad7768_1.xml @@ -0,0 +1 @@ +]> \ No newline at end of file diff --git a/test/emu/hardware_map.yml b/test/emu/hardware_map.yml index 43841da98..3202271c6 100644 --- a/test/emu/hardware_map.yml +++ b/test/emu/hardware_map.yml @@ -342,6 +342,15 @@ ad7768-4: - data_devices: - iio:device0 +ad7768_1: + - ad7768-1 + - pyadi_iio_class_support: + - ad7768_1 + - emulate: + - filename: ad7768_1.xml + - data_devices: + - iio:device0 + ad5592r: - ad5592r - pyadi_iio_class_support: diff --git a/test/test_ad7768_1.py b/test/test_ad7768_1.py new file mode 100644 index 000000000..472dbd551 --- /dev/null +++ b/test/test_ad7768_1.py @@ -0,0 +1,11 @@ +import pytest + +hardware = ["ad7768-1"] +classname = "adi.ad7768_1" + +######################################### +@pytest.mark.iio_hardware(hardware) +@pytest.mark.parametrize("classname", [(classname)]) +@pytest.mark.parametrize("channel", [0]) +def test_ad7768_1_rx_data(test_dma_rx, iio_uri, classname, channel): + test_dma_rx(iio_uri, classname, channel)