diff options
Diffstat (limited to 'host/lib')
-rw-r--r-- | host/lib/usrp/usrp_e100/clock_ctrl.cpp | 123 | ||||
-rw-r--r-- | host/lib/usrp/usrp_e100/clock_ctrl.hpp | 7 |
2 files changed, 108 insertions, 22 deletions
diff --git a/host/lib/usrp/usrp_e100/clock_ctrl.cpp b/host/lib/usrp/usrp_e100/clock_ctrl.cpp index 1fb1a7125..4048218f2 100644 --- a/host/lib/usrp/usrp_e100/clock_ctrl.cpp +++ b/host/lib/usrp/usrp_e100/clock_ctrl.cpp @@ -18,10 +18,12 @@ #include "clock_ctrl.hpp" #include "ad9522_regs.hpp" #include <uhd/utils/assert.hpp> +#include <uhd/utils/static.hpp> #include <boost/cstdint.hpp> #include "usrp_e100_regs.hpp" //spi slave constants #include <boost/assign/list_of.hpp> #include <boost/foreach.hpp> +#include <boost/format.hpp> #include <utility> #include <iostream> @@ -36,6 +38,62 @@ template <typename div_type, typename bypass_type> static void set_clock_divider } /*********************************************************************** + * Clock rate calculation stuff: + * Using the internal VCO between 1400 and 1800 MHz + **********************************************************************/ +struct clock_settings_type{ + size_t ref_clock_doubler, r_counter, a_counter, b_counter, prescaler, vco_divider, clk_divider; + size_t get_n_counter(void) const{return prescaler * b_counter + a_counter;} + double get_ref_rate(void) const{return 10e6 * ref_clock_doubler;} + double get_vco_rate(void) const{return get_ref_rate()/r_counter * get_n_counter();} + double get_clk_rate(void) const{return get_vco_rate()/vco_divider;} + double get_out_rate(void) const{return get_clk_rate()/clk_divider;} + std::string to_pp_string(void) const{ + return str(boost::format( + " r_counter: %d\n" + " a_counter: %d\n" + " b_counter: %d\n" + " prescaler: %d\n" + " vco_divider: %d\n" + " clk_divider: %d\n" + " vco_rate: %fMHz\n" + " clk_rate: %fMHz\n" + " out_rate: %fMHz\n" + ) + % r_counter + % a_counter + % b_counter + % prescaler + % vco_divider + % clk_divider + % (get_vco_rate()/1e6) + % (get_clk_rate()/1e6) + % (get_out_rate()/1e6) + ); + } +}; + +UHD_SINGLETON_FCN(std::vector<clock_settings_type>, get_clock_settings); + +UHD_STATIC_BLOCK(libuhd_usrp_e100_reg_clock_rates){ + clock_settings_type cs; + cs.ref_clock_doubler = 2; //always doubling + cs.prescaler = 8; //set to 8 when input is under 2400 MHz + + for (cs.r_counter = 1; cs.r_counter <= 1; cs.r_counter++){ + for (cs.b_counter = 3; cs.b_counter <= 10; cs.b_counter++){ + for (cs.a_counter = 0; cs.a_counter <= 10; cs.a_counter++){ + for (cs.vco_divider = 2; cs.vco_divider <= 6; cs.vco_divider++){ + for (cs.clk_divider = 1; cs.clk_divider <= 32; cs.clk_divider++){ + if (cs.get_vco_rate() > 1800e6) continue; + if (cs.get_vco_rate() < 1400e6) continue; + if (cs.get_out_rate() < 32e6) continue; //lowest we allow for GPMC interface + //std::cout << (cs.get_out_rate()/1e6) << std::endl; + get_clock_settings().push_back(cs); + }}}}} +} + +/*********************************************************************** * Constants **********************************************************************/ static const bool enable_test_clock = false; @@ -72,25 +130,45 @@ public: _ad9522_regs.ld_pin_control = 0x00; //dld _ad9522_regs.refmon_pin_control = 0x12; //show ref2 - _ad9522_regs.enable_ref2 = 1; - _ad9522_regs.enable_ref1 = 0; - _ad9522_regs.select_ref = ad9522_regs_t::SELECT_REF_REF2; + this->use_internal_ref(); - _ad9522_regs.set_r_counter(r_counter); - _ad9522_regs.a_counter = a_counter; - _ad9522_regs.set_b_counter(b_counter); + this->set_fpga_clock_rate(64e6); //initialize to something + + this->enable_rx_dboard_clock(false); + this->enable_tx_dboard_clock(false); + } + + ~usrp_e100_clock_ctrl_impl(void){ + this->enable_rx_dboard_clock(false); + this->enable_tx_dboard_clock(false); + } + + void set_clock_settings_with_internal_vco(const clock_settings_type &cs){ + _ad9522_regs.enable_clock_doubler = (cs.ref_clock_doubler == 2)? 1 : 0; + + _ad9522_regs.set_r_counter(cs.r_counter); + _ad9522_regs.a_counter = cs.a_counter; + _ad9522_regs.set_b_counter(cs.b_counter); + UHD_ASSERT_THROW(cs.prescaler == 8); //assumes this below: _ad9522_regs.prescaler_p = ad9522_regs_t::PRESCALER_P_DIV8_9; _ad9522_regs.pll_power_down = ad9522_regs_t::PLL_POWER_DOWN_NORMAL; _ad9522_regs.cp_current = ad9522_regs_t::CP_CURRENT_1_2MA; _ad9522_regs.vco_calibration_now = 1; //calibrate it! - _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV5; + switch(cs.vco_divider){ + case 1: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV1; break; + case 2: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV2; break; + case 3: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV3; break; + case 4: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV4; break; + case 5: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV5; break; + case 6: _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV6; break; + } _ad9522_regs.select_vco_or_clock = ad9522_regs_t::SELECT_VCO_OR_CLOCK_VCO; //setup fpga master clock _ad9522_regs.out0_format = ad9522_regs_t::OUT0_FORMAT_LVDS; - set_clock_divider(fpga_clock_divider, + set_clock_divider(cs.clk_divider, _ad9522_regs.divider0_low_cycles, _ad9522_regs.divider0_high_cycles, _ad9522_regs.divider0_bypass @@ -98,7 +176,7 @@ public: //setup codec clock _ad9522_regs.out3_format = ad9522_regs_t::OUT3_FORMAT_LVDS; - set_clock_divider(codec_clock_divider, + set_clock_divider(cs.clk_divider, _ad9522_regs.divider1_low_cycles, _ad9522_regs.divider1_high_cycles, _ad9522_regs.divider1_bypass @@ -125,21 +203,22 @@ public: } } this->latch_regs(); - //test read: - //boost::uint32_t reg = _ad9522_regs.get_read_reg(0x01b); - //boost::uint32_t result = _iface->transact_spi( - // UE_SPI_SS_AD9522, - // spi_config_t::EDGE_RISE, - // reg, 24, true /*no*/ - //); - //std::cout << "result " << std::hex << result << std::endl; - this->enable_rx_dboard_clock(false); - this->enable_tx_dboard_clock(false); } - ~usrp_e100_clock_ctrl_impl(void){ - this->enable_rx_dboard_clock(false); - this->enable_tx_dboard_clock(false); + void set_fpga_clock_rate(double rate){ + if (rate == 61.44e6){ + //TODO special settings for external VCXO + } + else{ + BOOST_FOREACH(const clock_settings_type &cs, get_clock_settings()){ + if (rate != cs.get_out_rate()) continue; + std::cout << "USRP-E100 clock control:" << std::endl << cs.to_pp_string() << std::endl; + set_clock_settings_with_internal_vco(cs); + } + throw std::runtime_error(str(boost::format( + "USRP-E100 clock control: could not find settings for clock rate %fMHz" + ) % (rate/1e6))); + } } double get_fpga_clock_rate(void){ diff --git a/host/lib/usrp/usrp_e100/clock_ctrl.hpp b/host/lib/usrp/usrp_e100/clock_ctrl.hpp index d613d1473..1f9960ce4 100644 --- a/host/lib/usrp/usrp_e100/clock_ctrl.hpp +++ b/host/lib/usrp/usrp_e100/clock_ctrl.hpp @@ -40,6 +40,13 @@ public: static sptr make(usrp_e100_iface::sptr iface); /*! + * Set the rate of the fpga clock line. + * Throws if rate is not valid. + * \param rate the new rate in Hz + */ + virtual void set_fpga_clock_rate(double rate) = 0; + + /*! * Get the rate of the fpga clock line. * \return the fpga clock rate in Hz */ |