From 7a303df8e4a9c167691ffd242424be76559a712f Mon Sep 17 00:00:00 2001 From: David Raeman Date: Tue, 8 Mar 2022 02:50:06 +0000 Subject: n320: fix issue that occasionally prevents lo_locked upon first set_freq For certain frequencies, the LMX2592 will sporadically fail to lock upon the very first tune. When this happens, subsequent tunes (even to the same frequency) do lock. This issue seems to be resolved by programming the FCAL adjustment register fields (FCAL_LPFD_ADJ/FCAL_HPFD_ADJ) as described in the LMX2592 datasheet. These fields adjust the FCAL calibration speed to better accomodate PFD frequencies below 20MHz or above 100MHz. This patch also fixes a few name typos in the register map that were directly in the scope of this change. --- host/lib/usrp/common/lmx2592.cpp | 49 +++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 6 deletions(-) (limited to 'host/lib/usrp/common') diff --git a/host/lib/usrp/common/lmx2592.cpp b/host/lib/usrp/common/lmx2592.cpp index 0833bc7c4..0a409f117 100644 --- a/host/lib/usrp/common/lmx2592.cpp +++ b/host/lib/usrp/common/lmx2592.cpp @@ -235,6 +235,8 @@ public: pfd_freq = input_freq / _regs.pll_r; } + _set_fcal_adj_values(pfd_freq); + // Calculate N and frac const auto N_dot_F = target_vco_freq / (pfd_freq * prescaler); auto N = static_cast(std::floor(N_dot_F)); @@ -253,12 +255,12 @@ public: // Calculate Fnum const auto initial_fnum = static_cast(std::round(frac * fden)); const auto fnum = (spur_dodging) ? _find_fnum(N, - initial_fnum, - fden, - prescaler, - pfd_freq, - output_divider, - spur_dodging_threshold) + initial_fnum, + fden, + prescaler, + pfd_freq, + output_divider, + spur_dodging_threshold) : initial_fnum; // Calculate mash_seed @@ -519,6 +521,41 @@ private: // Members } } + void _set_fcal_adj_values(const double pfd_freq) + { + // Adjust FCAL speed for particularly high or low PFD frequencies + if (pfd_freq < 5e6) { + _regs.fcal_lpfd_adj = lmx2592_regs_t::fcal_lpfd_adj_t::FCAL_LPFD_ADJ_5MHZ; + _regs.fcal_hpfd_adj = lmx2592_regs_t::fcal_hpfd_adj_t::FCAL_HPFD_ADJ_UNUSED; + _regs.pfd_ctl = lmx2592_regs_t::pfd_ctl_t::PFD_CTL_DUAL_PFD; + } else if (pfd_freq < 10e6) { + _regs.fcal_lpfd_adj = lmx2592_regs_t::fcal_lpfd_adj_t::FCAL_LPFD_ADJ_10MHZ; + _regs.fcal_hpfd_adj = lmx2592_regs_t::fcal_hpfd_adj_t::FCAL_HPFD_ADJ_UNUSED; + _regs.pfd_ctl = lmx2592_regs_t::pfd_ctl_t::PFD_CTL_DUAL_PFD; + } else if (pfd_freq < 20e6) { + _regs.fcal_lpfd_adj = lmx2592_regs_t::fcal_lpfd_adj_t::FCAL_LPFD_ADJ_20MHZ; + _regs.fcal_hpfd_adj = lmx2592_regs_t::fcal_hpfd_adj_t::FCAL_HPFD_ADJ_UNUSED; + _regs.pfd_ctl = lmx2592_regs_t::pfd_ctl_t::PFD_CTL_DUAL_PFD; + } else if (pfd_freq <= 100e6) { + _regs.fcal_lpfd_adj = lmx2592_regs_t::fcal_lpfd_adj_t::FCAL_LPFD_ADJ_UNUSED; + _regs.fcal_hpfd_adj = lmx2592_regs_t::fcal_hpfd_adj_t::FCAL_HPFD_ADJ_UNUSED; + _regs.pfd_ctl = lmx2592_regs_t::pfd_ctl_t::PFD_CTL_DUAL_PFD; + } else if (pfd_freq <= 150e6) { + _regs.fcal_lpfd_adj = lmx2592_regs_t::fcal_lpfd_adj_t::FCAL_LPFD_ADJ_UNUSED; + _regs.fcal_hpfd_adj = lmx2592_regs_t::fcal_hpfd_adj_t::FCAL_HPFD_ADJ_100MHZ; + _regs.pfd_ctl = lmx2592_regs_t::pfd_ctl_t::PFD_CTL_DUAL_PFD; + } else if (pfd_freq <= 200e6) { + _regs.fcal_lpfd_adj = lmx2592_regs_t::fcal_lpfd_adj_t::FCAL_LPFD_ADJ_UNUSED; + _regs.fcal_hpfd_adj = lmx2592_regs_t::fcal_hpfd_adj_t::FCAL_HPFD_ADJ_150MHZ; + _regs.pfd_ctl = lmx2592_regs_t::pfd_ctl_t::PFD_CTL_DUAL_PFD; + } else { + // Note, this case requires single-loop PFD which increases PLL noise floor + _regs.fcal_lpfd_adj = lmx2592_regs_t::fcal_lpfd_adj_t::FCAL_LPFD_ADJ_UNUSED; + _regs.fcal_hpfd_adj = lmx2592_regs_t::fcal_hpfd_adj_t::FCAL_HPFD_ADJ_200MHZ; + _regs.pfd_ctl = lmx2592_regs_t::pfd_ctl_t::PFD_CTL_SINGLE_PFD; + } + } + // "k" is a derived value that indicates where sub-fractional spurs will be present // at a given Fden value. A "k" value of 1 indicates there will be no spurs. // See the LMX2592 datasheet for more information -- cgit v1.2.3