Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for AD9084 Side B FPGA data interfaces #613

Merged
merged 5 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 59 additions & 5 deletions adi/ad9084.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

from typing import Dict, List

from adi.adrv9002 import rx1, rx2, tx1, tx2
from adi.context_manager import context_manager
from adi.obs import obs, remap, tx_two
from adi.rx_tx import rx_tx
from adi.sync_start import sync_start

Expand Down Expand Up @@ -59,19 +61,39 @@ class ad9084(rx_tx, context_manager, sync_start):

_complex_data = True
_rx_channel_names: List[str] = []
_rx2_channel_names: List[str] = []
_tx_channel_names: List[str] = []
_tx2_channel_names: List[str] = []
_tx_control_channel_names: List[str] = []
_rx_coarse_ddc_channel_names: List[str] = []
_tx_coarse_duc_channel_names: List[str] = []
_rx_fine_ddc_channel_names: List[str] = []
_tx_fine_duc_channel_names: List[str] = []
_dds_channel_names: List[str] = []
_dds2_channel_names: List[str] = []
_device_name = ""

_path_map: Dict[str, Dict[str, Dict[str, List[str]]]] = {}

def __init__(self, uri=""):

def __init__(
self,
uri="",
rx1_device_name="axi-ad9084-rx-hpc",
rx2_device_name="axi-ad9084b-rx-b",
tx1_device_name="axi-ad9084-tx-hpc",
tx2_device_name="axi-ad9084-tx-b",
):
"""Create a new instance of the AD9084 MxFE

rx1_device_name is used as the name for the control device and RX1/TX1 data device

Args:
uri: URI of device
rx1_device_name: Name of RX1 device driver. Default is 'axi-ad9084-rx-hpc'
rx2_device_name: Name of RX2 device driver. Default is 'axi-ad9084b-rx-b'
tx1_device_name: Name of TX1 device driver. Default is 'axi-ad9084-tx-hpc'
tx2_device_name: Name of TX2 device driver. Default is 'axi-ad9084-tx-b'
"""
# Reset default channel lists
self._rx_channel_names = []
self._tx_channel_names = []
Expand All @@ -84,10 +106,19 @@ def __init__(self, uri=""):

context_manager.__init__(self, uri, self._device_name)
# Default device for attribute writes
self._ctrl = self._ctx.find_device("axi-ad9084-rx-hpc")
self._ctrl = self._ctx.find_device(rx1_device_name)
# Devices with buffers
self._rxadc = self._ctx.find_device("axi-ad9084-rx-hpc")
self._txdac = self._ctx.find_device("axi-ad9084-tx-hpc")
self._rxadc = self._ctx.find_device(rx1_device_name)
self._txdac = self._ctx.find_device(tx1_device_name)
self._rxadc2 = self._ctx.find_device(rx2_device_name)
self._txdac2 = self._ctx.find_device(tx2_device_name)
# Checks
for dev, name in zip(
[self._rxadc, self._txdac, self._rxadc2, self._txdac2],
[rx1_device_name, tx1_device_name, rx2_device_name, tx2_device_name],
):
if dev is None:
raise Exception(f"No device found with name {name}")

# Get DDC and DUC mappings
paths = {}
Expand All @@ -101,16 +132,27 @@ def __init__(self, uri=""):
for ch in self._rxadc.channels:
if ch.scan_element and not ch.output:
self._rx_channel_names.append(ch._id)
for ch in self._rxadc2.channels:
if ch.scan_element and not ch.output:
self._rx2_channel_names.append(ch._id)
for ch in self._txdac.channels:
if ch.scan_element:
self._tx_channel_names.append(ch._id)
else:
self._dds_channel_names.append(ch._id)
for ch in self._txdac2.channels:
if ch.scan_element:
self._tx2_channel_names.append(ch._id)
else:
self._dds2_channel_names.append(ch._id)

# Sort channel names
self._rx_channel_names = _sortconv(self._rx_channel_names)
self._rx2_channel_names = _sortconv(self._rx2_channel_names)
self._tx_channel_names = _sortconv(self._tx_channel_names)
self._tx2_channel_names = _sortconv(self._tx2_channel_names)
self._dds_channel_names = _sortconv(self._dds_channel_names, dds=True)
self._dds2_channel_names = _sortconv(self._dds2_channel_names, dds=True)

# Map unique attributes to channel properties
self._rx_fine_ddc_channel_names = []
Expand All @@ -132,6 +174,18 @@ def __init__(self, uri=""):
self._tx_coarse_duc_channel_names.append(channels[0])
self._tx_fine_duc_channel_names += channels

