diff options
Diffstat (limited to 'host/lib/usrp/dboard/db_wbx_version3.cpp')
-rw-r--r-- | host/lib/usrp/dboard/db_wbx_version3.cpp | 142 |
1 files changed, 38 insertions, 104 deletions
diff --git a/host/lib/usrp/dboard/db_wbx_version3.cpp b/host/lib/usrp/dboard/db_wbx_version3.cpp index 6927ae4e4..2add8d25d 100644 --- a/host/lib/usrp/dboard/db_wbx_version3.cpp +++ b/host/lib/usrp/dboard/db_wbx_version3.cpp @@ -16,8 +16,6 @@ // #include "db_wbx_common.hpp" -#include "adf4350_regs.hpp" -#include "../common/adf435x_common.hpp" #include <uhd/utils/log.hpp> #include <uhd/types/dict.hpp> #include <uhd/types/ranges.hpp> @@ -82,13 +80,15 @@ static int tx_pga0_gain_to_iobits(double &gain){ wbx_base::wbx_version3::wbx_version3(wbx_base *_self_wbx_base) { //register our handle on the primary wbx_base instance self_base = _self_wbx_base; + _txlo = adf435x_iface::make_adf4350(boost::bind(&wbx_base::wbx_versionx::write_lo_regs, this, dboard_iface::UNIT_TX, _1)); + _rxlo = adf435x_iface::make_adf4350(boost::bind(&wbx_base::wbx_versionx::write_lo_regs, this, dboard_iface::UNIT_RX, _1)); //////////////////////////////////////////////////////////////////// // Register RX properties //////////////////////////////////////////////////////////////////// this->get_rx_subtree()->create<std::string>("name").set("WBXv3 RX"); this->get_rx_subtree()->create<double>("freq/value") - .coerce(boost::bind(&wbx_base::wbx_version3::set_lo_freq, this, dboard_iface::UNIT_RX, _1)) + .set_coercer(boost::bind(&wbx_base::wbx_version3::set_lo_freq, this, dboard_iface::UNIT_RX, _1)) .set((wbx_v3_freq_range.start() + wbx_v3_freq_range.stop())/2.0); this->get_rx_subtree()->create<meta_range_t>("freq/range").set(wbx_v3_freq_range); @@ -98,17 +98,17 @@ wbx_base::wbx_version3::wbx_version3(wbx_base *_self_wbx_base) { this->get_tx_subtree()->create<std::string>("name").set("WBXv3 TX"); BOOST_FOREACH(const std::string &name, wbx_v3_tx_gain_ranges.keys()){ self_base->get_tx_subtree()->create<double>("gains/"+name+"/value") - .coerce(boost::bind(&wbx_base::wbx_version3::set_tx_gain, this, _1, name)) + .set_coercer(boost::bind(&wbx_base::wbx_version3::set_tx_gain, this, _1, name)) .set(wbx_v3_tx_gain_ranges[name].start()); self_base->get_tx_subtree()->create<meta_range_t>("gains/"+name+"/range") .set(wbx_v3_tx_gain_ranges[name]); } this->get_tx_subtree()->create<double>("freq/value") - .coerce(boost::bind(&wbx_base::wbx_version3::set_lo_freq, this, dboard_iface::UNIT_TX, _1)) + .set_coercer(boost::bind(&wbx_base::wbx_version3::set_lo_freq, this, dboard_iface::UNIT_TX, _1)) .set((wbx_v3_freq_range.start() + wbx_v3_freq_range.stop())/2.0); this->get_tx_subtree()->create<meta_range_t>("freq/range").set(wbx_v3_freq_range); this->get_tx_subtree()->create<bool>("enabled") - .subscribe(boost::bind(&wbx_base::wbx_version3::set_tx_enabled, this, _1)) + .add_coerced_subscriber(boost::bind(&wbx_base::wbx_version3::set_tx_enabled, this, _1)) .set(true); //start enabled //set attenuator control bits @@ -129,29 +129,29 @@ wbx_base::wbx_version3::wbx_version3(wbx_base *_self_wbx_base) { //slip 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, v3_tx_mod, \ + gpio_atr::ATR_REG_IDLE, v3_tx_mod, \ TX_ATTN_MASK | TX_MIXER_DIS | v3_tx_mod); self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, \ - dboard_iface::ATR_REG_RX_ONLY, v3_tx_mod, \ + gpio_atr::ATR_REG_RX_ONLY, v3_tx_mod, \ TX_ATTN_MASK | TX_MIXER_DIS | v3_tx_mod); self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, \ - dboard_iface::ATR_REG_TX_ONLY, v3_tx_mod, \ + gpio_atr::ATR_REG_TX_ONLY, v3_tx_mod, \ TX_ATTN_MASK | TX_MIXER_DIS | v3_tx_mod); self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, \ - dboard_iface::ATR_REG_FULL_DUPLEX, v3_tx_mod, \ + gpio_atr::ATR_REG_FULL_DUPLEX, v3_tx_mod, \ TX_ATTN_MASK | TX_MIXER_DIS | v3_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); } @@ -181,8 +181,8 @@ double wbx_base::wbx_version3::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(); return self_base->_tx_gains[name]; //shadow @@ -209,108 +209,42 @@ double wbx_base::wbx_version3::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 - (0,23) //adf4350_regs_t::PRESCALER_4_5 - (1,75) //adf4350_regs_t::PRESCALER_8_9 - ; - - //map rf divider select output dividers to enums - static const uhd::dict<int, adf4350_regs_t::rf_divider_select_t> rfdivsel_to_enum = map_list_of - (1, adf4350_regs_t::RF_DIVIDER_SELECT_DIV1) - (2, adf4350_regs_t::RF_DIVIDER_SELECT_DIV2) - (4, adf4350_regs_t::RF_DIVIDER_SELECT_DIV4) - (8, adf4350_regs_t::RF_DIVIDER_SELECT_DIV8) - (16, adf4350_regs_t::RF_DIVIDER_SELECT_DIV16) - ; + //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 double synth_target_freq = target_freq * 2; - //TODO: Document why the following has to be true - bool div_resync_enabled = (target_freq > reference_freq); - - adf4350_regs_t::prescaler_t prescaler = - synth_target_freq > 3e9 ? adf4350_regs_t::PRESCALER_8_9 : adf4350_regs_t::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, 16); + + //Use 8/9 prescaler for vco_freq > 3 GHz (pg.18 prescaler) + lo_iface->set_prescaler(synth_target_freq > 3e9 ? + adf435x_iface::PRESCALER_8_9 : adf435x_iface::PRESCALER_4_5); + //When divider resync is enabled, a 180 deg phase error is introduced when syncing //multiple WBX boards. Switching to fundamental mode works arounds this issue. - tuning_constraints.feedback_after_divider = div_resync_enabled; + //TODO: Document why the following has to be true + lo_iface->set_feedback_select((target_freq > reference_freq) ? + 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 - adf4350_regs_t regs; - - if (unit == dboard_iface::UNIT_RX) - regs.output_power = (actual_freq == wbx_rx_lo_5dbm.clip(actual_freq)) ? adf4350_regs_t::OUTPUT_POWER_5DBM - : adf4350_regs_t::OUTPUT_POWER_2DBM; - else - regs.output_power = (actual_freq == wbx_tx_lo_5dbm.clip(actual_freq)) ? adf4350_regs_t::OUTPUT_POWER_5DBM - : adf4350_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 ? - adf4350_regs_t::FEEDBACK_SELECT_DIVIDED : - adf4350_regs_t::FEEDBACK_SELECT_FUNDAMENTAL; - regs.clock_div_mode = div_resync_enabled ? - adf4350_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE : - adf4350_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 ? - adf4350_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED : - adf4350_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED; - regs.reference_doubler = tuning_settings.r_doubler_en ? - adf4350_regs_t::REFERENCE_DOUBLER_ENABLED : - adf4350_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 ? - adf4350_regs_t::LDF_INT_N : - adf4350_regs_t::LDF_FRAC_N; - - //reset the N and R counter - regs.counter_reset = adf4350_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 = adf4350_regs_t::COUNTER_RESET_DISABLED; - - //write the registers - //correct power-up sequence to write registers (5, 4, 3, 2, 1, 0) - int addr; - - for(addr=5; addr>=0; addr--){ - UHD_LOGV(often) << boost::format( - "WBX SPI Reg (0x%02x): 0x%08x" - ) % 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( - "WBX tune: actual frequency %f MHz" - ) % (actual_freq/1e6) << std::endl; + //Write to hardware + lo_iface->commit(); + return actual_freq; } |