Using externally generated converter profiles

External device tools are often the source of truth for a converter datapath. pyadi-jif can reuse that information to solve the clocks and FPGA transceiver configuration around the converter, but the import process differs between AD9084 and ADRV9009.

Important

pyadi-jif models and validates clocking and JESD204 constraints. It does not program the converter. Keep the generated device profile with the software or device-tree configuration that loads it into the hardware.

Workflow overview

  1. Generate and validate the device profile in the vendor tool.

  2. Export the profile artifacts.

  3. Transfer the converter sample rates, datapath factors, and JESD204 parameters into pyadi-jif:

    • AD9084 profiles can be imported directly from the full JSON file.

    • ADRV9009 TES profiles must currently be mapped to pyadi-jif parameters.

  4. Configure the FPGA board and any external PLL topology.

  5. Solve the pyadi-jif system.

  6. Compare the solved lane rates, reference clocks, SYSREF, and JESD parameters with the generated profile before building or programming the hardware.

AD9084 Apollo profiles

Use the AD9084 (Apollo) Profile Generator supplied with the Apollo plugin for ACE to create and validate the device configuration. The generator’s output directory contains:

  • a full .json profile;

  • a _summary.json description;

  • a .bin profile for loading into the AD9084.

Pass the full JSON profile to pyadi-jif. Do not pass the summary JSON or binary file. The binary remains the artifact loaded by the device software.

Import and solve

The following example models an AD9084 RX path whose device clock is generated by an ADF4382 and whose SYSREF is generated by an ADF4030:

from pathlib import Path

import adijif

profile_json = Path("profiles/my_ad9084_profile.json")
vcxo = 125_000_000

system = adijif.system(
    "ad9084_rx", "hmc7044", "xilinx", vcxo, solver="CPLEX"
)
system.converter.apply_profile_settings(str(profile_json))
system.fpga.setup_by_dev_kit_name("vcu118")

system.converter.clocking_option = "direct"
system.add_pll_inline("adf4382", vcxo, system.converter)
system.add_pll_sysref("adf4030", vcxo, system.converter, system.fpga)

config = system.solve()

print(f"sample rate: {system.converter.sample_clock / 1e9:.6f} GSPS")
print(f"lane rate: {system.converter.bit_clock / 1e9:.6f} Gb/s")
print(
    "JESD: "
    f"{system.converter.jesd_class}, "
    f"M={system.converter.M}, L={system.converter.L}, "
    f"S={system.converter.S}, Np={system.converter.Np}"
)

Use "ad9084_tx" for a TX-only model or "ad9084" for the combined RX/TX model. Applying a profile to the combined model configures both system.converter.adc and system.converter.dac.

apply_profile_settings() extracts and applies:

  • the AD9084 device clock;

  • RX CDDC and FDDC decimation;

  • TX CDUC and FDUC interpolation;

  • sample rates;

  • JESD204 class and M, L, S, and Np parameters.

The importer currently validates Apollo profile schema version 9.1.0. A different version raises an error before settings are applied. bypass_version_check=True is available for development, but should only be used after confirming that the exported JSON has a schema compatible with the parser; bypassing the check does not translate a changed schema.

Validate the result

Before using the solved configuration, compare these values with the profile generator:

converter = system.converter
converter._check_clock_relations()

assert converter.bit_clock <= converter.bit_clock_max
assert config["clock"]["output_clocks"]

In particular, check the device clock, baseband sample rate, lane rate, JESD204 class, lane count, converter count, samples per frame, and sample width. A mismatch usually means the wrong JSON artifact or converter direction was selected.

A complete repository example is available in examples/ad9084_rx_ebz_profile.py.

ADRV9009 TES profiles

ADRV9009 profiles are commonly generated with the Transceiver Evaluation Software (TES). pyadi-jif can load a TES profile file directly using the apply_profile_settings method.

Since the TES profile contains RF and digital-filter settings but does not explicitly contain the JESD204 link parameters (M, L, S, Np), you must pass the desired JESD configuration parameters as dictionaries (rx_jesd and tx_jesd for combined, or jesd for individual RX/TX components) when loading the profile.

Values mapped from profile

