From a09c520f4a4c58c885ce63863b11363a55303e0f Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 4 Oct 2023 15:58:30 -0500 Subject: [PATCH] adi/ad2s1210: add AD2S1210 Resolver-to-Digital Converter This adds support for the AD2S1210 Resolver-to-Digital Converter. The IIO ABI is based on work that is currently being mainlined and is not compatible with the older driver in staging. Not all features are supported yet since libiio does not support iio events. This means that the AD2S1210's fault detection and threshold configuration is not supported. The tests are passing when run on real hardware. Signed-off-by: David Lechner --- adi/__init__.py | 1 + adi/ad2s1210.py | 99 ++++++++++++++++++ doc/source/devices/adi.ad2s1210.rst | 7 ++ doc/source/devices/index.rst | 1 + supported_parts.md | 1 + test/emu/devices/ad2s1210.xml | 154 ++++++++++++++++++++++++++++ test/emu/hardware_map.yml | 10 ++ test/test_ad2s1210.py | 47 +++++++++ 8 files changed, 320 insertions(+) create mode 100644 adi/ad2s1210.py create mode 100644 doc/source/devices/adi.ad2s1210.rst create mode 100644 test/emu/devices/ad2s1210.xml create mode 100644 test/test_ad2s1210.py diff --git a/adi/__init__.py b/adi/__init__.py index 7387aabd3..db32df83a 100644 --- a/adi/__init__.py +++ b/adi/__init__.py @@ -2,6 +2,7 @@ # # SPDX short identifier: ADIBSD +from adi.ad2s1210 import ad2s1210 from adi.ad469x import ad469x from adi.ad717x import ad717x from adi.ad719x import ad719x diff --git a/adi/ad2s1210.py b/adi/ad2s1210.py new file mode 100644 index 000000000..54905b370 --- /dev/null +++ b/adi/ad2s1210.py @@ -0,0 +1,99 @@ +# Copyright (C) 2023 Analog Devices, Inc. +# +# SPDX short identifier: ADIBSD + +from adi.attribute import attribute +from adi.context_manager import context_manager +from adi.rx_tx import rx + +# TODO: add support for events when libiio gains support for it + + +class ad2s1210(rx, context_manager): + """ + AD2S1210 resolver to digital converter. + """ + + _device_name = "ad2s1210" + + def __init__(self, uri=""): + context_manager.__init__(self, uri, self._device_name) + + self._rxadc = self._ctrl = self._ctx.find_device(self._device_name) + self._rx_channel_names = [] + + for ch in self._ctrl.channels: + name = ch.id + + if name == "angl0": + self._rx_channel_names.append(name) + self.position = self._position_channel(self._ctrl, name) + elif name == "anglvel0": + self._rx_channel_names.append(name) + self.velocity = self._velocity_channel(self._ctrl, name) + + rx.__init__(self) + + @property + def excitation_frequency(self) -> int: + """ + Gets and sets the excitation frequency in Hz. + + Setting the value also does a soft reset of the device so that the + physical output is updated for the change. + """ + return self._get_iio_attr("altvoltage0", "frequency", True) + + @excitation_frequency.setter + def excitation_frequency(self, value: int) -> None: + self._set_iio_attr("altvoltage0", "frequency", True, value) + + @property + def hysteresis_enable(self) -> bool: + """ + Gets and sets the hysteresis bit in the Control register. + """ + return bool(self._get_iio_attr("angl0", "hysteresis", False)) + + @hysteresis_enable.setter + def hysteresis_enable(self, value: bool) -> None: + # This is just a boolean bit flag in the Control register but the + # IIO ABI requires us to use raw angle units so we have to look up + # the available values to find out what the raw value is for True. + # `avail` will be a list of two int values. + avail = self._get_iio_attr("angl0", "hysteresis_available", False) + self._set_iio_attr("angl0", "hysteresis", False, avail[bool(value)]) + + class _position_channel(attribute): + """AD2S1210 channel""" + + def __init__(self, ctrl, channel_name): + self.name = channel_name + self._ctrl = ctrl + + @property + def raw(self) -> int: + """AD2S1210 position channel raw value""" + return self._get_iio_attr(self.name, "raw", False) + + @property + def scale(self) -> float: + """AD2S1210 position channel scale""" + return float(self._get_iio_attr(self.name, "scale", False)) + + class _velocity_channel(attribute): + """AD2S1210 channel""" + + def __init__(self, ctrl, channel_name): + self.name = channel_name + self._ctrl = ctrl + + @property + def raw(self) -> int: + """AD2S1210 velocity channel raw value""" + return self._get_iio_attr(self.name, "raw", False) + + @property + def scale(self) -> float: + """AD2S1210 velocity channel scale""" + return float(self._get_iio_attr(self.name, "scale", False)) diff --git a/doc/source/devices/adi.ad2s1210.rst b/doc/source/devices/adi.ad2s1210.rst new file mode 100644 index 000000000..40eb69717 --- /dev/null +++ b/doc/source/devices/adi.ad2s1210.rst @@ -0,0 +1,7 @@ +ad2s1210 +================= + +.. automodule:: adi.ad2s1210 + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/source/devices/index.rst b/doc/source/devices/index.rst index 3651d95f3..79cc052fb 100644 --- a/doc/source/devices/index.rst +++ b/doc/source/devices/index.rst @@ -8,6 +8,7 @@ Supported Devices :maxdepth: 4 adi.QuadMxFE_multi + adi.ad2s1210 adi.ad4020 adi.ad4110 adi.ad4130 diff --git a/supported_parts.md b/supported_parts.md index faf881689..a451abc3d 100644 --- a/supported_parts.md +++ b/supported_parts.md @@ -10,6 +10,7 @@ [[Wiki](https://wiki.analog.com/resources/tools-software/linux-software/pyadi-iio)] ### Currently supported hardware +- AD2S1210 - AD4020 - AD4130 - AD4110 diff --git a/test/emu/devices/ad2s1210.xml b/test/emu/devices/ad2s1210.xml new file mode 100644 index 000000000..589937aa9 --- /dev/null +++ b/test/emu/devices/ad2s1210.xml @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/emu/hardware_map.yml b/test/emu/hardware_map.yml index 9e95b374c..89c49afea 100644 --- a/test/emu/hardware_map.yml +++ b/test/emu/hardware_map.yml @@ -93,6 +93,16 @@ daq3: - data_devices: - iio:device3 - iio:device4 + +ad2s1210: + - ad2s1210 + - pyadi_iio_class_support: + - ad2s1210 + - emulate: + - filename: ad2s1210.xml + - data_devices: + - iio:device1 + ad9081: - axi-ad9081-tx-hpc - axi-ad9081-rx-hpc diff --git a/test/test_ad2s1210.py b/test/test_ad2s1210.py new file mode 100644 index 000000000..37a6222ce --- /dev/null +++ b/test/test_ad2s1210.py @@ -0,0 +1,47 @@ +import pytest + +hardware = "ad2s1210" +classname = "adi.ad2s1210" + + +######################################### +@pytest.mark.iio_hardware(hardware, True) +@pytest.mark.parametrize("classname", [classname]) +@pytest.mark.parametrize("channel", ["angl0", "anglvel0", ["angl0", "anglvel0"]]) +def test_ad2s1210_rx_data(test_dma_rx, iio_uri, classname, channel): + test_dma_rx(iio_uri, classname, channel, buffer_size=1024) + + +######################################### +@pytest.mark.iio_hardware(hardware) +@pytest.mark.parametrize("classname", [classname]) +@pytest.mark.parametrize( + "attr, start, stop, step, tol, repeats", + [("excitation_frequency", 2000, 20000, 250, 1, 10),], +) +def test_ad2s1210_attr( + test_attribute_single_value, + iio_uri, + classname, + attr, + start, + stop, + step, + tol, + repeats, +): + test_attribute_single_value( + iio_uri, classname, attr, start, stop, step, tol, repeats + ) + + +######################################### +@pytest.mark.iio_hardware(hardware) +@pytest.mark.parametrize("classname", [classname]) +@pytest.mark.parametrize( + "attr, value", [("hysteresis_enable", True), ("hysteresis_enable", False),], +) +def test_ad2s1210_attr_boolean( + test_attribute_single_value_boolean, iio_uri, classname, attr, value +): + test_attribute_single_value_boolean(iio_uri, classname, attr, value)