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

adrv9002 profile updates #600

Merged
merged 3 commits into from
Oct 1, 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
13 changes: 11 additions & 2 deletions adi/adrv9002.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,12 @@ def write_stream(self, value):
attr_encode = "stream_config".encode("ascii")
iio._d_write_attr(self._ctrl._device, attr_encode, data)

# we cannot really get the profile. The driver will just throw EPERM
profile = property(None, write_profile)
@property
def profile(self):
profile_data = self._get_iio_dev_attr_str("profile_config")
return dict(x.split(": ") for x in profile_data.split("\n"))

# we cannot really get the stream. The driver will just throw EPERM
stream = property(None, write_stream)

@property
Expand Down Expand Up @@ -719,3 +723,8 @@ def tx1_lo(self):
@tx1_lo.setter
def tx1_lo(self, value):
self._set_iio_attr("altvoltage3", "frequency", True, value)

@property
def api_version(self):
"""api_version: Get the version of the API"""
return self._get_iio_debug_attr_str("api_version")
177 changes: 177 additions & 0 deletions examples/adrv9002_profile_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
"""This example demonstrates how to load a prebuilt profile or create a custom
profile for the ADRV9002 transceiver. If you have libadrv9002-iio installed,
you can create a custom profile. Otherwise, you can use a prebuilt profile that
was generated using libadrv9002-iio or TES.
"""

import argparse
import os
import time

import adi
import matplotlib.pyplot as plt
import numpy as np
from scipy import signal

# Find the location of this script since the profile folder is relative to it
loc = os.path.dirname(os.path.realpath(__file__))

try:
# Try using libadrv9002 to load profiles
# Available at: https://analogdevicesinc.github.io/libadrv9002-iio/
import adrv9002 as libadrv9002
import copy

use_prebuilt_profiles = False
except ImportError:
print("libadrv9002 not found. Using prebuilt profiles.")
use_prebuilt_profiles = True
profile_folder = os.path.join(loc, "adrv9002_profiles")

# Add CLI argument for URI
parser = argparse.ArgumentParser()
parser.add_argument(
"uri", help="URI for IIO context with ADRV9002-EVAL or AD-JUPITER-EZ"
)
args = parser.parse_args()

# Create ADRV9002 interface
uri = args.uri
sdr = adi.adrv9002(uri=uri)

# Read back radio settings
current_profile = sdr.profile
interface_mode = current_profile["SSI interface"].lower()
api_version = sdr.api_version

print("\nCurrent radio settings:")
print(f"Interface mode: {interface_mode}")
print(f"API version: {api_version}")


# Configure ADRV9002
# See here for more information on the ADRV9002 python API:
# https://analogdevicesinc.github.io/pyadi-iio/devices/adi.adrv9002.html
if use_prebuilt_profiles:
api_version = api_version.replace(".", "_")
rate = 40 if interface_mode == "lvds" else 5
name = f"lte_{rate}_{interface_mode}_api_{api_version}"

print(f"\nLoading prebuilt profile: {name}")
else:
# Create profile configuration
print("\nCreating custom profile")
rx1 = libadrv9002.rx_radio_channel_config()
rx1.enabled = True
rx1.adc_high_performance_mode = True
rx1.frequency_offset_correction_enable = False
rx1.analog_filter_power_mode = 2 # High power/performance
rx1.analog_filter_biquad = False
rx1.analog_filter_bandwidth_hz = 18000000
rx1.channel_bandwidth_hz = 18000000
rx1.sample_rate_hz = 30720000
rx1.nco_enable = False
rx1.nco_frequency_hz = 0
rx1.rf_port = 0 # RX-A

rx2 = copy.deepcopy(rx1)

tx1 = libadrv9002.tx_radio_channel_config()
tx1.enabled = True
tx1.sample_rate_hz = 30720000
tx1.frequency_offset_correction_enable = False
tx1.analog_filter_power_mode = 2 # High power/performance
tx1.channel_bandwidth_hz = 18000000
tx1.orx_enabled = True
tx1.elb_type = 2

tx2 = copy.deepcopy(tx1)

r_cfg = libadrv9002.radio_config()
r_cfg.adc_rate_mode = 3 # High Performance
r_cfg.fdd = False
r_cfg.lvds = True
r_cfg.ssi_lanes = 2
r_cfg.ddr = True
r_cfg.adc_rate_mode = 3 # High Performance
r_cfg.short_strobe = True
r_cfg.rx_config[0] = rx1
r_cfg.rx_config[1] = rx2
r_cfg.tx_config[0] = tx1
r_cfg.tx_config[1] = tx2

clk_cfg = libadrv9002.clock_config()
clk_cfg.device_clock_frequency_khz = 38400
clk_cfg.clock_pll_high_performance_enable = True
clk_cfg.clock_pll_power_mode = 2 # High power/performance
clk_cfg.processor_clock_divider = 1

adrv_cfg = libadrv9002.adrv9002_config()
adrv_cfg.clk_cfg = clk_cfg
adrv_cfg.radio_cfg = r_cfg

# Generate profile and stream binary
profile, stream = libadrv9002.generate_profile(adrv_cfg)

# Save profile and stream
name = "custom_profile"
profile_folder = os.path.join(loc, "adrv9002_profiles")
if not os.path.exists(profile_folder):
os.makedirs(profile_folder)

with open(os.path.join(profile_folder, f"{name}.json"), "w") as f:
f.write(str(profile))
with open(os.path.join(profile_folder, f"{name}.stream"), "wb") as f:
f.write(stream)

print(f"\nProfile and stream saved to {profile_folder}")


# Load profile
sdr.write_stream_profile(
os.path.join(profile_folder, f"{name}.stream"),
os.path.join(profile_folder, f"{name}.json"),
)


sdr.rx_enabled_channels = [0]
sdr.rx_ensm_mode_chan0 = "rf_enabled"
sdr.rx_ensm_mode_chan1 = "rf_enabled"
sdr.tx_hardwaregain_chan0 = -20
sdr.tx_ensm_mode_chan0 = "rf_enabled"
sdr.tx_cyclic_buffer = True

sdr.rx0_lo = 1000000000
sdr.tx0_lo = 1000000000

fs = int(sdr.rx0_sample_rate)

# Set single DDS tone for TX on one transmitter
sdr.dds_single_tone(1000000, 0.9, channel=0)

# Create a sinewave waveform
# fc = 1000000
# N = 1024
# ts = 1 / float(fs)
# t = np.arange(0, N * ts, ts)
# i = np.cos(2 * np.pi * t * fc) * 2 ** 14
# q = np.sin(2 * np.pi * t * fc) * 2 ** 14
# iq = i + 1j * q
#
# # Send data
# sdr.tx(iq)

sdr.rx_buffer_size = 2 ** 18

# Collect data
for r in range(20):
x = sdr.rx()
f, Pxx_den = signal.periodogram(x, fs)
plt.clf()
plt.semilogy(f, Pxx_den)
# plt.ylim([1e-9, 1e2])
plt.xlabel("frequency [Hz]")
plt.ylabel("PSD [V**2/Hz]")
plt.draw()
plt.pause(0.05)
time.sleep(0.1)
1 change: 1 addition & 0 deletions examples/adrv9002_profiles/custom_profile.json

Large diffs are not rendered by default.

Binary file not shown.
Loading
Loading