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

Adrv9009 #149

Merged
merged 30 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
6bbf5eb
tests: clocks: fix and use solver fixture
liambeguin Sep 20, 2023
cf1bc6d
tests: clocks: drop duplicate test case
liambeguin Sep 20, 2023
a51246c
tests: adrv9009: factorize test cases
liambeguin Sep 21, 2023
e1065d8
tests: clocks: factorize ad9523_1_daq2_validate test case
liambeguin Sep 20, 2023
03c9303
clocks: ad9528: fix typo in divider name
liambeguin Sep 21, 2023
238a776
clocks: ad9528: fix N2 range
liambeguin Sep 21, 2023
ff2bb54
clocks: ad9528: add sysref support
liambeguin Sep 21, 2023
e8cdff3
clocks: ad9528: add vco and vcxo to configuration output
liambeguin Sep 21, 2023
ea82ec0
clocks: ad9528: allow for duplicate output frequencies
liambeguin Sep 22, 2023
7bf6aa6
tests: clocks: add ad9528 test case
liambeguin Sep 21, 2023
e4ff1ab
tests: clocks: add sysref test case for the ad9528
liambeguin Sep 21, 2023
c98be20
converters: adrv9009: add explicit converter names
liambeguin Sep 22, 2023
6adeed2
converters: ad9081: drop unused _model_type
liambeguin Sep 22, 2023
0f99480
converters: ad9081: make use of _add_intermediate
liambeguin Sep 22, 2023
d267a9f
converters: adrv9009: fix nested support
liambeguin Sep 22, 2023
bed5263
tests: adrv9009: mark gekko tests as expected failures
liambeguin Sep 22, 2023
4869e76
jesd: fix copy-paste error in docstring
liambeguin Sep 22, 2023
cd2f84f
jesd: use f-strings
liambeguin Sep 22, 2023
78358bf
converters: adrv9009: derive adrv9009_core from converter
liambeguin Sep 25, 2023
eb9658e
system: fix type hint on converter input
liambeguin Sep 25, 2023
a530ccd
system: use proper L parameter for nested devices
liambeguin Sep 25, 2023
99ede21
docs: update list of supported parts
liambeguin Sep 25, 2023
f0d48f8
utils: rename jesd_mode to jesd_class
liambeguin Sep 25, 2023
4d94b30
converters: adrv9009: update interpolation/decimation parameters
liambeguin Sep 26, 2023
3ff7ce6
converters: adrv9009: adjust converter_clock range
liambeguin Sep 26, 2023
a088a2e
examples: add adrv9009-pcbz sample
liambeguin Sep 26, 2023
9d14f95
converters: adrv9009: fix jesd_mode config output
liambeguin Sep 26, 2023
07f0a8b
docs: remove duplicate SYSREF definition
liambeguin Sep 28, 2023
dba090c
docs: fpga_internal: fix minor typos and formatting
liambeguin Sep 28, 2023
001a8ca
Merge branch 'main' into adrv9009
tfcollins Sep 27, 2024
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
95 changes: 86 additions & 9 deletions adijif/clocks/ad9528.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ class ad9528(ad9528_bf):
m1_available = [3, 4, 5]
""" Output dividers """
d_available = [*range(1, 1024)]
""" sysref dividers """
k_available = [*range(0, 65536)]
""" VCXO multiplier """
n2_available = [*range(12, 256)]
n2_available = [*range(1, 256)]
""" VCO calibration dividers """
a_available = [0, 1, 2, 3]
b_availble = [*range(3, 64)]
Expand All @@ -32,7 +34,8 @@ class ad9528(ad9528_bf):
# Defaults
_m1: Union[List[int], int] = [3, 4, 5]
_d: Union[List[int], int] = [*range(1, 1024)]
_n2: Union[List[int], int] = [*range(12, 255)]
_k: Union[List[int], int] = k_available
_n2: Union[List[int], int] = n2_available
_r1: Union[List[int], int] = [*range(1, 32)]
_a: Union[List[int], int] = [*range(0, 4)]
_b: Union[List[int], int] = [*range(3, 64)]
Expand All @@ -47,6 +50,10 @@ class ad9528(ad9528_bf):
use_vcxo_double = False
vcxo = 125e6

# sysref parameters
sysref_external = False
_sysref = None

@property
def m1(self) -> Union[int, List[int]]:
"""VCO divider path 1.
Expand Down Expand Up @@ -95,29 +102,53 @@ def d(self, value: Union[int, List[int]]) -> None:
self._check_in_range(value, self.d_available, "d")
self._d = value

@property
def k(self) -> Union[int, List[int]]:
"""Sysref dividers.

Valid dividers are 0->65535

