diff options
Diffstat (limited to 'host/lib/include')
-rw-r--r-- | host/lib/include/uhdlib/usrp/common/adf535x.hpp | 814 | ||||
-rw-r--r-- | host/lib/include/uhdlib/usrp/common/lmx2592.hpp | 6 |
2 files changed, 450 insertions, 370 deletions
diff --git a/host/lib/include/uhdlib/usrp/common/adf535x.hpp b/host/lib/include/uhdlib/usrp/common/adf535x.hpp index 39dfb4b2a..200610d02 100644 --- a/host/lib/include/uhdlib/usrp/common/adf535x.hpp +++ b/host/lib/include/uhdlib/usrp/common/adf535x.hpp @@ -9,16 +9,16 @@ #include "adf5355_regs.hpp" #include "adf5356_regs.hpp" -#include <uhd/utils/math.hpp> #include <uhd/utils/log.hpp> +#include <uhd/utils/math.hpp> +#include <uhd/utils/safe_call.hpp> +#include <stdint.h> +#include <boost/format.hpp> #include <boost/function.hpp> #include <boost/math/common_factor_rt.hpp> //gcd +#include <algorithm> #include <utility> #include <vector> -#include <algorithm> -#include <stdint.h> -#include <boost/format.hpp> -#include <uhd/utils/safe_call.hpp> class adf535x_iface { @@ -36,9 +36,22 @@ public: enum feedback_sel_t { FB_SEL_FUNDAMENTAL, FB_SEL_DIVIDED }; - enum output_power_t { OUTPUT_POWER_M4DBM, OUTPUT_POWER_M1DBM, OUTPUT_POWER_2DBM, OUTPUT_POWER_5DBM }; - - enum muxout_t { MUXOUT_3STATE, MUXOUT_DVDD, MUXOUT_DGND, MUXOUT_RDIV, MUXOUT_NDIV, MUXOUT_ALD, MUXOUT_DLD }; + enum output_power_t { + OUTPUT_POWER_M4DBM, + OUTPUT_POWER_M1DBM, + OUTPUT_POWER_2DBM, + OUTPUT_POWER_5DBM + }; + + enum muxout_t { + MUXOUT_3STATE, + MUXOUT_DVDD, + MUXOUT_DGND, + MUXOUT_RDIV, + MUXOUT_NDIV, + MUXOUT_ALD, + MUXOUT_DLD + }; virtual void set_reference_freq(double fref, bool force = false) = 0; @@ -52,7 +65,8 @@ public: virtual void set_muxout_mode(muxout_t mode) = 0; - virtual double set_frequency(double target_freq, double freq_resolution, bool flush = false) = 0; + virtual double set_frequency( + double target_freq, double freq_resolution, bool flush = false) = 0; virtual void commit() = 0; }; @@ -60,405 +74,471 @@ public: using namespace uhd; namespace { - const double ADF535X_DOUBLER_MAX_REF_FREQ = 60e6; - const double ADF535X_MAX_FREQ_PFD = 125e6; -//const double ADF535X_PRESCALER_THRESH = 7e9; - - const double ADF535X_MIN_VCO_FREQ = 3.4e9; -//const double ADF535X_MAX_VCO_FREQ = 6.8e9; - const double ADF535X_MAX_OUT_FREQ = 6.8e9; - const double ADF535X_MIN_OUT_FREQ = (3.4e9 / 64); -//const double ADF535X_MAX_OUTB_FREQ = (6.8e9 * 2); -//const double ADF535X_MIN_OUTB_FREQ = (3.4e9 * 2); - - const double ADF535X_PHASE_RESYNC_TIME = 400e-6; - - const uint32_t ADF535X_MOD1 = 16777216; - const uint32_t ADF535X_MAX_MOD2 = 16383; - const uint32_t ADF535X_MAX_FRAC2 = 16383; -//const uint16_t ADF535X_MIN_INT_PRESCALER_89 = 75; -} - -template <typename adf535x_regs_t> -class adf535x_impl : public adf535x_iface +const double ADF535X_DOUBLER_MAX_REF_FREQ = 60e6; +const double ADF535X_MAX_FREQ_PFD = 125e6; +// const double ADF535X_PRESCALER_THRESH = 7e9; + +const double ADF535X_MIN_VCO_FREQ = 3.4e9; +// const double ADF535X_MAX_VCO_FREQ = 6.8e9; +const double ADF535X_MAX_OUT_FREQ = 6.8e9; +const double ADF535X_MIN_OUT_FREQ = (3.4e9 / 64); +// const double ADF535X_MAX_OUTB_FREQ = (6.8e9 * 2); +// const double ADF535X_MIN_OUTB_FREQ = (3.4e9 * 2); + +const double ADF535X_PHASE_RESYNC_TIME = 400e-6; + +const uint32_t ADF535X_MOD1 = 16777216; +const uint32_t ADF535X_MAX_MOD2 = 16383; +const uint32_t ADF535X_MAX_FRAC2 = 16383; +// const uint16_t ADF535X_MIN_INT_PRESCALER_89 = 75; +} // namespace + +template <typename adf535x_regs_t> class adf535x_impl : public adf535x_iface { public: - explicit adf535x_impl(write_fn_t write_fn, wait_fn_t wait_fn) : - _write_fn(std::move(write_fn)), - _wait_fn(std::move(wait_fn)), - _regs(), - _rewrite_regs(true), - _wait_time_us(0), - _ref_freq(0.0), - _pfd_freq(0.0), - _fb_after_divider(true) - { - - _regs.vco_band_div = 3; - _regs.timeout = 11; - _regs.auto_level_timeout = 30; - _regs.synth_lock_timeout = 12; - - _regs.adc_clock_divider = 16; - _regs.adc_conversion = adf535x_regs_t::ADC_CONVERSION_ENABLED; - _regs.adc_enable = adf535x_regs_t::ADC_ENABLE_ENABLED; - - // Start with phase resync disabled and enable when reference clock is set - _regs.phase_resync = adf535x_regs_t::PHASE_RESYNC_DISABLED; - - set_feedback_select(FB_SEL_DIVIDED); - } - - ~adf535x_impl() override - { - UHD_SAFE_CALL( - _regs.power_down = adf535x_regs_t::POWER_DOWN_ENABLED; - commit(); - ) - } - - void set_feedback_select(const feedback_sel_t fb_sel) override - { - _fb_after_divider = (fb_sel == FB_SEL_DIVIDED); - - if (_fb_after_divider) { - _regs.feedback_select = adf535x_regs_t::FEEDBACK_SELECT_DIVIDED; - } else { - _regs.feedback_select = adf535x_regs_t::FEEDBACK_SELECT_FUNDAMENTAL; + explicit adf535x_impl(write_fn_t write_fn, wait_fn_t wait_fn) + : _write_fn(std::move(write_fn)) + , _wait_fn(std::move(wait_fn)) + , _regs() + , _rewrite_regs(true) + , _wait_time_us(0) + , _ref_freq(0.0) + , _pfd_freq(0.0) + , _fb_after_divider(true) + { + _regs.vco_band_div = 3; + _regs.timeout = 11; + _regs.auto_level_timeout = 30; + _regs.synth_lock_timeout = 12; + + _regs.adc_clock_divider = 16; + _regs.adc_conversion = adf535x_regs_t::ADC_CONVERSION_ENABLED; + _regs.adc_enable = adf535x_regs_t::ADC_ENABLE_ENABLED; + + // Start with phase resync disabled and enable when reference clock is set + _regs.phase_resync = adf535x_regs_t::PHASE_RESYNC_DISABLED; + + set_feedback_select(FB_SEL_DIVIDED); } - } - - void set_pfd_freq(const double pfd_freq) override - { - if (pfd_freq > ADF535X_MAX_FREQ_PFD) { - UHD_LOGGER_ERROR("ADF535x") << boost::format("%f MHz is above the maximum PFD frequency of %f MHz\n") - % (pfd_freq/1e6) % (ADF535X_MAX_FREQ_PFD/1e6); - return; - } - _pfd_freq = pfd_freq; - - set_reference_freq(_ref_freq); - } - void set_reference_freq(const double fref, const bool force = false) override - { - //Skip the body if the reference frequency does not change - if (uhd::math::frequencies_are_equal(fref, _ref_freq) and (not force)) - return; - - _ref_freq = fref; + ~adf535x_impl() override + { + UHD_SAFE_CALL(_regs.power_down = adf535x_regs_t::POWER_DOWN_ENABLED; commit();) + } - //----------------------------------------------------------- - //Set reference settings - int ref_div_factor = static_cast<int>(std::floor(_ref_freq / _pfd_freq)); + void set_feedback_select(const feedback_sel_t fb_sel) override + { + _fb_after_divider = (fb_sel == FB_SEL_DIVIDED); - //Reference doubler for 50% duty cycle - const bool doubler_en = (_ref_freq <= ADF535X_DOUBLER_MAX_REF_FREQ); - if (doubler_en) { - ref_div_factor *= 2; + if (_fb_after_divider) { + _regs.feedback_select = adf535x_regs_t::FEEDBACK_SELECT_DIVIDED; + } else { + _regs.feedback_select = adf535x_regs_t::FEEDBACK_SELECT_FUNDAMENTAL; + } } - //Reference divide-by-2 for 50% duty cycle - // if R even, move one divide by 2 to regs.reference_divide_by_2 - const bool div2_en = (ref_div_factor % 2 == 0); - if (div2_en) { - ref_div_factor /= 2; + void set_pfd_freq(const double pfd_freq) override + { + if (pfd_freq > ADF535X_MAX_FREQ_PFD) { + UHD_LOGGER_ERROR("ADF535x") + << boost::format("%f MHz is above the maximum PFD frequency of %f MHz\n") + % (pfd_freq / 1e6) % (ADF535X_MAX_FREQ_PFD / 1e6); + return; + } + _pfd_freq = pfd_freq; + + set_reference_freq(_ref_freq); } - _regs.reference_divide_by_2 = div2_en ? - adf535x_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED : - adf535x_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED; - _regs.reference_doubler = doubler_en ? - adf535x_regs_t::REFERENCE_DOUBLER_ENABLED : - adf535x_regs_t::REFERENCE_DOUBLER_DISABLED; - _regs.r_counter_10_bit = ref_div_factor; - UHD_ASSERT_THROW((_regs.r_counter_10_bit & ((uint16_t)~0x3FF)) == 0); - - //----------------------------------------------------------- - //Set timeouts (code from ADI driver) - _regs.timeout = std::max(1, std::min(int(ceil(_pfd_freq / (20e3 * 30))), 1023)); - - UHD_ASSERT_THROW((_regs.timeout & ((uint16_t)~0x3FF)) == 0); - _regs.synth_lock_timeout = + void set_reference_freq(const double fref, const bool force = false) override + { + // Skip the body if the reference frequency does not change + if (uhd::math::frequencies_are_equal(fref, _ref_freq) and (not force)) + return; + + _ref_freq = fref; + + //----------------------------------------------------------- + // Set reference settings + int ref_div_factor = static_cast<int>(std::floor(_ref_freq / _pfd_freq)); + + // Reference doubler for 50% duty cycle + const bool doubler_en = (_ref_freq <= ADF535X_DOUBLER_MAX_REF_FREQ); + if (doubler_en) { + ref_div_factor *= 2; + } + + // Reference divide-by-2 for 50% duty cycle + // if R even, move one divide by 2 to regs.reference_divide_by_2 + const bool div2_en = (ref_div_factor % 2 == 0); + if (div2_en) { + ref_div_factor /= 2; + } + + _regs.reference_divide_by_2 = + div2_en ? adf535x_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED + : adf535x_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED; + _regs.reference_doubler = doubler_en ? adf535x_regs_t::REFERENCE_DOUBLER_ENABLED + : adf535x_regs_t::REFERENCE_DOUBLER_DISABLED; + _regs.r_counter_10_bit = ref_div_factor; + UHD_ASSERT_THROW((_regs.r_counter_10_bit & ((uint16_t)~0x3FF)) == 0); + + //----------------------------------------------------------- + // Set timeouts (code from ADI driver) + _regs.timeout = std::max(1, std::min(int(ceil(_pfd_freq / (20e3 * 30))), 1023)); + + UHD_ASSERT_THROW((_regs.timeout & ((uint16_t)~0x3FF)) == 0); + _regs.synth_lock_timeout = static_cast<uint8_t>(ceil((_pfd_freq * 2) / (100e3 * _regs.timeout))); - UHD_ASSERT_THROW((_regs.synth_lock_timeout & ((uint16_t)~0x1F)) == 0); - _regs.auto_level_timeout = + UHD_ASSERT_THROW((_regs.synth_lock_timeout & ((uint16_t)~0x1F)) == 0); + _regs.auto_level_timeout = static_cast<uint8_t>(ceil((_pfd_freq * 5) / (100e3 * _regs.timeout))); - //----------------------------------------------------------- - //Set VCO band divider - _regs.vco_band_div = - static_cast<uint8_t>(ceil(_pfd_freq / 2.4e6)); + //----------------------------------------------------------- + // Set VCO band divider + _regs.vco_band_div = static_cast<uint8_t>(ceil(_pfd_freq / 2.4e6)); - //----------------------------------------------------------- - //Set ADC delay (code from ADI driver) - _regs.adc_enable = adf535x_regs_t::ADC_ENABLE_ENABLED; - _regs.adc_conversion = adf535x_regs_t::ADC_CONVERSION_ENABLED; - _regs.adc_clock_divider = std::max(1, std::min(int(ceil(((_pfd_freq / 100e3) - 2) / 4)),255)); + //----------------------------------------------------------- + // Set ADC delay (code from ADI driver) + _regs.adc_enable = adf535x_regs_t::ADC_ENABLE_ENABLED; + _regs.adc_conversion = adf535x_regs_t::ADC_CONVERSION_ENABLED; + _regs.adc_clock_divider = + std::max(1, std::min(int(ceil(((_pfd_freq / 100e3) - 2) / 4)), 255)); - _wait_time_us = static_cast<uint32_t>( + _wait_time_us = static_cast<uint32_t>( ceil(16e6 / (_pfd_freq / ((4 * _regs.adc_clock_divider) + 2)))); - //----------------------------------------------------------- - //Phase resync - _regs.phase_resync = adf535x_regs_t::PHASE_RESYNC_ENABLED; - - _regs.phase_adjust = adf535x_regs_t::PHASE_ADJUST_DISABLED; - _regs.sd_load_reset = adf535x_regs_t::SD_LOAD_RESET_ON_REG0_UPDATE; - _regs.phase_resync_clk_div = static_cast<uint16_t>( - floor(ADF535X_PHASE_RESYNC_TIME * _pfd_freq)); - - _rewrite_regs = true; - } - - double set_frequency(const double target_freq, const double freq_resolution, const bool flush = false) override - { - return _set_frequency(target_freq, freq_resolution, flush); - } - - void set_output_power(const output_power_t power) override - { - typename adf535x_regs_t::output_power_t setting; - switch (power) { - case OUTPUT_POWER_M4DBM: setting = adf535x_regs_t::OUTPUT_POWER_M4DBM; break; - case OUTPUT_POWER_M1DBM: setting = adf535x_regs_t::OUTPUT_POWER_M1DBM; break; - case OUTPUT_POWER_2DBM: setting = adf535x_regs_t::OUTPUT_POWER_2DBM; break; - case OUTPUT_POWER_5DBM: setting = adf535x_regs_t::OUTPUT_POWER_5DBM; break; - default: UHD_THROW_INVALID_CODE_PATH(); + //----------------------------------------------------------- + // Phase resync + _regs.phase_resync = adf535x_regs_t::PHASE_RESYNC_ENABLED; + + _regs.phase_adjust = adf535x_regs_t::PHASE_ADJUST_DISABLED; + _regs.sd_load_reset = adf535x_regs_t::SD_LOAD_RESET_ON_REG0_UPDATE; + _regs.phase_resync_clk_div = + static_cast<uint16_t>(floor(ADF535X_PHASE_RESYNC_TIME * _pfd_freq)); + + _rewrite_regs = true; + } + + double set_frequency(const double target_freq, + const double freq_resolution, + const bool flush = false) override + { + return _set_frequency(target_freq, freq_resolution, flush); } - if (_regs.output_power != setting) _rewrite_regs = true; - _regs.output_power = setting; - } - - void set_output_enable(const output_t output, const bool enable) override - { - switch (output) { - case RF_OUTPUT_A: _regs.rf_out_a_enabled = enable ? adf535x_regs_t::RF_OUT_A_ENABLED_ENABLED : - adf535x_regs_t::RF_OUT_A_ENABLED_DISABLED; - break; - case RF_OUTPUT_B: _regs.rf_out_b_enabled = enable ? adf535x_regs_t::RF_OUT_B_ENABLED_ENABLED : - adf535x_regs_t::RF_OUT_B_ENABLED_DISABLED; - break; + + void set_output_power(const output_power_t power) override + { + typename adf535x_regs_t::output_power_t setting; + switch (power) { + case OUTPUT_POWER_M4DBM: + setting = adf535x_regs_t::OUTPUT_POWER_M4DBM; + break; + case OUTPUT_POWER_M1DBM: + setting = adf535x_regs_t::OUTPUT_POWER_M1DBM; + break; + case OUTPUT_POWER_2DBM: + setting = adf535x_regs_t::OUTPUT_POWER_2DBM; + break; + case OUTPUT_POWER_5DBM: + setting = adf535x_regs_t::OUTPUT_POWER_5DBM; + break; + default: + UHD_THROW_INVALID_CODE_PATH(); + } + if (_regs.output_power != setting) + _rewrite_regs = true; + _regs.output_power = setting; + } + + void set_output_enable(const output_t output, const bool enable) override + { + switch (output) { + case RF_OUTPUT_A: + _regs.rf_out_a_enabled = enable + ? adf535x_regs_t::RF_OUT_A_ENABLED_ENABLED + : adf535x_regs_t::RF_OUT_A_ENABLED_DISABLED; + break; + case RF_OUTPUT_B: + _regs.rf_out_b_enabled = enable + ? adf535x_regs_t::RF_OUT_B_ENABLED_ENABLED + : adf535x_regs_t::RF_OUT_B_ENABLED_DISABLED; + break; + } } - } - - void set_muxout_mode(const muxout_t mode) override - { - switch (mode) { - case MUXOUT_3STATE: _regs.muxout = adf535x_regs_t::MUXOUT_3STATE; break; - case MUXOUT_DVDD: _regs.muxout = adf535x_regs_t::MUXOUT_DVDD; break; - case MUXOUT_DGND: _regs.muxout = adf535x_regs_t::MUXOUT_DGND; break; - case MUXOUT_RDIV: _regs.muxout = adf535x_regs_t::MUXOUT_RDIV; break; - case MUXOUT_NDIV: _regs.muxout = adf535x_regs_t::MUXOUT_NDIV; break; - case MUXOUT_ALD: _regs.muxout = adf535x_regs_t::MUXOUT_ANALOG_LD; break; - case MUXOUT_DLD: _regs.muxout = adf535x_regs_t::MUXOUT_DLD; break; - default: UHD_THROW_INVALID_CODE_PATH(); + + void set_muxout_mode(const muxout_t mode) override + { + switch (mode) { + case MUXOUT_3STATE: + _regs.muxout = adf535x_regs_t::MUXOUT_3STATE; + break; + case MUXOUT_DVDD: + _regs.muxout = adf535x_regs_t::MUXOUT_DVDD; + break; + case MUXOUT_DGND: + _regs.muxout = adf535x_regs_t::MUXOUT_DGND; + break; + case MUXOUT_RDIV: + _regs.muxout = adf535x_regs_t::MUXOUT_RDIV; + break; + case MUXOUT_NDIV: + _regs.muxout = adf535x_regs_t::MUXOUT_NDIV; + break; + case MUXOUT_ALD: + _regs.muxout = adf535x_regs_t::MUXOUT_ANALOG_LD; + break; + case MUXOUT_DLD: + _regs.muxout = adf535x_regs_t::MUXOUT_DLD; + break; + default: + UHD_THROW_INVALID_CODE_PATH(); + } } - } - void commit() override - { - _commit(); - } + void commit() override + { + _commit(); + } protected: - double _set_frequency(double, double, bool); - void _commit(); - -private: //Members - typedef std::vector<uint32_t> addr_vtr_t; - - write_fn_t _write_fn; - wait_fn_t _wait_fn; - adf535x_regs_t _regs; - bool _rewrite_regs; - uint32_t _wait_time_us; - double _ref_freq; - double _pfd_freq; - double _fb_after_divider; + double _set_frequency(double, double, bool); + void _commit(); + +private: // Members + typedef std::vector<uint32_t> addr_vtr_t; + + write_fn_t _write_fn; + wait_fn_t _wait_fn; + adf535x_regs_t _regs; + bool _rewrite_regs; + uint32_t _wait_time_us; + double _ref_freq; + double _pfd_freq; + double _fb_after_divider; }; // ADF5355 Functions template <> -inline double adf535x_impl<adf5355_regs_t>::_set_frequency(double target_freq, double freq_resolution, bool flush) +inline double adf535x_impl<adf5355_regs_t>::_set_frequency( + double target_freq, double freq_resolution, bool flush) { - if (target_freq > ADF535X_MAX_OUT_FREQ or target_freq < ADF535X_MIN_OUT_FREQ) { - throw uhd::runtime_error("requested frequency out of range."); - } - if ((uint32_t) freq_resolution == 0) { - throw uhd::runtime_error("requested resolution cannot be less than 1."); - } - - /* Calculate target VCOout frequency */ - //Increase RF divider until acceptable VCO frequency - double target_vco_freq = target_freq; - uint32_t rf_divider = 1; - while (target_vco_freq < ADF535X_MIN_VCO_FREQ && rf_divider < 64) { - target_vco_freq *= 2; - rf_divider *= 2; - } - - switch (rf_divider) { - case 1: _regs.rf_divider_select = adf5355_regs_t::RF_DIVIDER_SELECT_DIV1; break; - case 2: _regs.rf_divider_select = adf5355_regs_t::RF_DIVIDER_SELECT_DIV2; break; - case 4: _regs.rf_divider_select = adf5355_regs_t::RF_DIVIDER_SELECT_DIV4; break; - case 8: _regs.rf_divider_select = adf5355_regs_t::RF_DIVIDER_SELECT_DIV8; break; - case 16: _regs.rf_divider_select = adf5355_regs_t::RF_DIVIDER_SELECT_DIV16; break; - case 32: _regs.rf_divider_select = adf5355_regs_t::RF_DIVIDER_SELECT_DIV32; break; - case 64: _regs.rf_divider_select = adf5355_regs_t::RF_DIVIDER_SELECT_DIV64; break; - default: UHD_THROW_INVALID_CODE_PATH(); - } - - //Compute fractional PLL params - double prescaler_input_freq = target_vco_freq; - if (_fb_after_divider) { - prescaler_input_freq /= rf_divider; - } - - const double N = prescaler_input_freq / _pfd_freq; - const auto INT = static_cast<uint16_t>(floor(N)); - const auto FRAC1 = static_cast<uint32_t>(floor((N - INT) * ADF535X_MOD1)); - const double residue = (N - INT) * ADF535X_MOD1 - FRAC1; - - const double gcd = boost::math::gcd(static_cast<int>(_pfd_freq), static_cast<int>(freq_resolution)); - const auto MOD2 = static_cast<uint16_t>(std::min(floor(_pfd_freq / gcd), static_cast<double>(ADF535X_MAX_MOD2))); - const auto FRAC2 = static_cast<uint16_t>(std::min(ceil(residue * MOD2), static_cast<double>(ADF535X_MAX_FRAC2))); - - const double coerced_vco_freq = _pfd_freq * - (_fb_after_divider ? rf_divider : 1) * - (double(INT) + ((double(FRAC1) + (double(FRAC2) / double(MOD2))) / - double(ADF535X_MOD1))); - - const double coerced_out_freq = coerced_vco_freq / rf_divider; - - /* Update registers */ - _regs.int_16_bit = INT; - _regs.frac1_24_bit = FRAC1; - _regs.frac2_14_bit = FRAC2; - _regs.mod2_14_bit = MOD2; - _regs.phase_24_bit = 0; - - if (flush) commit(); - return coerced_out_freq; + if (target_freq > ADF535X_MAX_OUT_FREQ or target_freq < ADF535X_MIN_OUT_FREQ) { + throw uhd::runtime_error("requested frequency out of range."); + } + if ((uint32_t)freq_resolution == 0) { + throw uhd::runtime_error("requested resolution cannot be less than 1."); + } + + /* Calculate target VCOout frequency */ + // Increase RF divider until acceptable VCO frequency + double target_vco_freq = target_freq; + uint32_t rf_divider = 1; + while (target_vco_freq < ADF535X_MIN_VCO_FREQ && rf_divider < 64) { + target_vco_freq *= 2; + rf_divider *= 2; + } + + switch (rf_divider) { + case 1: + _regs.rf_divider_select = adf5355_regs_t::RF_DIVIDER_SELECT_DIV1; + break; + case 2: + _regs.rf_divider_select = adf5355_regs_t::RF_DIVIDER_SELECT_DIV2; + break; + case 4: + _regs.rf_divider_select = adf5355_regs_t::RF_DIVIDER_SELECT_DIV4; + break; + case 8: + _regs.rf_divider_select = adf5355_regs_t::RF_DIVIDER_SELECT_DIV8; + break; + case 16: + _regs.rf_divider_select = adf5355_regs_t::RF_DIVIDER_SELECT_DIV16; + break; + case 32: + _regs.rf_divider_select = adf5355_regs_t::RF_DIVIDER_SELECT_DIV32; + break; + case 64: + _regs.rf_divider_select = adf5355_regs_t::RF_DIVIDER_SELECT_DIV64; + break; + default: + UHD_THROW_INVALID_CODE_PATH(); + } + + // Compute fractional PLL params + double prescaler_input_freq = target_vco_freq; + if (_fb_after_divider) { + prescaler_input_freq /= rf_divider; + } + + const double N = prescaler_input_freq / _pfd_freq; + const auto INT = static_cast<uint16_t>(floor(N)); + const auto FRAC1 = static_cast<uint32_t>(floor((N - INT) * ADF535X_MOD1)); + const double residue = (N - INT) * ADF535X_MOD1 - FRAC1; + + const double gcd = + boost::math::gcd(static_cast<int>(_pfd_freq), static_cast<int>(freq_resolution)); + const auto MOD2 = static_cast<uint16_t>( + std::min(floor(_pfd_freq / gcd), static_cast<double>(ADF535X_MAX_MOD2))); + const auto FRAC2 = static_cast<uint16_t>( + std::min(ceil(residue * MOD2), static_cast<double>(ADF535X_MAX_FRAC2))); + + const double coerced_vco_freq = + _pfd_freq * (_fb_after_divider ? rf_divider : 1) + * (double(INT) + + ((double(FRAC1) + (double(FRAC2) / double(MOD2))) + / double(ADF535X_MOD1))); + + const double coerced_out_freq = coerced_vco_freq / rf_divider; + + /* Update registers */ + _regs.int_16_bit = INT; + _regs.frac1_24_bit = FRAC1; + _regs.frac2_14_bit = FRAC2; + _regs.mod2_14_bit = MOD2; + _regs.phase_24_bit = 0; + + if (flush) + commit(); + return coerced_out_freq; } -template <> -inline void adf535x_impl<adf5355_regs_t>::_commit() +template <> inline void adf535x_impl<adf5355_regs_t>::_commit() { - const size_t ONE_REG = 1; - - if (_rewrite_regs) { - //For a full state sync write registers in reverse order 12 - 0 - addr_vtr_t regs; - for (uint8_t addr = 12; addr > 0; addr--) { - regs.push_back(_regs.get_reg(addr)); + const size_t ONE_REG = 1; + + if (_rewrite_regs) { + // For a full state sync write registers in reverse order 12 - 0 + addr_vtr_t regs; + for (uint8_t addr = 12; addr > 0; addr--) { + regs.push_back(_regs.get_reg(addr)); + } + _write_fn(regs); + _wait_fn(_wait_time_us); + _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(0))); + _rewrite_regs = false; + } else { + // Frequency update sequence from data sheet + _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(6))); + _regs.counter_reset = adf5355_regs_t::COUNTER_RESET_ENABLED; + _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(4))); + _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(2))); + _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(1))); + _regs.autocal_en = adf5355_regs_t::AUTOCAL_EN_DISABLED; + _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(0))); + _regs.counter_reset = adf5355_regs_t::COUNTER_RESET_DISABLED; + _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(4))); + _regs.autocal_en = adf5355_regs_t::AUTOCAL_EN_ENABLED; + _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(0))); } - _write_fn(regs); - _wait_fn(_wait_time_us); - _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(0))); - _rewrite_regs = false; - } else { - //Frequency update sequence from data sheet - _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(6))); - _regs.counter_reset = adf5355_regs_t::COUNTER_RESET_ENABLED; - _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(4))); - _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(2))); - _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(1))); - _regs.autocal_en = adf5355_regs_t::AUTOCAL_EN_DISABLED; - _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(0))); - _regs.counter_reset = adf5355_regs_t::COUNTER_RESET_DISABLED; - _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(4))); - _regs.autocal_en = adf5355_regs_t::AUTOCAL_EN_ENABLED; - _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(0))); - } } // ADF5356 Functions template <> -inline double adf535x_impl<adf5356_regs_t>::_set_frequency(double target_freq, double freq_resolution, bool flush) +inline double adf535x_impl<adf5356_regs_t>::_set_frequency( + double target_freq, double freq_resolution, bool flush) { - if (target_freq > ADF535X_MAX_OUT_FREQ or target_freq < ADF535X_MIN_OUT_FREQ) { - throw uhd::runtime_error("requested frequency out of range."); - } - if ((uint32_t) freq_resolution == 0) { - throw uhd::runtime_error("requested resolution cannot be less than 1."); - } - - /* Calculate target VCOout frequency */ - //Increase RF divider until acceptable VCO frequency - double target_vco_freq = target_freq; - uint32_t rf_divider = 1; - while (target_vco_freq < ADF535X_MIN_VCO_FREQ && rf_divider < 64) { - target_vco_freq *= 2; - rf_divider *= 2; - } - - switch (rf_divider) { - case 1: _regs.rf_divider_select = adf5356_regs_t::RF_DIVIDER_SELECT_DIV1; break; - case 2: _regs.rf_divider_select = adf5356_regs_t::RF_DIVIDER_SELECT_DIV2; break; - case 4: _regs.rf_divider_select = adf5356_regs_t::RF_DIVIDER_SELECT_DIV4; break; - case 8: _regs.rf_divider_select = adf5356_regs_t::RF_DIVIDER_SELECT_DIV8; break; - case 16: _regs.rf_divider_select = adf5356_regs_t::RF_DIVIDER_SELECT_DIV16; break; - case 32: _regs.rf_divider_select = adf5356_regs_t::RF_DIVIDER_SELECT_DIV32; break; - case 64: _regs.rf_divider_select = adf5356_regs_t::RF_DIVIDER_SELECT_DIV64; break; - default: UHD_THROW_INVALID_CODE_PATH(); - } - - //Compute fractional PLL params - double prescaler_input_freq = target_vco_freq; - if (_fb_after_divider) { - prescaler_input_freq /= rf_divider; - } - - const double N = prescaler_input_freq / _pfd_freq; - const auto INT = static_cast<uint16_t>(floor(N)); - const auto FRAC1 = static_cast<uint32_t>(floor((N - INT) * ADF535X_MOD1)); - const double residue = (N - INT) * ADF535X_MOD1 - FRAC1; - - const double gcd = boost::math::gcd(static_cast<int>(_pfd_freq), static_cast<int>(freq_resolution)); - const auto MOD2 = static_cast<uint16_t>(std::min(floor(_pfd_freq / gcd), static_cast<double>(ADF535X_MAX_MOD2))); - const auto FRAC2 = static_cast<uint16_t>(std::min(round(residue * MOD2), static_cast<double>(ADF535X_MAX_FRAC2))); - - const double coerced_vco_freq = _pfd_freq * - (_fb_after_divider ? rf_divider : 1) * - (double(INT) + ((double(FRAC1) + (double(FRAC2) / double(MOD2))) - / double(ADF535X_MOD1))); - - const double coerced_out_freq = coerced_vco_freq / rf_divider; - - /* Update registers */ - _regs.int_16_bit = INT; - _regs.frac1_24_bit = FRAC1; - _regs.frac2_msb = FRAC2; - _regs.mod2_msb = MOD2; - _regs.phase_24_bit = 0; - - if (flush) commit(); - return coerced_out_freq; + if (target_freq > ADF535X_MAX_OUT_FREQ or target_freq < ADF535X_MIN_OUT_FREQ) { + throw uhd::runtime_error("requested frequency out of range."); + } + if ((uint32_t)freq_resolution == 0) { + throw uhd::runtime_error("requested resolution cannot be less than 1."); + } + + /* Calculate target VCOout frequency */ + // Increase RF divider until acceptable VCO frequency + double target_vco_freq = target_freq; + uint32_t rf_divider = 1; + while (target_vco_freq < ADF535X_MIN_VCO_FREQ && rf_divider < 64) { + target_vco_freq *= 2; + rf_divider *= 2; + } + + switch (rf_divider) { + case 1: + _regs.rf_divider_select = adf5356_regs_t::RF_DIVIDER_SELECT_DIV1; + break; + case 2: + _regs.rf_divider_select = adf5356_regs_t::RF_DIVIDER_SELECT_DIV2; + break; + case 4: + _regs.rf_divider_select = adf5356_regs_t::RF_DIVIDER_SELECT_DIV4; + break; + case 8: + _regs.rf_divider_select = adf5356_regs_t::RF_DIVIDER_SELECT_DIV8; + break; + case 16: + _regs.rf_divider_select = adf5356_regs_t::RF_DIVIDER_SELECT_DIV16; + break; + case 32: + _regs.rf_divider_select = adf5356_regs_t::RF_DIVIDER_SELECT_DIV32; + break; + case 64: + _regs.rf_divider_select = adf5356_regs_t::RF_DIVIDER_SELECT_DIV64; + break; + default: + UHD_THROW_INVALID_CODE_PATH(); + } + + // Compute fractional PLL params + double prescaler_input_freq = target_vco_freq; + if (_fb_after_divider) { + prescaler_input_freq /= rf_divider; + } + + const double N = prescaler_input_freq / _pfd_freq; + const auto INT = static_cast<uint16_t>(floor(N)); + const auto FRAC1 = static_cast<uint32_t>(floor((N - INT) * ADF535X_MOD1)); + const double residue = (N - INT) * ADF535X_MOD1 - FRAC1; + + const double gcd = + boost::math::gcd(static_cast<int>(_pfd_freq), static_cast<int>(freq_resolution)); + const auto MOD2 = static_cast<uint16_t>( + std::min(floor(_pfd_freq / gcd), static_cast<double>(ADF535X_MAX_MOD2))); + const auto FRAC2 = static_cast<uint16_t>( + std::min(round(residue * MOD2), static_cast<double>(ADF535X_MAX_FRAC2))); + + const double coerced_vco_freq = + _pfd_freq * (_fb_after_divider ? rf_divider : 1) + * (double(INT) + + ((double(FRAC1) + (double(FRAC2) / double(MOD2))) + / double(ADF535X_MOD1))); + + const double coerced_out_freq = coerced_vco_freq / rf_divider; + + /* Update registers */ + _regs.int_16_bit = INT; + _regs.frac1_24_bit = FRAC1; + _regs.frac2_msb = FRAC2; + _regs.mod2_msb = MOD2; + _regs.phase_24_bit = 0; + + if (flush) + commit(); + return coerced_out_freq; } -template <> -inline void adf535x_impl<adf5356_regs_t>::_commit() +template <> inline void adf535x_impl<adf5356_regs_t>::_commit() { - const size_t ONE_REG = 1; - if (_rewrite_regs) { - //For a full state sync write registers in reverse order 12 - 0 - addr_vtr_t regs; - for (uint8_t addr = 13; addr > 0; addr--) { - regs.push_back(_regs.get_reg(addr)); + const size_t ONE_REG = 1; + if (_rewrite_regs) { + // For a full state sync write registers in reverse order 12 - 0 + addr_vtr_t regs; + for (uint8_t addr = 13; addr > 0; addr--) { + regs.push_back(_regs.get_reg(addr)); + } + _write_fn(regs); + _wait_fn(_wait_time_us); + _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(0))); + _rewrite_regs = false; + } else { + // Frequency update sequence from data sheet + _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(13))); + _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(6))); + _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(2))); + _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(1))); + _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(0))); } - _write_fn(regs); - _wait_fn(_wait_time_us); - _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(0))); - _rewrite_regs = false; - } else { - //Frequency update sequence from data sheet - _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(13))); - _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(6))); - _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(2))); - _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(1))); - _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(0))); - } } #endif // INCLUDED_ADF535X_HPP diff --git a/host/lib/include/uhdlib/usrp/common/lmx2592.hpp b/host/lib/include/uhdlib/usrp/common/lmx2592.hpp index 91beb24b7..f71ae0cf5 100644 --- a/host/lib/include/uhdlib/usrp/common/lmx2592.hpp +++ b/host/lib/include/uhdlib/usrp/common/lmx2592.hpp @@ -19,7 +19,8 @@ #include <utility> #include <vector> -class lmx2592_iface { +class lmx2592_iface +{ public: typedef std::shared_ptr<lmx2592_iface> sptr; @@ -37,8 +38,7 @@ public: enum mash_order_t { INT_N, FIRST, SECOND, THIRD, FOURTH }; - virtual double set_frequency( - double target_freq, + virtual double set_frequency(double target_freq, const bool spur_dodging, const double spur_dodging_threshold) = 0; |