aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2022-03-10 12:07:24 +0100
committerAaron Rossetto <aaron.rossetto@ni.com>2022-04-11 13:01:05 -0700
commite43a8a79ed93daab802f578b3f8ea9c50b52a367 (patch)
treebf5bc99b1e2c2d49eea3da870c6d06a4c7d58f41
parent197cdc4f665cbd4e6394a7eeb44b405f67ab10b1 (diff)
downloaduhd-e43a8a79ed93daab802f578b3f8ea9c50b52a367.tar.gz
uhd-e43a8a79ed93daab802f578b3f8ea9c50b52a367.tar.bz2
uhd-e43a8a79ed93daab802f578b3f8ea9c50b52a367.zip
mpm: ad937x: Fix tuning code
This fixes a known issue (see TODO) that the N300 and N310 have sub-Hz tuning inaccuracies. In fact, these are explained in the corresponding User Guide (UG-992). This commit modifies MPM to return the actual frequency when calling into ad937x_device::tune() or ad937x_device::get_freq(), instead of the nearest integer value. Co-authored-by: Arthur Moraes do Lago <arthurmoraeslago@gmail.com>
-rw-r--r--mpm/lib/mykonos/ad937x_device.cpp55
1 files changed, 53 insertions, 2 deletions
diff --git a/mpm/lib/mykonos/ad937x_device.cpp b/mpm/lib/mykonos/ad937x_device.cpp
index 1a1905004..c9e58d2b9 100644
--- a/mpm/lib/mykonos/ad937x_device.cpp
+++ b/mpm/lib/mykonos/ad937x_device.cpp
@@ -759,6 +759,57 @@ void ad937x_device::set_enable_gain_pins(
/******************************************************
Get configuration functions
******************************************************/
+
+/* Convert from the value returned by MYKONOS_getRfPllFrequency into the actual
+ * frequency.
+ *
+ * Note that MYKONOS_setRfPllFrequency() and MYKONOS_getRfPllFrequency() only
+ * deal in integers, and thus will end up with sub-Hz errors.
+ *
+ * Depending on the frequency range, ad9371 adopts a set denominator for the
+ * fractional N PLL:
+ * From 400MHz to 750MHz : divide by 16
+ * From 750MHz to 1500MHz : divide by 8
+ * From 1500MHz to 3000MHz : divide by 4
+ * From 3000MHz to 6000MHz : divide by 2
+ * This table comes straight from the user guide, from section
+ * RF PLL FREQUENCY CHANGE PROCEDURE.
+ *
+ * From the the table in section RF PLL RESOLUTION LIMITATIONS,
+ * we have some frequency steps depending on the master clock rate (aka device
+ * clock, or DEV_CLK).
+ * Dividing the master clock rate by the frequency steps, and combining
+ * with some experimental data analyzing the possible frequency steps,
+ * we arrive at the formula for frequency_step below
+ *
+ */
+double _get_actual_pll_freq(const double coerced_pll_freq, const double dev_clk)
+{
+ const unsigned denominator = [&]() {
+ // This first band is in the datasheet as from 400 MHz to 750 MHz, but
+ // we'll leave it open-ended.
+ if (coerced_pll_freq <= 750e6) {
+ return 16;
+ } else if (coerced_pll_freq <= 1500e6) {
+ return 8;
+ } else if (coerced_pll_freq <= 3000e6) {
+ return 4;
+ // This last band is in the datasheet as from 3000 MHz to 6000 MHz, but
+ // we'll leave it open-ended.
+ } else {
+ return 2;
+ }
+ }();
+ // Note: This value is not listed in the data sheet, but can be derived by
+ // dividing the master clock rate by the frequency steps from Table 97,
+ // and verifying with experimental results (see comment above).
+ constexpr double pll_den_base = 33546240.0;
+ const double frequency_step = 2.0 * dev_clk / pll_den_base / denominator;
+
+ return std::round(coerced_pll_freq / frequency_step) * frequency_step;
+}
+
+
double ad937x_device::get_freq(const direction_t direction)
{
mykonosRfPllName_t pll;
@@ -773,10 +824,10 @@ double ad937x_device::get_freq(const direction_t direction)
MPM_THROW_INVALID_CODE_PATH();
}
- // TODO: because coerced_pll is returned as an integer, it's not accurate
uint64_t coerced_pll;
CALL_API(MYKONOS_getRfPllFrequency(mykonos_config.device, pll, &coerced_pll));
- return static_cast<double>(coerced_pll);
+ return _get_actual_pll_freq(static_cast<double>(coerced_pll),
+ mykonos_config.device->clocks->deviceClock_kHz * 1000.0);
}
bool ad937x_device::get_pll_lock_status(const uint8_t pll, const bool wait_for_lock)