Returns:
int: Current allowable dividers
"""
return self._k

@k.setter
def k(self, value: Union[int, List[int]]) -> None:
"""Sysref dividers.

Valid dividers are 0->65535

Args:
value (int, list[int]): Allowable values for divider

"""
self._check_in_range(value, self.d_available, "k")
self._k = value

@property
def n2(self) -> Union[int, List[int]]:
"""n2: VCO feedback divider.

Valid dividers are 12->255
Valid dividers are 1->255

Returns:
int: Current allowable dividers
"""
return self._m2
return self._n2

@n2.setter
def n2(self, value: Union[int, List[int]]) -> None:
"""VCO feedback divider.

Valid dividers are 12->255
Valid dividers are 1->255

Args:
value (int, list[int]): Allowable values for divider

"""
self._check_in_range(value, self.n2_available, "n2")
self._m2 = value
self._n2 = value

@property
def r1(self) -> Union[int, List[int]]:
Expand Down Expand Up @@ -191,6 +222,35 @@ def b(self, value: Union[int, List[int]]) -> None:
self._check_in_range(value, self.b_available, "b")
self._b = value

@property
def vco(self):
r1 = self._get_val(self.config["r1"])
m1 = self._get_val(self.config["m1"])
n2 = self._get_val(self.config["n2"])

return self.vcxo / r1 * m1 * n2

@property
def sysref(self):
"""SYSREF Frequency

Returns:
float: computed sysref frequency
"""
r1 = self._get_val(self.config["r1"])
k = self._get_val(self.config["k"])

if self.sysref_external:
sysref_src = self.vcxo
else:
sysref_src = self.vcxo / r1

return sysref_src / (2 * k)

@sysref.setter
def sysref(self, value: Union[int, float]):
self._sysref = int(value)

def get_config(self, solution: CpoSolveResult = None) -> Dict:
"""Extract configurations from solver results.

Expand All @@ -216,6 +276,8 @@ def get_config(self, solution: CpoSolveResult = None) -> Dict:
out_dividers = [self._get_val(x) for x in self.config["out_dividers"]]

config: Dict = {
"vcxo": self.vcxo / 2 if self.use_vcxo_double else self.vcxo,
"vco": self.vco,
"r1": self._get_val(self.config["r1"]),
"n2": self._get_val(self.config["n2"]),
"m1": self._get_val(self.config["m1"]),
Expand All @@ -225,6 +287,10 @@ def get_config(self, solution: CpoSolveResult = None) -> Dict:
"output_clocks": [],
}

if self._sysref:
config["k"] = self._get_val(self.config["k"])
config["sysref"] = self.sysref

clk = self.vcxo * config["n2"] / config["r1"]

