diff --git a/adi/ad9084.py b/adi/ad9084.py index 4f48d97ce..3b689386b 100644 --- a/adi/ad9084.py +++ b/adi/ad9084.py @@ -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 @@ -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 = [] @@ -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 = {} @@ -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 = [] @@ -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 diff --git a/doc/source/devices/adi.ad9084.rst b/doc/source/devices/adi.ad9084.rst index 7025ab869..c3e6cc560 100644 --- a/doc/source/devices/adi.ad9084.rst +++ b/doc/source/devices/adi.ad9084.rst @@ -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: diff --git a/test/emu/devices/adsy1100.xml b/test/emu/devices/adsy1100.xml new file mode 100755 index 000000000..31ac21939 --- /dev/null +++ b/test/emu/devices/adsy1100.xml @@ -0,0 +1,4 @@ +]> \ No newline at end of file diff --git a/test/emu/hardware_map.yml b/test/emu/hardware_map.yml index 48b1938f9..4ba0ac05d 100644 --- a/test/emu/hardware_map.yml +++ b/test/emu/hardware_map.yml @@ -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: diff --git a/test/test_ad9084.py b/test/test_ad9084.py index 291b5e3b8..65550eee0 100644 --- a/test/test_ad9084.py +++ b/test/test_ad9084.py @@ -3,7 +3,8 @@ import pytest -hardware = ["ad9084", "ad9084_tdd"] +# hardware = ["ad9084", "ad9084_tdd"] # older builds +hardware = ["adsy1100"] classname = "adi.ad9084" @@ -96,7 +97,7 @@ 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) @@ -104,7 +105,7 @@ def test_ad9084_tx_data(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", [ @@ -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", [ @@ -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)