Skip to content

Commit

Permalink
adi/ad2s1210: add AD2S1210 Resolver-to-Digital Converter
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
dlech committed Oct 4, 2023
1 parent 1124c4e commit 210f2b4
Show file tree
Hide file tree
Showing 8 changed files with 318 additions and 0 deletions.
1 change: 1 addition & 0 deletions adi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
106 changes: 106 additions & 0 deletions adi/ad2s1210.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Copyright (C) 2023 Analog Devices, Inc.
#
# SPDX short identifier: ADIBSD

from typing import List

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_enabled(self) -> bool:
"""
Gets and sets the hysteresis bit in the Control register.
"""
return bool(self._get_iio_attr("angl0", "hysteresis", False))

@hysteresis_enabled.setter
def hysteresis_enabled(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)])

@property
def hysteresis_avail(self) -> List[int]:
"""Get list of all the hysteresis available."""
return self._get_iio_attr("hysteresis_available")

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))
7 changes: 7 additions & 0 deletions doc/source/devices/adi.ad2s1210.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
ad2s1210
=================

.. automodule:: adi.ad2s1210
:members:
:undoc-members:
:show-inheritance:
1 change: 1 addition & 0 deletions doc/source/devices/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Supported Devices
:maxdepth: 4

adi.QuadMxFE_multi
adi.ad2s1210
adi.ad4020
adi.ad4110
adi.ad4130
Expand Down
1 change: 1 addition & 0 deletions supported_parts.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
[[Wiki](https://wiki.analog.com/resources/tools-software/linux-software/pyadi-iio)]

### Currently supported hardware
- AD2S1210
- AD4020
- AD4130
- AD4110
Expand Down
154 changes: 154 additions & 0 deletions test/emu/devices/ad2s1210.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE context [
<!ELEMENT context (device | context-attribute)*>
<!ELEMENT context-attribute EMPTY>
<!ELEMENT device (channel | attribute | debug-attribute | buffer-attribute)*>
<!ELEMENT channel (scan-element?, attribute*)>
<!ELEMENT attribute EMPTY>
<!ELEMENT scan-element EMPTY>
<!ELEMENT debug-attribute EMPTY>
<!ELEMENT buffer-attribute EMPTY>
<!ATTLIST context
name CDATA #REQUIRED
description CDATA #IMPLIED>
<!ATTLIST context-attribute
name CDATA #REQUIRED
value CDATA #REQUIRED>
<!ATTLIST device
id CDATA #REQUIRED
name CDATA #IMPLIED>
<!ATTLIST channel
id CDATA #REQUIRED
type (input|output) #REQUIRED
name CDATA #IMPLIED>
<!ATTLIST scan-element
index CDATA #REQUIRED
format CDATA #REQUIRED
scale CDATA #IMPLIED>
<!ATTLIST attribute
name CDATA #REQUIRED
filename CDATA #IMPLIED
value CDATA #IMPLIED>
<!ATTLIST debug-attribute
name CDATA #REQUIRED
value CDATA #IMPLIED>
<!ATTLIST buffer-attribute
name CDATA #REQUIRED
value CDATA #IMPLIED>
]>
<context name="network"
description="10.2.5.203 Linux setup-2-zed 6.6.0-rc1-00159-gc9e4b991d8c1 #1 SMP PREEMPT Tue Sep 26 10:20:33 CDT 2023 armv7l">
<context-attribute name="hw_carrier" value="Xilinx Zynq ZED" />
<context-attribute name="local,kernel" value="6.6.0-rc1-00159-gc9e4b991d8c1" />
<context-attribute name="uri" value="ip:10.2.5.203" />
<context-attribute name="ip,ip-addr" value="10.2.5.203" />
<device id="hwmon0" name="e000b000ethernetffffffff00">
<channel id="temp1" type="input">
<attribute name="crit" filename="temp1_crit" value="100000" />
<attribute name="input" filename="temp1_input" value="43000" />
<attribute name="max_alarm" filename="temp1_max_alarm" value="0" />
</channel>
</device>
<device id="iio:device0" name="xadc">
<channel id="voltage5" name="vccoddr" type="input">
<attribute name="label" filename="in_voltage5_vccoddr_label" value="vccoddr" />
<attribute name="raw" filename="in_voltage5_vccoddr_raw" value="2051" />
<attribute name="scale" filename="in_voltage5_vccoddr_scale" value="0.732421875" />
</channel>
<channel id="voltage0" name="vccint" type="input">
<attribute name="label" filename="in_voltage0_vccint_label" value="vccint" />
<attribute name="raw" filename="in_voltage0_vccint_raw" value="1394" />
<attribute name="scale" filename="in_voltage0_vccint_scale" value="0.732421875" />
</channel>
<channel id="voltage4" name="vccpaux" type="input">
<attribute name="label" filename="in_voltage4_vccpaux_label" value="vccpaux" />
<attribute name="raw" filename="in_voltage4_vccpaux_raw" value="2464" />
<attribute name="scale" filename="in_voltage4_vccpaux_scale" value="0.732421875" />
</channel>
<channel id="temp0" type="input">
<attribute name="offset" filename="in_temp0_offset" value="-2219" />
<attribute name="raw" filename="in_temp0_raw" value="2624" />
<attribute name="scale" filename="in_temp0_scale" value="123.040771484" />
</channel>
<channel id="voltage7" name="vrefn" type="input">
<attribute name="label" filename="in_voltage7_vrefn_label" value="vrefn" />
<attribute name="raw" filename="in_voltage7_vrefn_raw" value="11" />
<attribute name="scale" filename="in_voltage7_vrefn_scale" value="0.732421875" />
</channel>
<channel id="voltage1" name="vccaux" type="input">
<attribute name="label" filename="in_voltage1_vccaux_label" value="vccaux" />
<attribute name="raw" filename="in_voltage1_vccaux_raw" value="2459" />
<attribute name="scale" filename="in_voltage1_vccaux_scale" value="0.732421875" />
</channel>
<channel id="voltage2" name="vccbram" type="input">
<attribute name="label" filename="in_voltage2_vccbram_label" value="vccbram" />
<attribute name="raw" filename="in_voltage2_vccbram_raw" value="1397" />
<attribute name="scale" filename="in_voltage2_vccbram_scale" value="0.732421875" />
</channel>
<channel id="voltage3" name="vccpint" type="input">
<attribute name="label" filename="in_voltage3_vccpint_label" value="vccpint" />
<attribute name="raw" filename="in_voltage3_vccpint_raw" value="1393" />
<attribute name="scale" filename="in_voltage3_vccpint_scale" value="0.732421875" />
</channel>
<channel id="voltage6" name="vrefp" type="input">
<attribute name="label" filename="in_voltage6_vrefp_label" value="vrefp" />
<attribute name="raw" filename="in_voltage6_vrefp_raw" value="1715" />
<attribute name="scale" filename="in_voltage6_vrefp_scale" value="0.732421875" />
</channel>
<attribute name="sampling_frequency" value="961538" />
<attribute name="waiting_for_supplier" value="0" />
</device>
<device id="iio:device1" name="ad2s1210">
<channel id="angl0" type="input">
<scan-element index="0" format="be:U16/16&gt;&gt;0" scale="0.000096" />
<attribute name="hysteresis" filename="in_angl0_hysteresis" value="64" />
<attribute name="hysteresis_available" filename="in_angl0_hysteresis_available"
value="0 64" />
<attribute name="label" filename="in_angl0_label" value="position" />
<attribute name="raw" filename="in_angl0_raw" value="12577" />
<attribute name="scale" filename="in_angl0_scale" value="0.000095874" />
</channel>
<channel id="anglvel0" type="input">
<scan-element index="1" format="be:S16/16&gt;&gt;0" scale="0.023968" />
<attribute name="label" filename="in_anglvel0_label" value="velocity" />
<attribute name="raw" filename="in_anglvel0_raw" value="3" />
<attribute name="scale" filename="in_anglvel0_scale" value="0.023968449" />
</channel>
<channel id="timestamp" type="input">
<scan-element index="2" format="le:S64/64&gt;&gt;0" />
</channel>
<channel id="phase0" type="input">
<attribute name="label" filename="in_phase0_label" value="synthetic reference" />
</channel>
<channel id="altvoltage0" type="output">
<attribute name="frequency" filename="out_altvoltage0_frequency" value="10000" />
<attribute name="frequency_available" filename="out_altvoltage0_frequency_available"
value="[2000 250 20000]" />
<attribute name="label" filename="out_altvoltage0_label" value="excitation" />
</channel>
<channel id="altvoltage2" type="input">
<attribute name="label" filename="in_altvoltage2_label" value="sine" />
</channel>
<channel id="angl1" type="input">
<attribute name="label" filename="in_angl1_label" value="tracking error" />
</channel>
<channel id="altvoltage0" type="input">
<attribute name="label" filename="in_altvoltage0_label" value="monitor signal" />
</channel>
<channel id="altvoltage1" type="input">
<attribute name="label" filename="in_altvoltage1_label" value="cosine" />
</channel>
<attribute name="current_timestamp_clock" value="realtime" />
<attribute name="waiting_for_supplier" value="0" />
<buffer-attribute name="data_available" value="0" />
<buffer-attribute name="direction" value="in" />
<debug-attribute name="direct_reg_access" value="ERROR" />
</device>
<device id="iio_sysfs_trigger">
<attribute name="add_trigger" value="ERROR" />
<attribute name="remove_trigger" value="ERROR" />
</device>
<device id="trigger0" name="test">
<attribute name="sampling_frequency" value="100.000000" />
</device>
</context>
10 changes: 10 additions & 0 deletions test/emu/hardware_map.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
38 changes: 38 additions & 0 deletions test/test_ad2s1210.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import pytest

hardware = "ad2s1210"
classname = "adi.ad2s1210"


#########################################
@pytest.mark.iio_hardware(hardware, True)
@pytest.mark.parametrize("classname", [classname])
@pytest.mark.parametrize("channel", ["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),
("hysteresis_enabled", False, True, 1, 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
)

0 comments on commit 210f2b4

Please sign in to comment.