diff options
Diffstat (limited to 'host/lib/usrp/dboard/db_wbx_version4.cpp')
-rw-r--r-- | host/lib/usrp/dboard/db_wbx_version4.cpp | 140 |
1 files changed, 35 insertions, 105 deletions
diff --git a/host/lib/usrp/dboard/db_wbx_version4.cpp b/host/lib/usrp/dboard/db_wbx_version4.cpp index 81cdaefac..dc351af1d 100644 --- a/host/lib/usrp/dboard/db_wbx_version4.cpp +++ b/host/lib/usrp/dboard/db_wbx_version4.cpp @@ -16,8 +16,6 @@ // #include "db_wbx_common.hpp" -#include "adf4351_regs.hpp" -#include "../common/adf435x_common.hpp" #include <uhd/utils/log.hpp> #include <uhd/types/dict.hpp> #include <uhd/types/ranges.hpp> @@ -83,6 +81,8 @@ static int tx_pga0_gain_to_iobits(double &gain){ wbx_base::wbx_version4::wbx_version4(wbx_base *_self_wbx_base) { //register our handle on the primary wbx_base instance self_base = _self_wbx_base; + _txlo = adf435x_iface::make_adf4351(boost::bind(&wbx_base::wbx_versionx::write_lo_regs, this, dboard_iface::UNIT_TX, _1)); + _rxlo = adf435x_iface::make_adf4351(boost::bind(&wbx_base::wbx_versionx::write_lo_regs, this, dboard_iface::UNIT_RX, _1)); //////////////////////////////////////////////////////////////////// // Register RX properties @@ -92,7 +92,7 @@ wbx_base::wbx_version4::wbx_version4(wbx_base *_self_wbx_base) { if(rx_id == 0x0063) this->get_rx_subtree()->create<std::string>("name").set("WBXv4 RX"); else if(rx_id == 0x0081) this->get_rx_subtree()->create<std::string>("name").set("WBX-120 RX"); this->get_rx_subtree()->create<double>("freq/value") - .coerce(boost::bind(&wbx_base::wbx_version4::set_lo_freq, this, dboard_iface::UNIT_RX, _1)) + .set_coercer(boost::bind(&wbx_base::wbx_version4::set_lo_freq, this, dboard_iface::UNIT_RX, _1)) .set((wbx_v4_freq_range.start() + wbx_v4_freq_range.stop())/2.0); this->get_rx_subtree()->create<meta_range_t>("freq/range").set(wbx_v4_freq_range); @@ -105,17 +105,17 @@ wbx_base::wbx_version4::wbx_version4(wbx_base *_self_wbx_base) { else if(rx_id == 0x0081) this->get_tx_subtree()->create<std::string>("name").set("WBX-120 TX"); BOOST_FOREACH(const std::string &name, wbx_v4_tx_gain_ranges.keys()){ self_base->get_tx_subtree()->create<double>("gains/"+name+"/value") - .coerce(boost::bind(&wbx_base::wbx_version4::set_tx_gain, this, _1, name)) + .set_coercer(boost::bind(&wbx_base::wbx_version4::set_tx_gain, this, _1, name)) .set(wbx_v4_tx_gain_ranges[name].start()); self_base->get_tx_subtree()->create<meta_range_t>("gains/"+name+"/range") .set(wbx_v4_tx_gain_ranges[name]); } this->get_tx_subtree()->create<double>("freq/value") - .coerce(boost::bind(&wbx_base::wbx_version4::set_lo_freq, this, dboard_iface::UNIT_TX, _1)) + .set_coercer(boost::bind(&wbx_base::wbx_version4::set_lo_freq, this, dboard_iface::UNIT_TX, _1)) .set((wbx_v4_freq_range.start() + wbx_v4_freq_range.stop())/2.0); this->get_tx_subtree()->create<meta_range_t>("freq/range").set(wbx_v4_freq_range); this->get_tx_subtree()->create<bool>("enabled") - .subscribe(boost::bind(&wbx_base::wbx_version4::set_tx_enabled, this, _1)) + .add_coerced_subscriber(boost::bind(&wbx_base::wbx_version4::set_tx_enabled, this, _1)) .set(true); //start enabled //set attenuator control bits @@ -136,29 +136,29 @@ wbx_base::wbx_version4::wbx_version4(wbx_base *_self_wbx_base) { //between bursts) set TX gain iobits to min gain (max attenuation) when //RX_ONLY or IDLE to suppress LO leakage self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, \ - dboard_iface::ATR_REG_IDLE, v4_tx_mod, \ + gpio_atr::ATR_REG_IDLE, v4_tx_mod, \ TX_ATTN_MASK | TX_MIXER_DIS | v4_tx_mod); self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, \ - dboard_iface::ATR_REG_RX_ONLY, v4_tx_mod, \ + gpio_atr::ATR_REG_RX_ONLY, v4_tx_mod, \ TX_ATTN_MASK | TX_MIXER_DIS | v4_tx_mod); self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, \ - dboard_iface::ATR_REG_TX_ONLY, v4_tx_mod, \ + gpio_atr::ATR_REG_TX_ONLY, v4_tx_mod, \ TX_ATTN_MASK | TX_MIXER_DIS | v4_tx_mod); self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, \ - dboard_iface::ATR_REG_FULL_DUPLEX, v4_tx_mod, \ + gpio_atr::ATR_REG_FULL_DUPLEX, v4_tx_mod, \ TX_ATTN_MASK | TX_MIXER_DIS | v4_tx_mod); self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, \ - dboard_iface::ATR_REG_IDLE, \ + gpio_atr::ATR_REG_IDLE, \ RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB); self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, \ - dboard_iface::ATR_REG_TX_ONLY, \ + gpio_atr::ATR_REG_TX_ONLY, \ RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB); self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, \ - dboard_iface::ATR_REG_RX_ONLY, \ + gpio_atr::ATR_REG_RX_ONLY, \ RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB); self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, \ - dboard_iface::ATR_REG_FULL_DUPLEX, \ + gpio_atr::ATR_REG_FULL_DUPLEX, \ RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB); } @@ -188,8 +188,8 @@ double wbx_base::wbx_version4::set_tx_gain(double gain, const std::string &name) //write the new gain to tx gpio outputs //Update ATR with gain io_bits, only update for TX_ONLY and FULL_DUPLEX ATR states - self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY, io_bits, TX_ATTN_MASK); - self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, io_bits, TX_ATTN_MASK); + self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_TX_ONLY, io_bits, TX_ATTN_MASK); + self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_FULL_DUPLEX, io_bits, TX_ATTN_MASK); } else UHD_THROW_INVALID_CODE_PATH(); @@ -217,116 +217,46 @@ double wbx_base::wbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar : self_base->get_tx_subtree(); device_addr_t tune_args = subtree->access<device_addr_t>("tune_args").get(); bool is_int_n = boost::iequals(tune_args.get("mode_n",""), "integer"); + double reference_freq = self_base->get_iface()->get_clock_rate(unit); - //map prescaler setting to mininmum integer divider (N) values (pg.18 prescaler) - static const uhd::dict<int, int> prescaler_to_min_int_div = map_list_of - (adf4351_regs_t::PRESCALER_4_5, 23) - (adf4351_regs_t::PRESCALER_8_9, 75) - ; - - //map rf divider select output dividers to enums - static const uhd::dict<int, adf4351_regs_t::rf_divider_select_t> rfdivsel_to_enum = map_list_of - (1, adf4351_regs_t::RF_DIVIDER_SELECT_DIV1) - (2, adf4351_regs_t::RF_DIVIDER_SELECT_DIV2) - (4, adf4351_regs_t::RF_DIVIDER_SELECT_DIV4) - (8, adf4351_regs_t::RF_DIVIDER_SELECT_DIV8) - (16, adf4351_regs_t::RF_DIVIDER_SELECT_DIV16) - (32, adf4351_regs_t::RF_DIVIDER_SELECT_DIV32) - (64, adf4351_regs_t::RF_DIVIDER_SELECT_DIV64) - ; + //Select the LO + adf435x_iface::sptr& lo_iface = unit == dboard_iface::UNIT_RX ? _rxlo : _txlo; + lo_iface->set_reference_freq(reference_freq); - double reference_freq = self_base->get_iface()->get_clock_rate(unit); //The mixer has a divide-by-2 stage on the LO port so the synthesizer //frequency must 2x the target frequency. This introduces a 180 degree phase //ambiguity when trying to synchronize the phase of multiple boards. double synth_target_freq = target_freq * 2; - adf4351_regs_t::prescaler_t prescaler = - synth_target_freq > 3.6e9 ? adf4351_regs_t::PRESCALER_8_9 : adf4351_regs_t::PRESCALER_4_5; + //Use 8/9 prescaler for vco_freq > 3 GHz (pg.18 prescaler) + lo_iface->set_prescaler(synth_target_freq > 3.6e9 ? + adf435x_iface::PRESCALER_8_9 : adf435x_iface::PRESCALER_4_5); - adf435x_tuning_constraints tuning_constraints; - tuning_constraints.force_frac0 = is_int_n; - tuning_constraints.band_sel_freq_max = 100e3; - tuning_constraints.ref_doubler_threshold = 12.5e6; - tuning_constraints.int_range = uhd::range_t(prescaler_to_min_int_div[prescaler], 4095); - tuning_constraints.pfd_freq_max = 25e6; - tuning_constraints.rf_divider_range = uhd::range_t(1, 64); //The feedback of the divided frequency must be disabled whenever the target frequency //divided by the minimum PFD frequency cannot meet the minimum integer divider (N) value. //If it is disabled, additional phase ambiguity will be introduced. With a minimum PFD //frequency of 10 MHz, synthesizer frequencies below 230 MHz (LO frequencies below 115 MHz) //will have too much ambiguity to synchronize. - tuning_constraints.feedback_after_divider = - (int(synth_target_freq / 10e6) >= prescaler_to_min_int_div[prescaler]); + lo_iface->set_feedback_select( + (int(synth_target_freq / 10e6) >= lo_iface->get_int_range().start() ? + adf435x_iface::FB_SEL_DIVIDED : adf435x_iface::FB_SEL_FUNDAMENTAL)); - double synth_actual_freq = 0; - adf435x_tuning_settings tuning_settings = tune_adf435x_synth( - synth_target_freq, reference_freq, tuning_constraints, synth_actual_freq); + double synth_actual_freq = lo_iface->set_frequency(synth_target_freq, is_int_n); //The mixer has a divide-by-2 stage on the LO port so the synthesizer //actual_freq must /2 the synth_actual_freq double actual_freq = synth_actual_freq / 2; - //load the register values - adf4351_regs_t regs; - - if (unit == dboard_iface::UNIT_RX) - regs.output_power = (actual_freq == wbx_rx_lo_5dbm.clip(actual_freq)) ? adf4351_regs_t::OUTPUT_POWER_5DBM - : adf4351_regs_t::OUTPUT_POWER_2DBM; - else - regs.output_power = (actual_freq == wbx_tx_lo_5dbm.clip(actual_freq)) ? adf4351_regs_t::OUTPUT_POWER_5DBM - : adf4351_regs_t::OUTPUT_POWER_M1DBM; - - regs.frac_12_bit = tuning_settings.frac_12_bit; - regs.int_16_bit = tuning_settings.int_16_bit; - regs.mod_12_bit = tuning_settings.mod_12_bit; - regs.clock_divider_12_bit = tuning_settings.clock_divider_12_bit; - regs.feedback_select = tuning_constraints.feedback_after_divider ? - adf4351_regs_t::FEEDBACK_SELECT_DIVIDED : - adf4351_regs_t::FEEDBACK_SELECT_FUNDAMENTAL; - regs.clock_div_mode = tuning_constraints.feedback_after_divider ? - adf4351_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE : - adf4351_regs_t::CLOCK_DIV_MODE_FAST_LOCK; - regs.prescaler = prescaler; - regs.r_counter_10_bit = tuning_settings.r_counter_10_bit; - regs.reference_divide_by_2 = tuning_settings.r_divide_by_2_en ? - adf4351_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED : - adf4351_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED; - regs.reference_doubler = tuning_settings.r_doubler_en ? - adf4351_regs_t::REFERENCE_DOUBLER_ENABLED : - adf4351_regs_t::REFERENCE_DOUBLER_DISABLED; - regs.band_select_clock_div = tuning_settings.band_select_clock_div; - UHD_ASSERT_THROW(rfdivsel_to_enum.has_key(tuning_settings.rf_divider)); - regs.rf_divider_select = rfdivsel_to_enum[tuning_settings.rf_divider]; - regs.ldf = is_int_n ? - adf4351_regs_t::LDF_INT_N : - adf4351_regs_t::LDF_FRAC_N; - - //reset the N and R counter - regs.counter_reset = adf4351_regs_t::COUNTER_RESET_ENABLED; - self_base->get_iface()->write_spi(unit, spi_config_t::EDGE_RISE, regs.get_reg(2), 32); - regs.counter_reset = adf4351_regs_t::COUNTER_RESET_DISABLED; - - //write the registers - //correct power-up sequence to write registers (5, 4, 3, 2, 1, 0) - int addr; - - boost::uint16_t rx_id = self_base->get_rx_id().to_uint16(); - std::string board_name = (rx_id == 0x0081) ? "WBX-120" : "WBX"; - for(addr=5; addr>=0; addr--){ - UHD_LOGV(often) << boost::format( - "%s SPI Reg (0x%02x): 0x%08x" - ) % board_name.c_str() % addr % regs.get_reg(addr) << std::endl; - self_base->get_iface()->write_spi( - unit, spi_config_t::EDGE_RISE, - regs.get_reg(addr), 32 - ); + if (unit == dboard_iface::UNIT_RX) { + lo_iface->set_output_power((actual_freq == wbx_rx_lo_5dbm.clip(actual_freq)) ? + adf435x_iface::OUTPUT_POWER_5DBM : adf435x_iface::OUTPUT_POWER_2DBM); + } else { + lo_iface->set_output_power((actual_freq == wbx_tx_lo_5dbm.clip(actual_freq)) ? + adf435x_iface::OUTPUT_POWER_5DBM : adf435x_iface::OUTPUT_POWER_M1DBM); } - //return the actual frequency - UHD_LOGV(often) << boost::format( - "%s tune: actual frequency %f MHz" - ) % board_name.c_str() % (actual_freq/1e6) << std::endl; + //Write to hardware + lo_iface->commit(); return actual_freq; } |