uhd/mpm/python/tests/x440_clock_tests.py
Martin Anderseck c1cc72258d test: Correct sysref divider
In one of the previous changes for dual-rate a wrong value for the
sysref divider made it into test_two_sample_rates. This fixes this and
makes the MPM tests green again.
2023-11-29 08:47:48 -06:00

292 lines
15 KiB
Python

#
# Copyright 2023 Ettus Research, a National Instruments Brand
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
import unittest
import logging
from base_tests import TestBase
from usrp_mpm.periph_manager.x4xx_clock_policy import X440ClockPolicy
from usrp_mpm.periph_manager.x4xx_clock_types import Spll1Vco
from usrp_mpm.periph_manager.x4xx_rfdc_ctrl import X4xxRfdcCtrl
class TestX440ClockConfig(TestBase):
def test_4GHz(self):
"""
Checking values for 4 GHz converter rate
"""
log = logging.getLogger()
cp = X440ClockPolicy(None, None, {}, log)
dsp_info = {
'num_rx_chans': 4,
'num_tx_chans': 4,
'bw': 1600,
'extra_resampling': 1,
'spc_rx': 8,
'spc_tx': 8,
}
cp.set_dsp_info([dsp_info, dsp_info])
mcr = 2e9
ref_clock_freq = 10e6
clk_config = cp.get_config(ref_clock_freq, (mcr, mcr))
self.assertEqual(clk_config.mmcm_use_defaults, False)
# We need to calculate if the values lead to what we want
for idx, clock_rate in enumerate([mcr,mcr]):
self.assertTrue(clk_config.rfdc_configs[idx].resampling in X4xxRfdcCtrl.RFDC_RESAMPLER)
conv_rate = clock_rate * clk_config.rfdc_configs[idx].resampling
self.assertEqual(clk_config.rfdc_configs[idx].conv_rate, conv_rate)
lmk_vco_rate = clk_config.spll_config.output_divider * clk_config.spll_config.output_freq
# Overall PLL2 N divider as combination of prescalar and n div
pll2_n = clk_config.spll_config.pll2_prescaler * clk_config.spll_config.pll2_n_div
self.assertEqual(lmk_vco_rate, 100e6 * pll2_n)
mmcm_vco_rate = lmk_vco_rate / clk_config.spll_config.prc_divider * clk_config.mmcm_feedback_divider
self.assertEqual(mmcm_vco_rate / clk_config.mmcm_output_div_map['r0_clk'], mcr / dsp_info['spc_rx'])
self.assertEqual(mmcm_vco_rate / clk_config.mmcm_output_div_map['r1_clk'], mcr / dsp_info['spc_rx'])
self.assertEqual(clk_config.spll_config.vcxo_freq, Spll1Vco.VCO100MHz)
self.assertEqual(clk_config.spll_config.sysref_div, 1200)
self.assertEqual(clk_config.spll_config.clkin0_r_div, 200)
self.assertEqual(clk_config.spll_config.pll2_n_cal_div, clk_config.spll_config.pll2_n_div)
def test_2_94912GHz(self):
"""
Checking values for default 2.94912 GHz converter rate
"""
log = logging.getLogger()
cp = X440ClockPolicy(None, None, {}, log)
dsp_info = {
'num_rx_chans': 4,
'num_tx_chans': 4,
'bw': 1600,
'extra_resampling': 1,
'spc_rx': 8,
'spc_tx': 8,
}
cp.set_dsp_info([dsp_info, dsp_info])
mcr = 368.64e6
ref_clock_freq = 10e6
clk_config = cp.get_config(ref_clock_freq, [mcr, mcr])
self.assertEqual(clk_config.mmcm_use_defaults, False)
# This should be a rate that we can achieve with PLL bypass:
self.assertEqual(clk_config.rfdc_configs[0].conv_rate, clk_config.spll_config.output_freq)
# We need to calculate if the values lead to what we want
for idx, clock_rate in enumerate([mcr,mcr]):
self.assertTrue(clk_config.rfdc_configs[idx].resampling in X4xxRfdcCtrl.RFDC_RESAMPLER)
conv_rate = clock_rate * clk_config.rfdc_configs[idx].resampling
self.assertEqual(clk_config.rfdc_configs[idx].conv_rate, conv_rate)
lmk_vco_rate = clk_config.spll_config.output_divider * clk_config.spll_config.output_freq
# Overall PLL2 N divider as combination of prescalar and n div
pll2_n = clk_config.spll_config.pll2_prescaler * clk_config.spll_config.pll2_n_div
self.assertEqual(lmk_vco_rate, 122.88e6 * pll2_n)
mmcm_vco_rate = lmk_vco_rate / clk_config.spll_config.prc_divider * clk_config.mmcm_feedback_divider
self.assertEqual(mmcm_vco_rate / clk_config.mmcm_output_div_map['r0_clk'], mcr / dsp_info['spc_rx'])
self.assertEqual(mmcm_vco_rate / clk_config.mmcm_output_div_map['r1_clk'], mcr / dsp_info['spc_rx'])
self.assertEqual(clk_config.spll_config.vcxo_freq, Spll1Vco.VCO122_88MHz)
self.assertEqual(clk_config.spll_config.sysref_div, 1152)
self.assertEqual(clk_config.spll_config.clkin0_r_div, 250)
self.assertEqual(clk_config.spll_config.pll2_n_cal_div, clk_config.spll_config.pll2_n_div)
def test_253_90625M_Conv_Rate(self):
"""
Checking values for difficult master clock rate of 253.90625 MHz
"""
log = logging.getLogger()
cp = X440ClockPolicy(None, None, {}, log)
dsp_info = {
'num_rx_chans': 4,
'num_tx_chans': 4,
'bw': 1600,
'extra_resampling': 1,
'spc_rx': 8,
'spc_tx': 8,
}
cp.set_dsp_info([dsp_info, dsp_info])
mcr = {253.90625e6}
ref_clock_freq = 10e6
mcr = cp.coerce_mcr(mcr)
clk_config = cp.get_config(ref_clock_freq, mcr)
self.assertEqual(clk_config.mmcm_use_defaults, False)
# We need to calculate if the values lead to what we want
for idx, clock_rate in enumerate(mcr):
self.assertTrue(clk_config.rfdc_configs[idx].resampling in X4xxRfdcCtrl.RFDC_RESAMPLER)
conv_rate = clock_rate * clk_config.rfdc_configs[idx].resampling
self.assertEqual(clk_config.rfdc_configs[idx].conv_rate, conv_rate)
lmk_vco_rate = clk_config.spll_config.output_divider * clk_config.spll_config.output_freq
# Overall PLL2 N divider as combination of prescalar and n div
pll2_n = clk_config.spll_config.pll2_prescaler * clk_config.spll_config.pll2_n_div
self.assertEqual(lmk_vco_rate, 100e6 * pll2_n)
mmcm_vco_rate = lmk_vco_rate / clk_config.spll_config.prc_divider * clk_config.mmcm_feedback_divider
self.assertEqual(mmcm_vco_rate / clk_config.mmcm_output_div_map['r0_clk'], mcr[0] / dsp_info['spc_rx'])
self.assertEqual(mmcm_vco_rate / clk_config.mmcm_output_div_map['r1_clk'], mcr[1] / dsp_info['spc_rx'])
self.assertEqual(clk_config.spll_config.vcxo_freq, Spll1Vco.VCO100MHz)
self.assertEqual(clk_config.spll_config.sysref_div, 6400)
self.assertEqual(clk_config.spll_config.clkin0_r_div, 200)
self.assertEqual(clk_config.spll_config.pll2_n_cal_div, clk_config.spll_config.pll2_n_div)
def test_two_sample_rates(self):
"""
Checking values for two different master clock rates
"""
log = logging.getLogger()
cp = X440ClockPolicy(None, None, {}, log)
dsp_info = {
'num_rx_chans': 4,
'num_tx_chans': 4,
'bw': 1600,
'extra_resampling': 1,
'spc_rx': 8,
'spc_tx': 8,
}
cp.set_dsp_info([dsp_info, dsp_info])
mcr = (250e6, 1500e6)
ref_clock_freq = 10e6
mcr = cp.coerce_mcr(mcr)
clk_config = cp.get_config(ref_clock_freq, mcr)
self.assertEqual(clk_config.mmcm_use_defaults, False)
# We need to calculate if the values lead to what we want
for idx, clock_rate in enumerate(mcr):
self.assertTrue(clk_config.rfdc_configs[idx].resampling in X4xxRfdcCtrl.RFDC_RESAMPLER)
conv_rate = clock_rate * clk_config.rfdc_configs[idx].resampling
self.assertEqual(clk_config.rfdc_configs[idx].conv_rate, conv_rate)
lmk_vco_rate = clk_config.spll_config.output_divider * clk_config.spll_config.output_freq
# Overall PLL2 N divider as combination of prescalar and n div
pll2_n = clk_config.spll_config.pll2_prescaler * clk_config.spll_config.pll2_n_div
self.assertEqual(lmk_vco_rate, 100e6 * pll2_n)
mmcm_vco_rate = lmk_vco_rate / clk_config.spll_config.prc_divider * clk_config.mmcm_feedback_divider
self.assertEqual(mmcm_vco_rate / clk_config.mmcm_output_div_map['r0_clk'], mcr[0] / dsp_info['spc_rx'])
self.assertEqual(mmcm_vco_rate / clk_config.mmcm_output_div_map['r1_clk'], mcr[1] / dsp_info['spc_rx'])
self.assertEqual(clk_config.spll_config.vcxo_freq, Spll1Vco.VCO100MHz)
self.assertEqual(clk_config.spll_config.sysref_div, 2400)
self.assertEqual(clk_config.spll_config.clkin0_r_div, 200)
self.assertEqual(clk_config.spll_config.pll2_n_cal_div, clk_config.spll_config.pll2_n_div)
def test_two_sample_rates_inverted(self):
"""
Checking that configurations are only mirrored but not completely different
if the two MCRs are swapped
"""
log = logging.getLogger()
cp = X440ClockPolicy(None, None, {}, log)
dsp_info = {
'num_rx_chans': 4,
'num_tx_chans': 4,
'bw': 1600,
'extra_resampling': 1,
'spc_rx': 8,
'spc_tx': 8,
}
cp.set_dsp_info([dsp_info, dsp_info])
mcr0 = [250e6, 1500e6]
mcr1 = mcr0.copy()
mcr1.reverse()
ref_clock_freq = 10e6
mcr0 = cp.coerce_mcr(mcr0)
mcr1 = cp.coerce_mcr(mcr1)
clk_config0 = cp.get_config(ref_clock_freq, mcr0)
clk_config1 = cp.get_config(ref_clock_freq, mcr1)
self.assertEqual(clk_config0.mmcm_use_defaults, False)
self.assertEqual(clk_config1.mmcm_use_defaults, False)
# We need to calculate if the values lead to what we want
for idx, clock_rate in enumerate(mcr0):
self.assertTrue(clk_config0.rfdc_configs[idx].resampling in X4xxRfdcCtrl.RFDC_RESAMPLER)
conv_rate0 = clock_rate * clk_config0.rfdc_configs[idx].resampling
conv_rate1 = mcr1[1-idx] * clk_config1.rfdc_configs[1-idx].resampling
self.assertEqual(conv_rate0, conv_rate1)
lmk_vco_rate = clk_config0.spll_config.output_divider * clk_config1.spll_config.output_freq
# Overall PLL2 N divider as combination of prescalar and n div
pll2_n0 = clk_config0.spll_config.pll2_prescaler * clk_config0.spll_config.pll2_n_div
pll2_n1 = clk_config1.spll_config.pll2_prescaler * clk_config1.spll_config.pll2_n_div
self.assertEqual(pll2_n0, pll2_n1)
mmcm_vco_rate0 = lmk_vco_rate / clk_config0.spll_config.prc_divider * clk_config0.mmcm_feedback_divider
mmcm_vco_rate1 = lmk_vco_rate / clk_config1.spll_config.prc_divider * clk_config1.mmcm_feedback_divider
self.assertEqual(mmcm_vco_rate0, mmcm_vco_rate1)
self.assertEqual(clk_config0.spll_config.sysref_div, clk_config1.spll_config.sysref_div)
self.assertEqual(clk_config0.spll_config.clkin0_r_div, clk_config1.spll_config.clkin0_r_div)
self.assertEqual(clk_config0.mmcm_output_div_map['r0_clk'], clk_config1.mmcm_output_div_map['r1_clk'])
self.assertEqual(clk_config0.mmcm_output_div_map['r1_clk'], clk_config1.mmcm_output_div_map['r0_clk'])
self.assertEqual(clk_config0.spll_config.vcxo_freq, clk_config1.spll_config.vcxo_freq)
self.assertEqual(clk_config0.rfdc_configs[0], clk_config1.rfdc_configs[1])
self.assertEqual(clk_config0.rfdc_configs[1], clk_config1.rfdc_configs[0])
def test_two_incompatible_sample_rates(self):
"""
Checking that for incompatible sample rates we fall back to MCR0
"""
log = logging.getLogger()
cp = X440ClockPolicy(None, None, {}, log)
dsp_info = {
'num_rx_chans': 4,
'num_tx_chans': 4,
'bw': 1600,
'extra_resampling': 1,
'spc_rx': 8,
'spc_tx': 8,
}
cp.set_dsp_info([dsp_info, dsp_info])
mcr = (1000e6, 368.64e6)
ref_clock_freq = 10e6
mcr = cp.coerce_mcr(mcr)
# ...but since values are incompatible, we can focus on #0
clk_config = cp.get_config(ref_clock_freq, mcr)
self.assertEqual(clk_config.mmcm_use_defaults, False)
# We need to calculate if the values lead to what we want
for idx, clock_rate in enumerate(mcr):
self.assertTrue(clk_config.rfdc_configs[idx].resampling in X4xxRfdcCtrl.RFDC_RESAMPLER)
conv_rate = clock_rate * clk_config.rfdc_configs[idx].resampling
self.assertEqual(clk_config.rfdc_configs[idx].conv_rate, conv_rate)
lmk_vco_rate = clk_config.spll_config.output_divider * clk_config.spll_config.output_freq
# Overall PLL2 N divider as combination of prescalar and n div
pll2_n = clk_config.spll_config.pll2_prescaler * clk_config.spll_config.pll2_n_div
self.assertEqual(lmk_vco_rate, 100e6 * pll2_n)
mmcm_vco_rate = lmk_vco_rate / clk_config.spll_config.prc_divider * clk_config.mmcm_feedback_divider
self.assertEqual(mmcm_vco_rate / clk_config.mmcm_output_div_map['r0_clk'], mcr[0] / dsp_info['spc_rx'])
self.assertEqual(mmcm_vco_rate / clk_config.mmcm_output_div_map['r1_clk'], mcr[1] / dsp_info['spc_rx'])
self.assertEqual(clk_config.spll_config.vcxo_freq, Spll1Vco.VCO100MHz)
self.assertEqual(clk_config.spll_config.sysref_div, 1200)
self.assertEqual(clk_config.spll_config.clkin0_r_div, 200)
self.assertEqual(clk_config.spll_config.pll2_n_cal_div, clk_config.spll_config.pll2_n_div)
def test_converter_rate_arg(self):
"""
Checks if the converter_rate argument is used.
"""
log = logging.getLogger()
cr = 2e9
cp = X440ClockPolicy(None, None, {'converter_rate':cr}, log)
dsp_info = {
'num_rx_chans': 4,
'num_tx_chans': 4,
'bw': 1600,
'extra_resampling': 1,
'spc_rx': 8,
'spc_tx': 8,
}
cp.set_dsp_info([dsp_info, dsp_info])
# In theory, for MCR=500e6, the Conv_Rate should go to 4e9. By passing the conv_rate
# argument we should be able to influence this.
mcr = (500e6,)
ref_clock_freq = 10e6
mcr = cp.coerce_mcr(mcr)
clk_config = cp.get_config(ref_clock_freq, mcr)
self.assertEqual(clk_config.mmcm_use_defaults, False)
# We need to calculate if the values lead to what we want
for idx, clock_rate in enumerate(mcr):
self.assertTrue(clk_config.rfdc_configs[idx].resampling in X4xxRfdcCtrl.RFDC_RESAMPLER)
conv_rate = clock_rate * clk_config.rfdc_configs[idx].resampling
self.assertEqual(conv_rate, cr)
self.assertEqual(clk_config.rfdc_configs[idx].conv_rate, conv_rate)
lmk_vco_rate = clk_config.spll_config.output_divider * clk_config.spll_config.output_freq
# Overall PLL2 N divider as combination of prescalar and n div
pll2_n = clk_config.spll_config.pll2_prescaler * clk_config.spll_config.pll2_n_div
self.assertEqual(lmk_vco_rate, 100e6 * pll2_n)
mmcm_vco_rate = lmk_vco_rate / clk_config.spll_config.prc_divider * clk_config.mmcm_feedback_divider
self.assertEqual(mmcm_vco_rate / clk_config.mmcm_output_div_map['r0_clk'], mcr[0] / dsp_info['spc_rx'])
self.assertEqual(mmcm_vco_rate / clk_config.mmcm_output_div_map['r1_clk'], mcr[1] / dsp_info['spc_rx'])
self.assertEqual(clk_config.spll_config.vcxo_freq, Spll1Vco.VCO100MHz)
self.assertEqual(clk_config.spll_config.sysref_div, 1200)
self.assertEqual(clk_config.spll_config.clkin0_r_div, 200)
self.assertEqual(clk_config.spll_config.pll2_n_cal_div, clk_config.spll_config.pll2_n_div)