# Setup second DMA path
self._rx2 = obs(self._ctx, self._rxadc2, self._rx2_channel_names)
setattr(ad9084, "rx1", rx1)
setattr(ad9084, "rx2", rx2)
remap(self._rx2, "rx_", "rx2_", type(self))

self._tx2 = tx_two(self._ctx, self._txdac2, self._tx2_channel_names)
setattr(ad9084, "tx1", tx1)
setattr(ad9084, "tx2", tx2)
remap(self._tx2, "tx_", "tx2_", type(self))
remap(self._tx2, "dds_", "dds2_", type(self))

rx_tx.__init__(self)
sync_start.__init__(self)
self.rx_buffer_size = 2 ** 16
Expand Down
2 changes: 2 additions & 0 deletions doc/source/devices/adi.ad9084.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
ad9081
=================

AD9084 is a tiled chip with 2 halves or sides. The control interfaces are unified but the DMA and DDS controls are split into multiple methods. This is similar to ADRV9002 and its split DMA modes. There are multiple **rx** and **tx** methods to control the DMA and DDS for each side of the chip. The **rx** (and **rx1**) and **tx** (and **tx1**) methods are used to control the DMA and DDS for the first side of the chip. The **rx2** and **tx2** methods are used to control the DMA and DDS for the second side of the chip.

.. automodule:: adi.ad9084
:members:
:undoc-members:
Expand Down
4 changes: 4 additions & 0 deletions test/emu/devices/adsy1100.xml

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions test/emu/hardware_map.yml
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,20 @@ packrf:
- cf-ad9361-lpc,4
- pyadi_iio_class_support:
- ad9361
adsy1100:
- axi-ad9084-rx-hpc
- axi-ad9084-tx-hpc
- axi-ad9084b-rx-b
- axi-ad9084-tx-b
- pyadi_iio_class_support:
- ad9084
- emulate:
- filename: adsy1100.xml
- data_devices:
- iio:device4
- iio:device5
- iio:device6
- iio:device7

# Generics
ad9361:
Expand Down
34 changes: 30 additions & 4 deletions test/test_ad9084.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

import pytest

hardware = ["ad9084", "ad9084_tdd"]
# hardware = ["ad9084", "ad9084_tdd"] # older builds
hardware = ["adsy1100"]
classname = "adi.ad9084"


Expand Down Expand Up @@ -96,15 +97,15 @@ def test_ad9084_rx_data(test_dma_rx, iio_uri, classname, channel):
#########################################
@pytest.mark.iio_hardware(hardware)
@pytest.mark.parametrize("classname", [(classname)])
@pytest.mark.parametrize("channel", [0, 1, 2, 3])
@pytest.mark.parametrize("channel", [0, 1])
def test_ad9084_tx_data(test_dma_tx, iio_uri, classname, channel):
test_dma_tx(iio_uri, classname, channel)


#########################################
@pytest.mark.iio_hardware(hardware)
@pytest.mark.parametrize("classname", [(classname)])
@pytest.mark.parametrize("channel", [0, 1, 2, 3])
@pytest.mark.parametrize("channel", [0, 1])
@pytest.mark.parametrize(
"param_set",
[
Expand Down Expand Up @@ -134,7 +135,7 @@ def test_ad9084_cyclic_buffers(
#########################################
@pytest.mark.iio_hardware(hardware)
@pytest.mark.parametrize("classname", [(classname)])
@pytest.mark.parametrize("channel", [0, 1, 2, 3])
@pytest.mark.parametrize("channel", [0, 1])
@pytest.mark.parametrize(
"param_set",
[
Expand Down Expand Up @@ -304,3 +305,28 @@ def test_ad9084_nco_loopback(


#########################################
@pytest.mark.iio_hardware("adsy1100")
def test_split_rx_buffers(iio_uri):
import adi

dev = adi.ad9084(uri=iio_uri)
dev.rx_buffer_size = 2 ** 10

d = dev.rx()
d1 = dev.rx1()
d2 = dev.rx2()

assert d is not None
assert d1 is not None
assert d2 is not None


#########################################
@pytest.mark.iio_hardware("adsy1100")
@pytest.mark.parametrize("classname", [(classname)])
@pytest.mark.parametrize("channel", [0, 1])
@pytest.mark.parametrize("use_tx2", [False, True])
def test_ad9084_tx_data_split_buffers(
test_dma_tx, iio_uri, classname, channel, use_tx2
):
test_dma_tx(iio_uri, classname, channel, use_tx2)
Loading