diff options
| author | Derek Kozel <derek.kozel@ettus.com> | 2017-12-07 18:04:36 +0000 | 
|---|---|---|
| committer | Martin Braun <martin.braun@ettus.com> | 2017-12-08 12:07:52 -0800 | 
| commit | 85a707d7fff008e15e8f83c66dbbe253d6093479 (patch) | |
| tree | 2f98f8f240b06a713a053cf44067d54b75b3876b /host/lib/usrp/common/adf5355.cpp | |
| parent | 298a13ac3d9f9e785bf031e85060569541ca4b6f (diff) | |
| download | uhd-85a707d7fff008e15e8f83c66dbbe253d6093479.tar.gz uhd-85a707d7fff008e15e8f83c66dbbe253d6093479.tar.bz2 uhd-85a707d7fff008e15e8f83c66dbbe253d6093479.zip | |
TwinRX: Added ADF5356 synth and TwinRX Rev C support
ADF5355 and ADF5356 support merged into adf535x class
Default register values moved into regmap
Reviewed-By: Martin Braun <martin.braun@ettus.com>
Reviewed-By: Ashish Chaudhari <ashish@ettus.com>
Reviewed-By: Mark Meserve <mark.meserve@ni.com>
Diffstat (limited to 'host/lib/usrp/common/adf5355.cpp')
| -rw-r--r-- | host/lib/usrp/common/adf5355.cpp | 354 | 
1 files changed, 0 insertions, 354 deletions
| diff --git a/host/lib/usrp/common/adf5355.cpp b/host/lib/usrp/common/adf5355.cpp deleted file mode 100644 index 36d41a5c3..000000000 --- a/host/lib/usrp/common/adf5355.cpp +++ /dev/null @@ -1,354 +0,0 @@ -// -// Copyright 2013-2014 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program.  If not, see <http://www.gnu.org/licenses/>. -// - -#include "adf5355.hpp" -#include "adf5355_regs.hpp" -#include <uhd/utils/math.hpp> -#include <boost/math/common_factor_rt.hpp> //gcd -#include <boost/thread.hpp> - -using namespace uhd; - -template<typename data_t> -data_t clamp(data_t val, data_t min, data_t max) { -    return (val < min) ? min : ((val > max) ? max : val); -} - -template<typename data_t> -double todbl(data_t val) { -    return static_cast<double>(val); -} - -static const double ADF5355_DOUBLER_MAX_REF_FREQ    = 60e6; -//static const double ADF5355_MAX_FREQ_PFD            = 125e6; -//static const double ADF5355_PRESCALER_THRESH        = 7e9; - -static const double ADF5355_MIN_VCO_FREQ            = 3.4e9; -//static const double ADF5355_MAX_VCO_FREQ            = 6.8e9; -static const double ADF5355_MAX_OUT_FREQ            = 6.8e9; -static const double ADF5355_MIN_OUT_FREQ            = (3.4e9 / 64); -//static const double ADF5355_MAX_OUTB_FREQ           = (6.8e9 * 2); -//static const double ADF5355_MIN_OUTB_FREQ           = (3.4e9 * 2); - -static const double ADF5355_PHASE_RESYNC_TIME       = 400e-6; - -static const uint32_t ADF5355_MOD1           = 16777216; -static const uint32_t ADF5355_MAX_MOD2       = 16383; -static const uint32_t ADF5355_MAX_FRAC2      = 16383; -//static const uint16_t ADF5355_MIN_INT_PRESCALER_89 = 75; - -class adf5355_impl : public adf5355_iface -{ -public: -    adf5355_impl(write_fn_t write_fn) : -        _write_fn(write_fn), -        _regs(), -        _rewrite_regs(true), -        _wait_time_us(0), -        _ref_freq(0.0), -        _pfd_freq(0.0), -        _fb_after_divider(false) -    { - -        // TODO This is a hardware specific value, but can be made the default in the ic_reg_map -        _regs.charge_pump_current = adf5355_regs_t::CHARGE_PUMP_CURRENT_0_94MA; - -        // TODO cleanup these magic numbers -        _regs.cp_bleed_current = 2; -        _regs.r_counter_10_bit = 8; - -        _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 = adf5355_regs_t::ADC_CONVERSION_ENABLED; -        _regs.adc_enable = adf5355_regs_t::ADC_ENABLE_ENABLED; - - -        // TODO Needs to be enabled for phase resync -        _regs.phase_resync = adf5355_regs_t::PHASE_RESYNC_DISABLED; - -        // TODO Default should be divided, but there seems to be a bug preventing that. Needs rechecking -        _regs.feedback_select = adf5355_regs_t::FEEDBACK_SELECT_FUNDAMENTAL; -         -        // TODO 0 is an invalid value for this field. Setting to 1 seemed to break phase sync, needs retesting. -        _regs.phase_resync_clk_div = 0; -    } - -    ~adf5355_impl() -    { -        _regs.power_down = adf5355_regs_t::POWER_DOWN_ENABLED; -        commit(); -    } - -    void set_feedback_select(feedback_sel_t fb_sel) -    { -        _fb_after_divider = (fb_sel == FB_SEL_DIVIDED); - -        if (_fb_after_divider) { -            _regs.feedback_select = adf5355_regs_t::FEEDBACK_SELECT_DIVIDED; -        } else { -            _regs.feedback_select = adf5355_regs_t::FEEDBACK_SELECT_FUNDAMENTAL; -        } -    } - -    void set_reference_freq(double fref, bool force = false) -    { -        //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 - -        //Reference doubler for 50% duty cycle -        bool doubler_en = (_ref_freq <= ADF5355_DOUBLER_MAX_REF_FREQ); - -        /* Calculate and maximize PFD frequency */ -        // TODO Target PFD should be configurable -        /* TwinRX requires PFD of 6.25 MHz or less */ -        const double TWINRX_PFD_FREQ = 6.25e6; -        _pfd_freq = TWINRX_PFD_FREQ; - -        int ref_div_factor = 16; - -        //Reference divide-by-2 for 50% duty cycle -        // if R even, move one divide by 2 to to regs.reference_divide_by_2 -        bool div2_en = (ref_div_factor % 2 == 0); -        if (div2_en) { -            ref_div_factor /= 2; -        } - -        _regs.reference_divide_by_2 = div2_en ? -            adf5355_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED : -            adf5355_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED; -        _regs.reference_doubler = doubler_en ? -            adf5355_regs_t::REFERENCE_DOUBLER_ENABLED : -            adf5355_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 = clamp<uint16_t>( -            static_cast<uint16_t>(ceil(_pfd_freq / (20e3 * 30))), 1, 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 = -            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 ADC delay (code from ADI driver) -        _regs.adc_enable = adf5355_regs_t::ADC_ENABLE_ENABLED; -        _regs.adc_conversion = adf5355_regs_t::ADC_CONVERSION_ENABLED; -        _regs.adc_clock_divider = clamp<uint8_t>( -            static_cast<uint8_t>(ceil(((_pfd_freq / 100e3) - 2) / 4)), 1, 255); -        _wait_time_us = static_cast<uint32_t>( -            ceil(16e6 / (_pfd_freq / ((4 * _regs.adc_clock_divider) + 2)))); - -        //----------------------------------------------------------- -        //Phase resync -        // TODO Renable here, in initialization, or through separate set_phase_resync(bool enable) function -        _regs.phase_resync = adf5355_regs_t::PHASE_RESYNC_DISABLED; - -        _regs.phase_adjust = adf5355_regs_t::PHASE_ADJUST_DISABLED; -        _regs.sd_load_reset = adf5355_regs_t::SD_LOAD_RESET_ON_REG0_UPDATE; -        _regs.phase_resync_clk_div = static_cast<uint16_t>( -            floor(ADF5355_PHASE_RESYNC_TIME * _pfd_freq)); - -        _rewrite_regs = true; -    } - -    void set_output_power(output_power_t power) -    { -        adf5355_regs_t::output_power_t setting; -        switch (power) { -            case OUTPUT_POWER_M4DBM: setting = adf5355_regs_t::OUTPUT_POWER_M4DBM; break; -            case OUTPUT_POWER_M1DBM: setting = adf5355_regs_t::OUTPUT_POWER_M1DBM; break; -            case OUTPUT_POWER_2DBM:  setting = adf5355_regs_t::OUTPUT_POWER_2DBM; break; -            case OUTPUT_POWER_5DBM:  setting = adf5355_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(output_t output, bool enable) { - -        switch (output) { -            case RF_OUTPUT_A: _regs.rf_out_a_enabled = enable ? adf5355_regs_t::RF_OUT_A_ENABLED_ENABLED : -                                                                adf5355_regs_t::RF_OUT_A_ENABLED_DISABLED; -                              break; -            case RF_OUTPUT_B: _regs.rf_out_b_enabled = enable ? adf5355_regs_t::RF_OUT_B_ENABLED_ENABLED : -                                                                adf5355_regs_t::RF_OUT_B_ENABLED_DISABLED; -                              break; -        } -    } - -    void set_muxout_mode(muxout_t mode) -    { -        switch (mode) { -            case MUXOUT_3STATE: _regs.muxout = adf5355_regs_t::MUXOUT_3STATE; break; -            case MUXOUT_DVDD:   _regs.muxout = adf5355_regs_t::MUXOUT_DVDD; break; -            case MUXOUT_DGND:   _regs.muxout = adf5355_regs_t::MUXOUT_DGND; break; -            case MUXOUT_RDIV:   _regs.muxout = adf5355_regs_t::MUXOUT_RDIV; break; -            case MUXOUT_NDIV:   _regs.muxout = adf5355_regs_t::MUXOUT_NDIV; break; -            case MUXOUT_ALD:    _regs.muxout = adf5355_regs_t::MUXOUT_ANALOG_LD; break; -            case MUXOUT_DLD:    _regs.muxout = adf5355_regs_t::MUXOUT_DLD; break; -            default: UHD_THROW_INVALID_CODE_PATH(); -        } -    } - -    double set_frequency(double target_freq, double freq_resolution, bool flush = false) -    { -        if (target_freq > ADF5355_MAX_OUT_FREQ or target_freq < ADF5355_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 < ADF5355_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; -        } - -        double N = prescaler_input_freq / _pfd_freq; -        uint16_t INT = static_cast<uint16_t>(floor(N)); -        uint32_t FRAC1 = static_cast<uint32_t>(floor((N - INT) * ADF5355_MOD1)); -        double residue = (N - INT) * ADF5355_MOD1 - FRAC1; - -        double gcd = boost::math::gcd(static_cast<int>(_pfd_freq), static_cast<int>(freq_resolution)); -        uint16_t MOD2 = static_cast<uint16_t>(std::min(floor(_pfd_freq / gcd), static_cast<double>(ADF5355_MAX_MOD2))); -        uint16_t FRAC2 = static_cast<uint16_t>(std::min(ceil(residue * MOD2), static_cast<double>(ADF5355_MAX_FRAC2))); - -        double coerced_vco_freq = _pfd_freq * ( -            todbl(INT) + ( -                (todbl(FRAC1) + -                    (todbl(FRAC2) / todbl(MOD2))) -                / todbl(ADF5355_MOD1) -            ) -        ); - -        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 (_regs.int_16_bit >= ADF5355_MIN_INT_PRESCALER_89) { -            _regs.prescaler = adf5355_regs_t::PRESCALER_8_9; -        } else { -            _regs.prescaler = adf5355_regs_t::PRESCALER_4_5; -        } - -        // ADI: Tests have shown that the optimal bleed set is the following: -        // 4/N < IBLEED/ICP < 10/N */ -/* -        uint32_t cp_curr_ua = -            (static_cast<uint32_t>(_regs.charge_pump_current) + 1) * 315; -        _regs.cp_bleed_current = clamp<uint8_t>( -            ceil((todbl(400)*cp_curr_ua) / (_regs.int_16_bit*375)), 1, 255); -        _regs.negative_bleed = adf5355_regs_t::NEGATIVE_BLEED_ENABLED; -        _regs.gated_bleed = adf5355_regs_t::GATED_BLEED_DISABLED; -*/ - -        if (flush) commit(); -        return coerced_out_freq; -    } - -    void commit() -    { -        if (_rewrite_regs) { -            //For a full state sync write registers in reverse order 12 - 0 -            addr_vtr_t regs; -            for (int addr = 12; addr >= 0; addr--) { -                regs.push_back(_regs.get_reg(uint32_t(addr))); -            } -            _write_fn(regs); -            _rewrite_regs = false; - -        } else { -            //Frequency update sequence from data sheet -            static const size_t ONE_REG = 1; -            _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))); -            boost::this_thread::sleep(boost::posix_time::microsec(_wait_time_us)); -            _regs.autocal_en = adf5355_regs_t::AUTOCAL_EN_ENABLED; -            _write_fn(addr_vtr_t(ONE_REG, _regs.get_reg(0))); -        } -    } - -private: //Members -    typedef std::vector<uint32_t> addr_vtr_t; - -    write_fn_t      _write_fn; -    adf5355_regs_t  _regs; -    bool            _rewrite_regs; -    uint32_t _wait_time_us; -    double          _ref_freq; -    double          _pfd_freq; -    double          _fb_after_divider; -}; - -adf5355_iface::sptr adf5355_iface::make(write_fn_t write) -{ -    return sptr(new adf5355_impl(write)); -} | 