Applying a profile extracts and maps the following values automatically:

Profile information

pyadi-jif setting

RX output rate (rxOutputRate_kHz)

system.converter.adc.sample_clock in Hz

Product of enabled RX decimation stages (rxFirDecimation × rxDec5Decimation × rhb1Decimation)

system.converter.adc.decimation

TX input rate (txInputRate_kHz)

system.converter.dac.sample_clock in Hz

Product of enabled TX interpolation stages (txFirInterpolation × thb1Interpolation × thb2Interpolation × thb3Interpolation × txInt5Interpolation)

system.converter.dac.interpolation

Configure and solve

import adijif

vcxo = 122_880_000
system = adijif.system("adrv9009", "ad9528", "xilinx", vcxo=vcxo)
system.fpga.setup_by_dev_kit_name("zcu102")
system.fpga.force_qpll = True

# Load and configure from external TES profile path
profile_path = "path/to/Tx_BW200_IR245p76_Rx_BW100_OR122p88_ORx_BW200_OR245p76_DC245p76.txt"
system.converter.apply_profile_settings(
    profile_path,
    rx_jesd={"M": 4, "L": 2, "S": 1, "Np": 16},
    tx_jesd={"M": 4, "L": 4, "S": 1, "Np": 16}
)

config = system.solve()

print(f"RX lane rate: {system.converter.adc.bit_clock / 1e9:.6f} Gb/s")
print(f"TX lane rate: {system.converter.dac.bit_clock / 1e9:.6f} Gb/s")

The corresponding repository example, including the mapping from device-tree profile fields to total decimation and interpolation, is examples/adrv9009_pcbz_example.py.

AD9371 profiles

AD9371 profile files from the iio-oscilloscope ad9371_5 profile collection can be loaded directly. The parser requires Mykonos profile version 0 and validates the profile device clock plus the primary RX, observation RX, and TX datapath rate/factor pairs before changing model state. The combined model exposes and solves all three links as adc, obs, and dac.

The files do not carry JESD framing. pyadi-jif therefore uses the ADI Mykonos transport semantics: JESD204B subclass 1, N=14, Np=16, CS=2, S=1, K=32, and an AD9371 lane-rate range of 614.4 Mb/s through 6.144 Gb/s. The three links share one physical SYSREF domain. The Linux JESD-FSM target’s 78.125 kHz maximum pulsed-SYSREF setting is exported as device metadata because AD9528 programs that provider separately from ordinary output-divider clocks.

import adijif

system = adijif.system("ad9371", "ad9528", "xilinx", vcxo=122_880_000)
system.converter.apply_profile_settings(
    "profile_TxBW200_ORxBW200_RxBW100.txt",
    rx_jesd={"M": 4, "L": 2, "S": 1, "Np": 16},
    tx_jesd={"M": 4, "L": 4, "S": 1, "Np": 16},
)
system.fpga.setup_by_dev_kit_name("zc706")
system.fpga.force_qpll = True
config = system.solve()

For this profile, the model applies a 122.88 MHz primary RX rate, a 245.76 MHz TX rate, a 122.88 MHz AD9371 device clock, RX decimation of 10, and TX interpolation of 2. The JESD arguments are explicit because the profile configures the transceiver datapaths but does not encode the FPGA HDL transport framing.

Use adijif.ad9371_rx, adijif.ad9371_obs, or adijif.ad9371_tx for a single direction. A malformed file, a profile for another device, or a profile missing any of the clocks, rx, obs, or tx sections is rejected before model state is changed.

Final consistency checklist

Before carrying the result into HDL, device tree, or board software, verify that the external profile and pyadi-jif agree on:

  • RX and TX sample rates;

  • total decimation and interpolation;

  • JESD204B or JESD204C encoding;

  • M, L, S, and Np for every link;

  • lane rates and FPGA transceiver limits;

  • converter device/reference clocks;

  • FPGA reference clock;

  • SYSREF frequency and topology.

The generated device profile and pyadi-jif solution serve different purposes. The profile configures the converter; the pyadi-jif result configures and validates the surrounding clock tree and FPGA interface. Keep both artifacts under version control so the complete hardware configuration remains reproducible.