output_cfg = {}
Expand Down Expand Up @@ -256,6 +322,7 @@ def _setup_solver_constraints(self, vcxo: int) -> None:
self.config = {
"r1": self._convert_input(self._r1, "r1"),
"m1": self._convert_input(self._m1, "m1"),
"k": self._convert_input(self._k, "k"),
"n2": self._convert_input(self._n2, "n2"),
"a": self._convert_input(self._a, "a"),
"b": self._convert_input(self._b, "b"),
Expand Down Expand Up @@ -318,7 +385,7 @@ def _get_clock_constraint(
return self.vcxo / self.config["r1"] * self.config["n2"] / od

def set_requested_clocks(
self, vcxo: int, out_freqs: List, clk_names: List[str]
self, vcxo: int, out_freqs: List, clk_names: List[str],
) -> None:
"""Define necessary clocks to be generated in model.

Expand All @@ -337,10 +404,20 @@ def set_requested_clocks(
# Setup clock chip internal constraints
self._setup(vcxo)

if self._sysref:
if self.sysref_external:
sysref_src = self.vcxo
else:
sysref_src = self.vcxo / self.config["r1"]

self._add_equation(
[sysref_src / (2 * self.config["k"]) == self._sysref]
)

# Add requested clocks to output constraints
for out_freq in out_freqs:
for out_freq, name in zip(out_freqs, clk_names):
# od = self.model.Var(integer=True, lb=1, ub=256, value=1)
od = self._convert_input(self._d, "d_" + str(out_freq))
od = self._convert_input(self._d, f"d_{name}_{out_freq}")
# od = self.model.sos1([n*n for n in range(1,9)])
self._add_equation(
[self.vcxo / self.config["r1"] * self.config["n2"] / od == out_freq]
Expand Down
71 changes: 18 additions & 53 deletions adijif/converters/ad9081.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ class ad9081_core(converter, metaclass=ABCMeta):
config = {} # type: ignore

device_clock_max = 12e9
_model_type = "adc"
_lmfc_divisor_sysref_available = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]

def _check_valid_internal_configuration(self) -> None:
Expand Down Expand Up @@ -264,15 +263,9 @@ def get_required_clocks(self) -> List:
self._lmfc_divisor_sysref_available, "lmfc_divisor_sysref"
)

if self.solver == "gekko":
self.config["sysref"] = self.model.Intermediate(
self.multiframe_clock # type: ignore
/ self.config["lmfc_divisor_sysref"]
)
elif self.solver == "CPLEX":
self.config["sysref"] = (
self.multiframe_clock / self.config["lmfc_divisor_sysref"]
)
self.config["sysref"] = self._add_intermediate(
self.multiframe_clock / self.config["lmfc_divisor_sysref"]
)

# Device Clocking
if self.clocking_option == "direct":
Expand All @@ -291,7 +284,6 @@ def get_required_clocks(self) -> List:
class ad9081_rx(adc, ad9081_core):
"""AD9081 Receive model."""

_model_type = "adc"
name = "AD9081_RX"

converter_clock_min = 1.45e9
Expand Down Expand Up @@ -369,15 +361,9 @@ def _converter_clock_config(self) -> None:
adc_clk = self.decimation * self.sample_clock
self.config["l"] = self._convert_input([1, 2, 3, 4], "l")
self.config["adc_clk"] = self._convert_input(adc_clk)

if self.solver == "gekko":
self.config["converter_clk"] = self.model.Intermediate(
self.config["adc_clk"] * self.config["l"]
)
elif self.solver == "CPLEX":
self.config["converter_clk"] = self.config["adc_clk"] * self.config["l"]
else:
raise Exception(f"Unknown solver {self.solver}")
self.config["converter_clk"] = self._add_intermediate(
self.config["adc_clk"] * self.config["l"]
)

def _check_valid_internal_configuration(self) -> None:
mode = self._check_valid_jesd_mode()
Expand Down Expand Up @@ -410,7 +396,6 @@ def _check_valid_internal_configuration(self) -> None:
class ad9081_tx(dac, ad9081_core):
"""AD9081 Transmit model."""

_model_type = "dac"
name = "AD9081_TX"

converter_clock_min = 2.9e9
Expand Down Expand Up @@ -492,14 +477,9 @@ def _converter_clock_config(self) -> None:
"""
dac_clk = self.interpolation * self.sample_clock
self.config["dac_clk"] = self._convert_input(dac_clk)
if self.solver == "gekko":
self.config["converter_clk"] = self.model.Intermediate(
self.config["dac_clk"]
)
elif self.solver == "CPLEX":
self.config["converter_clk"] = self.config["dac_clk"]
else:
raise Exception(f"Unknown solver {self.solver}")
self.config["converter_clk"] = self._add_intermediate(
self.config["dac_clk"]
)


class ad9081(ad9081_core):
Expand Down Expand Up @@ -571,14 +551,9 @@ def _converter_clock_config(self) -> None:

self.config["dac_clk"] = self._convert_input(dac_clk)
self.config["adc_clk"] = self._convert_input(adc_clk)
if self.solver == "gekko":
self.config["converter_clk"] = self.model.Intermediate(
self.config["dac_clk"]
)
elif self.solver == "CPLEX":
self.config["converter_clk"] = self.config["dac_clk"]
else:
raise Exception(f"Unknown solver {self.solver}")
self.config["converter_clk"] = self._add_intermediate(
self.config["dac_clk"]
)

# Add single PLL constraint
# JESD204B/C transmitter is a power of 2 divisor of the lane rate of
Expand Down Expand Up @@ -617,22 +592,12 @@ def get_required_clocks(self) -> List:
self.dac._dac_lmfc_divisor_sysref, "dac_lmfc_divisor_sysref"
)

if self.solver == "gekko":
self.config["sysref_adc"] = self.model.Intermediate(
self.adc.multiframe_clock / self.config["adc_lmfc_divisor_sysref"]
)
self.config["sysref_dac"] = self.model.Intermediate(
self.dac.multiframe_clock / self.config["dac_lmfc_divisor_sysref"]
)
elif self.solver == "CPLEX":
self.config["sysref_adc"] = self.adc.multiframe_clock / (
self.config["adc_lmfc_divisor_sysref"]
)
self.config["sysref_dac"] = self.dac.multiframe_clock / (
self.config["dac_lmfc_divisor_sysref"]
)
else:
raise Exception(f"Unknown solver {self.solver}")
self.config["sysref_adc"] = self._add_intermediate(
self.adc.multiframe_clock / self.config["adc_lmfc_divisor_sysref"]
)
self.config["sysref_dac"] = self._add_intermediate(
self.dac.multiframe_clock / self.config["dac_lmfc_divisor_sysref"]
)

# Device Clocking
if self.clocking_option == "direct":
Expand Down
Loading
Loading