コード例 #1
0
ファイル: db_sbx.cpp プロジェクト: GREO/uhd
/***********************************************************************
 * Structors
 **********************************************************************/
sbx_xcvr::sbx_xcvr(ctor_args_t args) : xcvr_dboard_base(args){

    //enable the clocks that we need
    this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true);
    this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true);

    //set the gpio directions and atr controls (identically)
    this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_TX, (TXIO_MASK|TX_LED_IO));
    this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, (RXIO_MASK|RX_LED_IO));
    this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, (TXIO_MASK|TX_LED_IO));
    this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, (RXIO_MASK|RX_LED_IO));

    //flash LEDs
    flash_leds();

    UHD_LOGV(often) << boost::format(
        "SBX GPIO Direction: RX: 0x%08x, TX: 0x%08x"
    ) % RXIO_MASK % TXIO_MASK << std::endl;

    //set some default values
    set_rx_lo_freq((sbx_freq_range.start() + sbx_freq_range.stop())/2.0);
    set_tx_lo_freq((sbx_freq_range.start() + sbx_freq_range.stop())/2.0);
    set_rx_ant("RX2");

    BOOST_FOREACH(const std::string &name, sbx_tx_gain_ranges.keys()){
        set_tx_gain(sbx_tx_gain_ranges[name].start(), name);
    }
    BOOST_FOREACH(const std::string &name, sbx_rx_gain_ranges.keys()){
        set_rx_gain(sbx_rx_gain_ranges[name].start(), name);
    }
}
コード例 #2
0
ファイル: db_wbx.cpp プロジェクト: vlqk/uhd-8bit
/***********************************************************************
 * Structors
 **********************************************************************/
wbx_xcvr::wbx_xcvr(ctor_args_t args) : xcvr_dboard_base(args){

    //enable the clocks that we need
    this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true);
    this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true);

    //set the gpio directions and atr controls (identically)
    this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_TX, TXIO_MASK);
    this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, RXIO_MASK);
    this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, TXIO_MASK);
    this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, RXIO_MASK);
    if (wbx_debug) std::cerr << boost::format(
        "WBX GPIO Direction: RX: 0x%08x, TX: 0x%08x"
    ) % RXIO_MASK % TXIO_MASK << std::endl;

    //set some default values
    set_rx_lo_freq((wbx_freq_range.start() + wbx_freq_range.stop())/2.0);
    set_tx_lo_freq((wbx_freq_range.start() + wbx_freq_range.stop())/2.0);
    set_rx_ant("RX2");

    BOOST_FOREACH(const std::string &name, wbx_tx_gain_ranges.keys()){
        set_tx_gain(wbx_tx_gain_ranges[name].start(), name);
    }
    BOOST_FOREACH(const std::string &name, wbx_rx_gain_ranges.keys()){
        set_rx_gain(wbx_rx_gain_ranges[name].start(), name);
    }
}
コード例 #3
0
ファイル: db_tvrx.cpp プロジェクト: Gabotero/UHD
/***********************************************************************
 * Structors
 **********************************************************************/
tvrx::tvrx(ctor_args_t args) : rx_dboard_base(args){
    ////////////////////////////////////////////////////////////////////
    // Register properties
    ////////////////////////////////////////////////////////////////////
    this->get_rx_subtree()->create<std::string>("name")
        .set("TVRX");
    this->get_rx_subtree()->create<int>("sensors"); //phony property so this dir exists
    BOOST_FOREACH(const std::string &name, get_tvrx_gain_ranges().keys()){
        this->get_rx_subtree()->create<double>("gains/"+name+"/value")
            .coerce(boost::bind(&tvrx::set_gain, this, _1, name));
        this->get_rx_subtree()->create<meta_range_t>("gains/"+name+"/range")
            .set(get_tvrx_gain_ranges()[name]);
    }
    this->get_rx_subtree()->create<double>("freq/value")
        .coerce(boost::bind(&tvrx::set_freq, this, _1));
    this->get_rx_subtree()->create<meta_range_t>("freq/range")
        .set(tvrx_freq_range);
    this->get_rx_subtree()->create<std::string>("antenna/value")
        .set(tvrx_antennas.at(0));
    this->get_rx_subtree()->create<std::vector<std::string> >("antenna/options")
        .set(tvrx_antennas);
    this->get_rx_subtree()->create<std::string>("connection")
        .set("I");
    this->get_rx_subtree()->create<bool>("enabled")
        .set(true); //always enabled
    this->get_rx_subtree()->create<bool>("use_lo_offset")
        .set(false);
    this->get_rx_subtree()->create<double>("bandwidth/value")
        .set(6.0e6);
    this->get_rx_subtree()->create<meta_range_t>("bandwidth/range")
        .set(freq_range_t(6.0e6, 6.0e6));

    //enable only the clocks we need
    this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true);

    //set the gpio directions and atr controls (identically)
    this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, 0x0); // All unused in atr
    if (this->get_iface()->get_special_props().soft_clock_divider){
        this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0x1); // GPIO0 is clock
    }
    else{
        this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0x0); // All Inputs
    }

    //send initial register settings if necessary

    //set default freq
    _lo_freq = tvrx_freq_range.start() + tvrx_if_freq; //init _lo_freq to a sane default
    this->get_rx_subtree()->access<double>("freq/value").set(tvrx_freq_range.start());

    //set default gains
    BOOST_FOREACH(const std::string &name, get_tvrx_gain_ranges().keys()){
        this->get_rx_subtree()->access<double>("gains/"+name+"/value")
            .set(get_tvrx_gain_ranges()[name].start());
    }
}
コード例 #4
0
/***********************************************************************
 * WBX Common Implementation
 **********************************************************************/
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;

    ////////////////////////////////////////////////////////////////////
    // Register RX properties
    ////////////////////////////////////////////////////////////////////
    this->get_rx_subtree()->create<std::string>("name").set("WBXv4 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((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);

    ////////////////////////////////////////////////////////////////////
    // Register TX properties
    ////////////////////////////////////////////////////////////////////
    this->get_tx_subtree()->create<std::string>("name").set("WBXv4 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(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((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))
        .set(true); //start enabled

    //set attenuator control bits
    int v4_iobits = TX_ATTN_MASK;
    int v4_tx_mod = ADF4351_PDBRF;

    //set the gpio directions and atr controls
    self_base->get_iface()->set_pin_ctrl(dboard_iface::UNIT_TX, v4_tx_mod|v4_iobits);
    self_base->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, RXBB_PDB|ADF4351_PDBRF);
    self_base->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, TX_PUP_5V|TX_PUP_3V|v4_tx_mod|v4_iobits);
    self_base->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, RX_PUP_5V|RX_PUP_3V|ADF4351_CE|RXBB_PDB|ADF4351_PDBRF|RX_ATTN_MASK);

    //setup ATR for the mixer enables (always enabled to prevent phase 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,        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, 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, 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, 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,        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,     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,     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, RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB);
}
コード例 #5
0
ファイル: db_dbsrx.cpp プロジェクト: 211217613/uhd
/***********************************************************************
 * Bandwidth Handling
 **********************************************************************/
double dbsrx::set_bandwidth(double bandwidth){
    //convert complex bandpass to lowpass bandwidth
    bandwidth = bandwidth/2.0;

    //clip the input
    bandwidth = dbsrx_bandwidth_range.clip(bandwidth);

    double ref_clock = this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX);

    //NOTE: _max2118_write_regs.m_divider set in set_lo_freq

    //compute f_dac setting
    _max2118_write_regs.f_dac = uhd::clip<int>(int((((bandwidth*_max2118_write_regs.m_divider)/ref_clock) - 4)/0.145),0,127);

    //determine actual bandwidth
    _bandwidth = double((ref_clock/(_max2118_write_regs.m_divider))*(4+0.145*_max2118_write_regs.f_dac));

    UHD_LOGV(often) << boost::format(
        "DBSRX Filter Bandwidth: %f MHz, m: %d, f_dac: %d\n"
    ) % (_bandwidth/1e6) % int(_max2118_write_regs.m_divider) % int(_max2118_write_regs.f_dac) << std::endl;

    this->send_reg(0x3, 0x4);

    //convert lowpass back to complex bandpass bandwidth
    return 2.0*_bandwidth;
}
コード例 #6
0
ファイル: db_wbx_version3.cpp プロジェクト: ilovezfs/uhd
/***********************************************************************
 * Tuning
 **********************************************************************/
double wbx_base::wbx_version3::set_lo_freq(dboard_iface::unit_t unit, double target_freq) {
    //clip to tuning range
    target_freq = wbx_v3_freq_range.clip(target_freq);

    UHD_LOGGER_TRACE("WBX") << boost::format(
        "WBX tune: target frequency %f MHz"
    ) % (target_freq/1e6) ;

    /*
     * If the user sets 'mode_n=integer' in the tuning args, the user wishes to
     * tune in Integer-N mode, which can result in better spur
     * performance on some mixers. The default is fractional tuning.
     */
    property_tree::sptr subtree = (unit == dboard_iface::UNIT_RX) ? self_base->get_rx_subtree()
                                                                  : 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);

    //Select the LO
    adf435x_iface::sptr& lo_iface = unit == dboard_iface::UNIT_RX ? _rxlo : _txlo;
    lo_iface->set_reference_freq(reference_freq);

    //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;

    //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);

    //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.
    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 = 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;

    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);
    }

    //Write to hardware
    lo_iface->commit();

    return actual_freq;
}
コード例 #7
0
ファイル: db_wbx_version3.cpp プロジェクト: 211217613/uhd
/***********************************************************************
 * Tuning
 **********************************************************************/
double wbx_base::wbx_version3::set_lo_freq(dboard_iface::unit_t unit, double target_freq) {
    //clip to tuning range
    target_freq = wbx_v3_freq_range.clip(target_freq);

    UHD_LOGV(often) << boost::format(
        "WBX tune: target frequency %f MHz"
    ) % (target_freq/1e6) << std::endl;

    /*
     * If the user sets 'mode_n=integer' in the tuning args, the user wishes to
     * tune in Integer-N mode, which can result in better spur
     * performance on some mixers. The default is fractional tuning.
     */
    property_tree::sptr subtree = (unit == dboard_iface::UNIT_RX) ? self_base->get_rx_subtree()
                                                                  : 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);

    //Select the LO
    adf435x_iface::sptr& lo_iface = unit == dboard_iface::UNIT_RX ? _rxlo : _txlo;
    lo_iface->set_reference_freq(reference_freq);

    //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;

    //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.
    //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 = 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;

    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);
    }

    //Write to hardware
    lo_iface->commit();

    return actual_freq;
}
コード例 #8
0
ファイル: db_sbx.cpp プロジェクト: GREO/uhd
/***********************************************************************
 * Antenna Handling
 **********************************************************************/
void sbx_xcvr::update_atr(void){
    //calculate atr pins
    int rx_pga0_iobits = rx_pga0_gain_to_iobits(_rx_gains["PGA0"]);
    int tx_pga0_iobits = tx_pga0_gain_to_iobits(_tx_gains["PGA0"]);
    int rx_lo_lpf_en = (_rx_lo_freq == sbx_enable_rx_lo_filter.clip(_rx_lo_freq)) ? LO_LPF_EN : 0;
    int tx_lo_lpf_en = (_tx_lo_freq == sbx_enable_tx_lo_filter.clip(_tx_lo_freq)) ? LO_LPF_EN : 0;
    int rx_ld_led = get_locked(dboard_iface::UNIT_RX) ? 0 : RX_LED_LD;
    int tx_ld_led = get_locked(dboard_iface::UNIT_TX) ? 0 : TX_LED_LD;
    int rx_ant_led = _rx_ant == "TX/RX" ? RX_LED_RX1RX2 : 0;
    int tx_ant_led = _rx_ant == "TX/RX" ? 0 : TX_LED_TXRX;

    //setup the tx atr (this does not change with antenna)
    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE,
        tx_pga0_iobits | tx_lo_lpf_en | tx_ld_led | tx_ant_led | TX_POWER_UP | ANT_XX | TX_MIXER_DIS);
    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY,
        tx_pga0_iobits | tx_lo_lpf_en | tx_ld_led | tx_ant_led | TX_POWER_UP | ANT_TX | TX_MIXER_ENB);
    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX,
        tx_pga0_iobits | tx_lo_lpf_en | tx_ld_led | tx_ant_led | TX_POWER_UP | ANT_TX | TX_MIXER_ENB);

    //setup the rx atr (this does not change with antenna)
    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE,
        rx_pga0_iobits | rx_lo_lpf_en | rx_ld_led | rx_ant_led | RX_POWER_UP | ANT_XX | RX_MIXER_DIS);
    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY,
        rx_pga0_iobits | rx_lo_lpf_en | rx_ld_led | rx_ant_led | RX_POWER_UP | ANT_RX2 | RX_MIXER_DIS);
    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX,
        rx_pga0_iobits | rx_lo_lpf_en | rx_ld_led | rx_ant_led | RX_POWER_UP | ANT_RX2 | RX_MIXER_ENB);

    //set the atr regs that change with antenna setting
    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY,
        tx_pga0_iobits | tx_lo_lpf_en | tx_ld_led | tx_ant_led | TX_POWER_UP | TX_MIXER_DIS |
            ((_rx_ant == "TX/RX")? ANT_RX : ANT_TX));
    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY,
        rx_pga0_iobits | rx_lo_lpf_en | rx_ld_led | rx_ant_led | RX_POWER_UP | RX_MIXER_ENB | 
            ((_rx_ant == "TX/RX")? ANT_TXRX : ANT_RX2));

    UHD_LOGV(often) << boost::format(
        "SBX RXONLY ATR REG: 0x%08x"
    ) % (rx_pga0_iobits | RX_POWER_UP | RX_MIXER_ENB | ((_rx_ant == "TX/RX")? ANT_TXRX : ANT_RX2)) << std::endl;
}
コード例 #9
0
ファイル: db_wbx_simple.cpp プロジェクト: GREO/uhd
/***********************************************************************
 * Structors
 **********************************************************************/
wbx_simple::wbx_simple(ctor_args_t args) : wbx_base(args){

    //set the gpio directions and atr controls (antenna switches all under ATR)
    this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_TX, ANTSW_IO, ANTSW_IO);
    this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, ANTSW_IO, ANTSW_IO);
    this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, ANTSW_IO, ANTSW_IO);
    this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, ANTSW_IO, ANTSW_IO);

    //setup ATR for the antenna switches (constant)
    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE,        ANT_RX, ANTSW_IO);
    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY,     ANT_RX, ANTSW_IO);
    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY,     ANT_TX, ANTSW_IO);
    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, ANT_TX, ANTSW_IO);

    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE,        ANT_TXRX, ANTSW_IO);
    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY,     ANT_RX2, ANTSW_IO);
    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, ANT_RX2, ANTSW_IO);

    //set some default values
    set_rx_lo_freq((wbx_freq_range.start() + wbx_freq_range.stop())/2.0);
    set_tx_lo_freq((wbx_freq_range.start() + wbx_freq_range.stop())/2.0);
    set_rx_ant("RX2");
}
コード例 #10
0
ファイル: db_dbsrx.cpp プロジェクト: sunila/airblue_7dec12
/***********************************************************************
 * Structors
 **********************************************************************/
dbsrx::dbsrx(ctor_args_t args) : rx_dboard_base(args){
    //warn user about incorrect DBID on USRP1, requires R193 populated
    if (this->get_iface()->get_special_props().soft_clock_divider and this->get_rx_id() == 0x000D)
        uhd::warning::post(
            str(boost::format(
                "DBSRX: incorrect dbid\n"
                "Expected dbid 0x0002 and R193\n"
                "found dbid == %d\n"
                "Please see the daughterboard app notes" 
                ) % this->get_rx_id().to_pp_string())
        );

    //warn user about incorrect DBID on non-USRP1, requires R194 populated
    if (not this->get_iface()->get_special_props().soft_clock_divider and this->get_rx_id() == 0x0002)
        uhd::warning::post(
            str(boost::format(
                "DBSRX: incorrect dbid\n"
                "Expected dbid 0x000D and R194\n"
                "found dbid == %d\n"
                "Please see the daughterboard app notes" 
                ) % this->get_rx_id().to_pp_string())
        );

    //enable only the clocks we need
    this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true);

    //set the gpio directions and atr controls (identically)
    this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, 0x0); // All unused in atr
    if (this->get_iface()->get_special_props().soft_clock_divider){
        this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0x1); // GPIO0 is clock
    }
    else{
        this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0x0); // All Inputs
    }

    //send initial register settings
    this->send_reg(0x0, 0x5);

    //set defaults for LO, gains, and filter bandwidth
    _bandwidth = 33e6;
    set_lo_freq(dbsrx_freq_range.start());

    BOOST_FOREACH(const std::string &name, dbsrx_gain_ranges.keys()){
        set_gain(dbsrx_gain_ranges[name].start(), name);
    }

    set_bandwidth(33e6); // default bandwidth from datasheet
}
コード例 #11
0
ファイル: db_tvrx.cpp プロジェクト: Gabotero/UHD
double tvrx::set_freq(double freq) {
    freq = tvrx_freq_range.clip(freq);
    std::string prev_band = get_band(_lo_freq - tvrx_if_freq);
    std::string new_band = get_band(freq);

    double target_lo_freq = freq + tvrx_if_freq; //the desired LO freq for high-side mixing
    double f_ref = reference_freq / double(reference_divider); //your tuning step size

    int divisor = int((target_lo_freq + (f_ref * 4.0)) / (f_ref * 8)); //the divisor we'll use
    double actual_lo_freq = (f_ref * 8 * divisor); //the LO freq we'll actually get

    if((divisor & ~0x7fff)) UHD_THROW_INVALID_CODE_PATH();

    //now we update the registers
    _tuner_4937di5_regs.db1 = (divisor >> 8) & 0xff;
    _tuner_4937di5_regs.db2 = divisor & 0xff;

    if(new_band == "VHFLO") _tuner_4937di5_regs.bandsel = tuner_4937di5_regs_t::BANDSEL_VHFLO;
    else if(new_band == "VHFHI") _tuner_4937di5_regs.bandsel = tuner_4937di5_regs_t::BANDSEL_VHFHI;
    else if(new_band == "UHF") _tuner_4937di5_regs.bandsel = tuner_4937di5_regs_t::BANDSEL_UHF;
    else UHD_THROW_INVALID_CODE_PATH();

    _tuner_4937di5_regs.power = tuner_4937di5_regs_t::POWER_OFF;
    update_regs();

    //ok don't forget to reset RF gain here if the new band != the old band
    //we do this because the gains are different for different band settings
    //not FAR off, but we do this to be consistent
    if(prev_band != new_band) set_gain(_gains["RF"], "RF");

    UHD_LOGV(often) << boost::format("set_freq: target LO: %f f_ref: %f divisor: %i actual LO: %f") % target_lo_freq % f_ref % divisor % actual_lo_freq << std::endl;

    _lo_freq = actual_lo_freq; //for rx props

    //Check the the IF if larger than the dsp rate and apply a corrective adjustment
    //so that the cordic will be tuned to a possible rate within its range.
    const double codec_rate = this->get_iface()->get_codec_rate(dboard_iface::UNIT_RX);
    if (tvrx_if_freq >= codec_rate/2){
        return _lo_freq - codec_rate;
    }

    return _lo_freq;
}
コード例 #12
0
/***********************************************************************
 * Tuning
 **********************************************************************/
double wbx_base::wbx_version2::set_lo_freq(dboard_iface::unit_t unit, double target_freq) {
    //clip to tuning range
    target_freq = wbx_v2_freq_range.clip(target_freq);

    UHD_LOGV(often) << boost::format(
        "WBX tune: target frequency %f Mhz"
    ) % (target_freq/1e6) << std::endl;

    //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)
    ;

    double actual_freq, pfd_freq;
    double ref_freq = self_base->get_iface()->get_clock_rate(unit);
    int R=0, BS=0, N=0, FRAC=0, MOD=0;
    int RFdiv = 1;
    adf4350_regs_t::reference_divide_by_2_t T     = adf4350_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED;
    adf4350_regs_t::reference_doubler_t     D     = adf4350_regs_t::REFERENCE_DOUBLER_DISABLED;    

    //Reference doubler for 50% duty cycle
    // if ref_freq < 12.5MHz enable regs.reference_divide_by_2
    if(ref_freq <= 12.5e6) D = adf4350_regs_t::REFERENCE_DOUBLER_ENABLED;

    //increase RF divider until acceptable VCO frequency
    //start with target_freq*2 because mixer has divide by 2
    double vco_freq = target_freq*2;
    while (vco_freq < 2.2e9) {
        vco_freq *= 2;
        RFdiv *= 2;
    }

    //use 8/9 prescaler for vco_freq > 3 GHz (pg.18 prescaler)
    adf4350_regs_t::prescaler_t prescaler = vco_freq > 3e9 ? adf4350_regs_t::PRESCALER_8_9 : adf4350_regs_t::PRESCALER_4_5;

    /*
     * The goal here is to loop though possible R dividers,
     * band select clock dividers, N (int) dividers, and FRAC 
     * (frac) dividers.
     *
     * Calculate the N and F dividers for each set of values.
     * The loop exists when it meets all of the constraints.
     * The resulting loop values are loaded into the registers.
     *
     * from pg.21
     *
     * f_pfd = f_ref*(1+D)/(R*(1+T))
     * f_vco = (N + (FRAC/MOD))*f_pfd
     *    N = f_vco/f_pfd - FRAC/MOD = f_vco*((R*(T+1))/(f_ref*(1+D))) - FRAC/MOD
     * f_rf = f_vco/RFdiv)
     * f_actual = f_rf/2
     */
    for(R = 1; R <= 1023; R+=1){
        //PFD input frequency = f_ref/R ... ignoring Reference doubler/divide-by-2 (D & T)
        pfd_freq = ref_freq*(1+D)/(R*(1+T));

        //keep the PFD frequency at or below 25MHz (Loop Filter Bandwidth)
        if (pfd_freq > 25e6) continue;

        //ignore fractional part of tuning
        N = int(std::floor(vco_freq/pfd_freq));

        //keep N > minimum int divider requirement
        if (N < prescaler_to_min_int_div[prescaler]) continue;

        for(BS=1; BS <= 255; BS+=1){
            //keep the band select frequency at or below 100KHz
            //constraint on band select clock
            if (pfd_freq/BS > 100e3) continue;
            goto done_loop;
        }
    } done_loop:

    //Fractional-N calculation
    MOD = 4095; //max fractional accuracy
    FRAC = int((vco_freq/pfd_freq - N)*MOD);

    //Reference divide-by-2 for 50% duty cycle
    // if R even, move one divide by 2 to to regs.reference_divide_by_2
    if(R % 2 == 0){
        T = adf4350_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED;
        R /= 2;
    }

    //actual frequency calculation
    actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T)))/RFdiv/2);


    UHD_LOGV(often)
        << boost::format("WBX Intermediates: ref=%0.2f, outdiv=%f, fbdiv=%f") % (ref_freq*(1+int(D))/(R*(1+int(T)))) % double(RFdiv*2) % double(N + double(FRAC)/double(MOD)) << std::endl

        << boost::format("WBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d, LD=%s"
            ) % R % BS % N % FRAC % MOD % T % D % RFdiv % self_base->get_locked(unit).to_pp_string() << std::endl
        << boost::format("WBX Frequencies (MHz): REQ=%0.2f, ACT=%0.2f, VCO=%0.2f, PFD=%0.2f, BAND=%0.2f"
            ) % (target_freq/1e6) % (actual_freq/1e6) % (vco_freq/1e6) % (pfd_freq/1e6) % (pfd_freq/BS/1e6) << std::endl;

    //load the register values
    adf4350_regs_t regs;

    regs.frac_12_bit = FRAC;
    regs.int_16_bit = N;
    regs.mod_12_bit = MOD;
    regs.prescaler = prescaler;
    regs.r_counter_10_bit = R;
    regs.reference_divide_by_2 = T;
    regs.reference_doubler = D;
    regs.band_select_clock_div = BS;
    UHD_ASSERT_THROW(rfdivsel_to_enum.has_key(RFdiv));
    regs.rf_divider_select = rfdivsel_to_enum[RFdiv];

    if (unit == dboard_iface::UNIT_RX) {
        freq_range_t rx_lo_5dbm = list_of
            (range_t(0.05e9, 1.4e9))
        ;

        freq_range_t rx_lo_2dbm = list_of
            (range_t(1.4e9, 2.2e9))
        ;

        if (actual_freq == rx_lo_5dbm.clip(actual_freq)) regs.output_power = adf4350_regs_t::OUTPUT_POWER_5DBM;

        if (actual_freq == rx_lo_2dbm.clip(actual_freq)) regs.output_power = adf4350_regs_t::OUTPUT_POWER_2DBM;

    } else if (unit == dboard_iface::UNIT_TX) {
        freq_range_t tx_lo_5dbm = list_of
            (range_t(0.05e9, 1.7e9))
            (range_t(1.9e9, 2.2e9))
        ;

        freq_range_t tx_lo_m1dbm = list_of
            (range_t(1.7e9, 1.9e9))
        ;

        if (actual_freq == tx_lo_5dbm.clip(actual_freq)) regs.output_power = adf4350_regs_t::OUTPUT_POWER_5DBM;

        if (actual_freq == tx_lo_m1dbm.clip(actual_freq)) regs.output_power = adf4350_regs_t::OUTPUT_POWER_M1DBM;

    }

    //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
        );
    }

    //return the actual frequency
    UHD_LOGV(often) << boost::format(
        "WBX tune: actual frequency %f Mhz"
    ) % (actual_freq/1e6) << std::endl;
    return actual_freq;
}
コード例 #13
0
ファイル: db_dbsrx.cpp プロジェクト: sunila/airblue_7dec12
/***********************************************************************
 * Tuning
 **********************************************************************/
void dbsrx::set_lo_freq(double target_freq){
    target_freq = dbsrx_freq_range.clip(target_freq);

    double actual_freq=0.0, pfd_freq=0.0, ref_clock=0.0;
    int R=0, N=0, r=0, m=0;
    bool update_filter_settings = false;
    //choose refclock
    std::vector<double> clock_rates = this->get_iface()->get_clock_rates(dboard_iface::UNIT_RX);
    const double max_clock_rate = std::sorted(clock_rates).back();
    BOOST_FOREACH(ref_clock, std::reversed(std::sorted(clock_rates))){
        if (ref_clock > 27.0e6) continue;
        if (size_t(max_clock_rate/ref_clock)%2 == 1) continue; //reject asymmetric clocks (odd divisors)

        //choose m_divider such that filter tuning constraint is met
        m = 31;
        while ((ref_clock/m < 1e6 or ref_clock/m > 2.5e6) and m > 0){ m--; }

        if(dbsrx_debug) std::cerr << boost::format(
            "DBSRX: trying ref_clock %f and m_divider %d"
        ) % (ref_clock) % m << std::endl;

        if (m >= 32) continue;

        //choose R
        for(r = 0; r <= 6; r += 1) {
            //compute divider from setting
            R = 1 << (r+1);
            if (dbsrx_debug) std::cerr << boost::format("DBSRX R:%d\n") % R << std::endl;

            //compute PFD compare frequency = ref_clock/R
            pfd_freq = ref_clock / R;

            //constrain the PFD frequency to specified range
            if ((pfd_freq < dbsrx_pfd_freq_range.start()) or (pfd_freq > dbsrx_pfd_freq_range.stop())) continue;

            //compute N
            N = int(std::floor(target_freq/pfd_freq));

            //constrain N to specified range
            if ((N < 256) or (N > 32768)) continue;

            goto done_loop;
        }
    } 

    done_loop:

    //Assert because we failed to find a suitable combination of ref_clock, R and N 
    UHD_ASSERT_THROW(ref_clock <= 27.0e6 and ref_clock >= 0.0);
    UHD_ASSERT_THROW(ref_clock/m >= 1e6 and ref_clock/m <= 2.5e6);
    UHD_ASSERT_THROW((pfd_freq >= dbsrx_pfd_freq_range.start()) and (pfd_freq <= dbsrx_pfd_freq_range.stop()));
    UHD_ASSERT_THROW((N >= 256) and (N <= 32768));

    if(dbsrx_debug) std::cerr << boost::format(
        "DBSRX: choose ref_clock (current: %f, new: %f) and m_divider %d"
    ) % (this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX)) % ref_clock % m << std::endl;

    //if ref_clock or m divider changed, we need to update the filter settings
    if (ref_clock != this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX) or m != _max2118_write_regs.m_divider) update_filter_settings = true;

    //compute resulting output frequency
    actual_freq = pfd_freq * N;

    //apply ref_clock, R, and N settings
    this->get_iface()->set_clock_rate(dboard_iface::UNIT_RX, ref_clock);
    ref_clock = this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX);
    _max2118_write_regs.m_divider = m;
    _max2118_write_regs.r_divider = (max2118_write_regs_t::r_divider_t) r;
    _max2118_write_regs.set_n_divider(N);
    _max2118_write_regs.ade_vco_ade_read = max2118_write_regs_t::ADE_VCO_ADE_READ_ENABLED;
    
    //compute prescaler variables
    int scaler = actual_freq > 1125e6 ? 2 : 4;
    _max2118_write_regs.div2 = scaler == 4 ? max2118_write_regs_t::DIV2_DIV4 : max2118_write_regs_t::DIV2_DIV2;

    if(dbsrx_debug) std::cerr << boost::format(
        "DBSRX: scaler %d, actual_freq %f MHz, register bit: %d"
    ) % scaler % (actual_freq/1e6) % int(_max2118_write_regs.div2) << std::endl;

    //compute vco frequency and select vco
    double vco_freq = actual_freq * scaler;
    if (vco_freq < 2433e6)
        _max2118_write_regs.osc_band = 0;
    else if (vco_freq < 2711e6)
        _max2118_write_regs.osc_band = 1;
    else if (vco_freq < 3025e6)
        _max2118_write_regs.osc_band = 2;
    else if (vco_freq < 3341e6)
        _max2118_write_regs.osc_band = 3;
    else if (vco_freq < 3727e6)
        _max2118_write_regs.osc_band = 4;
    else if (vco_freq < 4143e6)
        _max2118_write_regs.osc_band = 5;
    else if (vco_freq < 4493e6)
        _max2118_write_regs.osc_band = 6;
    else
        _max2118_write_regs.osc_band = 7;

    //send settings over i2c
    send_reg(0x0, 0x4);

    //check vtune for lock condition
    read_reg(0x0, 0x0);

    if(dbsrx_debug) std::cerr << boost::format(
        "DBSRX: initial guess for vco %d, vtune adc %d"
    ) % int(_max2118_write_regs.osc_band) % int(_max2118_read_regs.adc) << std::endl;

    //if we are out of lock for chosen vco, change vco
    while ((_max2118_read_regs.adc == 0) or (_max2118_read_regs.adc == 7)){

        //vtune is too low, try lower frequency vco
        if (_max2118_read_regs.adc == 0){
            if (_max2118_write_regs.osc_band == 0){
                uhd::warning::post(
                    str(boost::format(
                        "DBSRX: Tuning exceeded vco range, _max2118_write_regs.osc_band == %d\n" 
                        ) % int(_max2118_write_regs.osc_band))
                );
                UHD_ASSERT_THROW(_max2118_read_regs.adc != 0); //just to cause a throw
            }
            if (_max2118_write_regs.osc_band <= 0) break;
            _max2118_write_regs.osc_band -= 1;
        }

        //vtune is too high, try higher frequency vco
        if (_max2118_read_regs.adc == 7){
            if (_max2118_write_regs.osc_band == 7){
                uhd::warning::post(
                    str(boost::format(
                        "DBSRX: Tuning exceeded vco range, _max2118_write_regs.osc_band == %d\n" 
                        ) % int(_max2118_write_regs.osc_band))
                );
                UHD_ASSERT_THROW(_max2118_read_regs.adc != 7); //just to cause a throw
            }
            if (_max2118_write_regs.osc_band >= 7) break;
            _max2118_write_regs.osc_band += 1;
        }

        if(dbsrx_debug) std::cerr << boost::format(
            "DBSRX: trying vco %d, vtune adc %d"
        ) % int(_max2118_write_regs.osc_band) % int(_max2118_read_regs.adc) << std::endl;

        //update vco selection and check vtune
        send_reg(0x2, 0x2);
        read_reg(0x0, 0x0);

        //allow for setup time before checking condition again
        boost::this_thread::sleep(boost::posix_time::milliseconds(10));
    }
      
    if(dbsrx_debug) std::cerr << boost::format(
        "DBSRX: final vco %d, vtune adc %d"
    ) % int(_max2118_write_regs.osc_band) % int(_max2118_read_regs.adc) << std::endl;

    //select charge pump bias current
    if (_max2118_read_regs.adc <= 2) _max2118_write_regs.cp_current = max2118_write_regs_t::CP_CURRENT_I_CP_100UA;
    else if (_max2118_read_regs.adc >= 5) _max2118_write_regs.cp_current = max2118_write_regs_t::CP_CURRENT_I_CP_400UA;
    else _max2118_write_regs.cp_current = max2118_write_regs_t::CP_CURRENT_I_CP_200UA;
    
    //update charge pump bias current setting
    send_reg(0x2, 0x2);

    //compute actual tuned frequency
    _lo_freq = this->get_iface()->get_clock_rate(dboard_iface::UNIT_RX) / std::pow(2.0,(1 + _max2118_write_regs.r_divider)) * _max2118_write_regs.get_n_divider();

    //debug output of calculated variables
    if (dbsrx_debug) std::cerr
        << boost::format("DBSRX tune:\n")
        << boost::format("    VCO=%d, CP=%d, PFD Freq=%fMHz\n") % int(_max2118_write_regs.osc_band) % _max2118_write_regs.cp_current % (pfd_freq/1e6)
        << boost::format("    R=%d, N=%f, scaler=%d, div2=%d\n") % R % N % scaler % int(_max2118_write_regs.div2)
        << boost::format("    Ref    Freq=%fMHz\n") % (ref_clock/1e6)
        << boost::format("    Target Freq=%fMHz\n") % (target_freq/1e6)
        << boost::format("    Actual Freq=%fMHz\n") % (_lo_freq/1e6)
        << boost::format("    VCO    Freq=%fMHz\n") % (vco_freq/1e6)
        << std::endl;

    if (update_filter_settings) set_bandwidth(_bandwidth);
    get_locked();
}
コード例 #14
0
ファイル: db_wbx_version4.cpp プロジェクト: Bobakka/uhd
/***********************************************************************
 * Tuning
 **********************************************************************/
double wbx_base::wbx_version4::set_lo_freq(dboard_iface::unit_t unit, double target_freq) {
    //clip to tuning range
    target_freq = wbx_v4_freq_range.clip(target_freq);

    UHD_LOGV(often) << boost::format(
        "WBX tune: target frequency %f Mhz"
    ) % (target_freq/1e6) << std::endl;

    /*
     * If the user sets 'mode_n=integer' in the tuning args, the user wishes to
     * tune in Integer-N mode, which can result in better spur
     * performance on some mixers. The default is fractional tuning.
     */
    property_tree::sptr subtree = (unit == dboard_iface::UNIT_RX) ? self_base->get_rx_subtree()
                                                                  : 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");

    //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) //adf4351_regs_t::PRESCALER_4_5
        (1,75) //adf4351_regs_t::PRESCALER_8_9
    ;

    //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)
    ;

    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);

    adf4351_regs_t::prescaler_t prescaler =
        synth_target_freq > 3e9 ? adf4351_regs_t::PRESCALER_8_9 : adf4351_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, 64);
    //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;

    double synth_actual_freq = 0;
    adf435x_tuning_settings tuning_settings = tune_adf435x_synth(
        synth_target_freq, reference_freq, tuning_constraints, synth_actual_freq);

    //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         = div_resync_enabled ?
                                    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
        );
    }

    //return the actual frequency
    UHD_LOGV(often) << boost::format(
        "%s tune: actual frequency %f Mhz"
    ) % board_name.c_str() % (actual_freq/1e6) << std::endl;

    return actual_freq;
}
コード例 #15
0
ファイル: db_dbsrx.cpp プロジェクト: 211217613/uhd
/***********************************************************************
 * Structors
 **********************************************************************/
dbsrx::dbsrx(ctor_args_t args) : rx_dboard_base(args){
    //warn user about incorrect DBID on USRP1, requires R193 populated
    if (this->get_iface()->get_special_props().soft_clock_divider and this->get_rx_id() == 0x000D)
        UHD_MSG(warning) << boost::format(
                "DBSRX: incorrect dbid\n"
                "Expected dbid 0x0002 and R193\n"
                "found dbid == %d\n"
                "Please see the daughterboard app notes"
                ) % this->get_rx_id().to_pp_string();

    //warn user about incorrect DBID on non-USRP1, requires R194 populated
    if (not this->get_iface()->get_special_props().soft_clock_divider and this->get_rx_id() == 0x0002)
        UHD_MSG(warning) << boost::format(
                "DBSRX: incorrect dbid\n"
                "Expected dbid 0x000D and R194\n"
                "found dbid == %d\n"
                "Please see the daughterboard app notes"
                ) % this->get_rx_id().to_pp_string();

    //send initial register settings
    this->send_reg(0x0, 0x5);

    //set defaults for LO, gains, and filter bandwidth
    double codec_rate = this->get_iface()->get_codec_rate(dboard_iface::UNIT_RX);
    _bandwidth = 0.8*codec_rate/2.0; // default to anti-alias at different codec_rate

    ////////////////////////////////////////////////////////////////////
    // Register properties
    ////////////////////////////////////////////////////////////////////
    this->get_rx_subtree()->create<std::string>("name")
        .set("DBSRX");
    this->get_rx_subtree()->create<sensor_value_t>("sensors/lo_locked")
        .set_publisher(boost::bind(&dbsrx::get_locked, this));
    BOOST_FOREACH(const std::string &name, dbsrx_gain_ranges.keys()){
        this->get_rx_subtree()->create<double>("gains/"+name+"/value")
            .set_coercer(boost::bind(&dbsrx::set_gain, this, _1, name))
            .set(dbsrx_gain_ranges[name].start());
        this->get_rx_subtree()->create<meta_range_t>("gains/"+name+"/range")
            .set(dbsrx_gain_ranges[name]);
    }
    this->get_rx_subtree()->create<double>("freq/value")
        .set_coercer(boost::bind(&dbsrx::set_lo_freq, this, _1));
    this->get_rx_subtree()->create<meta_range_t>("freq/range")
        .set(dbsrx_freq_range);
    this->get_rx_subtree()->create<std::string>("antenna/value")
        .set(dbsrx_antennas.at(0));
    this->get_rx_subtree()->create<std::vector<std::string> >("antenna/options")
        .set(dbsrx_antennas);
    this->get_rx_subtree()->create<std::string>("connection")
        .set("IQ");
    this->get_rx_subtree()->create<bool>("enabled")
        .set(true); //always enabled
    this->get_rx_subtree()->create<bool>("use_lo_offset")
        .set(false);
    this->get_rx_subtree()->create<double>("bandwidth/value")
        .set_coercer(boost::bind(&dbsrx::set_bandwidth, this, _1));
    this->get_rx_subtree()->create<meta_range_t>("bandwidth/range")
        .set(dbsrx_bandwidth_range);

    //enable only the clocks we need
    this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true);

    //set the gpio directions and atr controls (identically)
    this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, 0x0); // All unused in atr
    if (this->get_iface()->get_special_props().soft_clock_divider){
        this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0x1); // GPIO0 is clock when on USRP1
    }
    else{
        this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0x0); // All Inputs
    }

    //now its safe to set inital freq and bw
    this->get_rx_subtree()->access<double>("freq/value")
        .set(dbsrx_freq_range.start());
    this->get_rx_subtree()->access<double>("bandwidth/value")
        .set(2.0*_bandwidth); //_bandwidth in lowpass, convert to complex bandpass
}
コード例 #16
0
/***********************************************************************
 * Tuning
 **********************************************************************/
void xcvr2450::set_lo_freq(double target_freq) {

    //clip the input to the range
    target_freq = xcvr_freq_range.clip(target_freq);

    //variables used in the calculation below
    double scaler = xcvr2450::is_highband(target_freq)? (4.0/5.0) : (4.0/3.0);
    double ref_freq = this->get_iface()->get_clock_rate(dboard_iface::UNIT_TX);
    int R, intdiv, fracdiv;

    //loop through values until we get a match
    for(_ad9515div = 2; _ad9515div <= 3; _ad9515div++) {
        for(R = 1; R <= 7; R++) {
            double N = (target_freq*scaler*R*_ad9515div)/ref_freq;
            intdiv = int(std::floor(N));
            fracdiv = boost::math::iround((N - intdiv)*double(1 << 16));
            //actual minimum is 128, but most chips seems to require higher to lock
            if (intdiv < 131 or intdiv > 255) continue;
            //constraints met: exit loop
            goto done_loop;
        }
    }
done_loop:

    //calculate the actual freq from the values above
    double N = double(intdiv) + double(fracdiv)/double(1 << 16);
    _lo_freq = (N*ref_freq)/(scaler*R*_ad9515div);

    if (xcvr2450_debug) std::cerr
                << boost::format("XCVR2450 tune:\n")
                << boost::format("    R=%d, N=%f, ad9515=%d, scaler=%f\n") % R % N % _ad9515div % scaler
                << boost::format("    Ref    Freq=%fMHz\n") % (ref_freq/1e6)
                << boost::format("    Target Freq=%fMHz\n") % (target_freq/1e6)
                << boost::format("    Actual Freq=%fMHz\n") % (_lo_freq/1e6)
                << std::endl;

    //high-high band or low-high band?
    if(_lo_freq > (5.35e9 + 5.47e9)/2.0) {
        if (xcvr2450_debug) std::cerr << "XCVR2450 tune: Using  high-high band" << std::endl;
        _max2829_regs.band_select_802_11a = max2829_regs_t::BAND_SELECT_802_11A_5_47GHZ_TO_5_875GHZ;
    } else {
        if (xcvr2450_debug) std::cerr << "XCVR2450 tune: Using  low-high band" << std::endl;
        _max2829_regs.band_select_802_11a = max2829_regs_t::BAND_SELECT_802_11A_4_9GHZ_TO_5_35GHZ;
    }

    //new band select settings and ad9515 divider
    this->update_atr();

    //load new counters into registers
    _max2829_regs.int_div_ratio_word = intdiv;
    _max2829_regs.frac_div_ratio_lsb = fracdiv & 0x3;
    _max2829_regs.frac_div_ratio_msb = fracdiv >> 2;
    this->send_reg(0x3); //integer
    this->send_reg(0x4); //fractional

    //load the reference divider and band select into registers
    //toggle the bandswitch from off to automatic (which really means start)
    _max2829_regs.ref_divider = R;
    _max2829_regs.band_select = (xcvr2450::is_highband(_lo_freq))?
                                max2829_regs_t::BAND_SELECT_5GHZ   :
                                max2829_regs_t::BAND_SELECT_2_4GHZ ;
    _max2829_regs.vco_bandswitch = max2829_regs_t::VCO_BANDSWITCH_DISABLE;
    this->send_reg(0x5);
    _max2829_regs.vco_bandswitch = max2829_regs_t::VCO_BANDSWITCH_AUTOMATIC;;
    this->send_reg(0x5);
}
コード例 #17
0
ファイル: db_wbx_simple.cpp プロジェクト: GREO/uhd
void wbx_simple::set_tx_lo_freq(double freq){
    _tx_lo_freq = set_lo_freq(dboard_iface::UNIT_TX, wbx_freq_range.clip(freq));
}
コード例 #18
0
ファイル: db_rfx.cpp プロジェクト: excursionator/uhd
/***********************************************************************
 * Tuning
 **********************************************************************/
double rfx_xcvr::set_lo_freq(
    dboard_iface::unit_t unit,
    double target_freq
){
    UHD_LOGGER_TRACE("RFX") << boost::format(
        "RFX tune: target frequency %f MHz"
    ) % (target_freq/1e6) ;

    //clip the input
    target_freq = _freq_range.clip(target_freq);
    if (_div2[unit]) target_freq *= 2;

    //rfx400 rx is a special case with div2 in mixer, so adf4360 must output fundamental
    bool is_rx_rfx400 = ((get_rx_id() == 0x0024) && unit != dboard_iface::UNIT_TX);

    //map prescalers to the register enums
    static const uhd::dict<int, adf4360_regs_t::prescaler_value_t> prescaler_to_enum = map_list_of
        (8,  adf4360_regs_t::PRESCALER_VALUE_8_9)
        (16, adf4360_regs_t::PRESCALER_VALUE_16_17)
        (32, adf4360_regs_t::PRESCALER_VALUE_32_33)
    ;

    //map band select clock dividers to enums
    static const uhd::dict<int, adf4360_regs_t::band_select_clock_div_t> bandsel_to_enum = map_list_of
        (1, adf4360_regs_t::BAND_SELECT_CLOCK_DIV_1)
        (2, adf4360_regs_t::BAND_SELECT_CLOCK_DIV_2)
        (4, adf4360_regs_t::BAND_SELECT_CLOCK_DIV_4)
        (8, adf4360_regs_t::BAND_SELECT_CLOCK_DIV_8)
    ;

    double actual_freq=0, ref_freq = this->get_iface()->get_clock_rate(unit);
    int R=0, BS=0, P=0, B=0, A=0;

    /*
     * The goal here to to loop though possible R dividers,
     * band select clock dividers, and prescaler values.
     * Calculate the A and B counters for each set of values.
     * The loop exits when it meets all of the constraints.
     * The resulting loop values are loaded into the registers.
     *
     * fvco = [P*B + A] * fref/R
     * fvco*R/fref = P*B + A = N
     */
    for(R = 2; R <= 32; R+=2){
        for(auto BS:  bandsel_to_enum.keys()){
            if (ref_freq/R/BS > 1e6) continue; //constraint on band select clock
            for(auto P:  prescaler_to_enum.keys()){
                //calculate B and A from N
                double N = target_freq*R/ref_freq;
                B = int(std::floor(N/P));
                A = boost::math::iround(N - P*B);
                if (B < A or B > 8191 or B < 3 or A > 31) continue; //constraints on A, B
                //calculate the actual frequency
                actual_freq = double(P*B + A)*ref_freq/R;
                if (actual_freq/P > 300e6) continue; //constraint on prescaler output
                //constraints met: exit loop
                goto done_loop;
            }
        }
    } done_loop:

    UHD_LOGGER_TRACE("RFX") << boost::format(
        "RFX tune: R=%d, BS=%d, P=%d, B=%d, A=%d, DIV2=%d"
    ) % R % BS % P % B % A % int(_div2[unit] && (!is_rx_rfx400)) ;

    //load the register values
    adf4360_regs_t regs;
    regs.core_power_level        = adf4360_regs_t::CORE_POWER_LEVEL_10MA;
    regs.counter_operation       = adf4360_regs_t::COUNTER_OPERATION_NORMAL;
    regs.muxout_control          = adf4360_regs_t::MUXOUT_CONTROL_DLD;
    regs.phase_detector_polarity = adf4360_regs_t::PHASE_DETECTOR_POLARITY_POS;
    regs.charge_pump_output      = adf4360_regs_t::CHARGE_PUMP_OUTPUT_NORMAL;
    regs.cp_gain_0               = adf4360_regs_t::CP_GAIN_0_SET1;
    regs.mute_till_ld            = adf4360_regs_t::MUTE_TILL_LD_ENB;
    regs.output_power_level      = adf4360_regs_t::OUTPUT_POWER_LEVEL_3_5MA;
    regs.current_setting1        = adf4360_regs_t::CURRENT_SETTING1_0_31MA;
    regs.current_setting2        = adf4360_regs_t::CURRENT_SETTING2_0_31MA;
    regs.power_down              = adf4360_regs_t::POWER_DOWN_NORMAL_OP;
    regs.prescaler_value         = prescaler_to_enum[P];
    regs.a_counter               = A;
    regs.b_counter               = B;
    regs.cp_gain_1               = adf4360_regs_t::CP_GAIN_1_SET1;
    regs.divide_by_2_output      = (_div2[unit] && (!is_rx_rfx400)) ?  // Special case RFX400 RX Mixer divides by two
                                    adf4360_regs_t::DIVIDE_BY_2_OUTPUT_DIV2 :
                                    adf4360_regs_t::DIVIDE_BY_2_OUTPUT_FUND ;
    regs.divide_by_2_prescaler   = adf4360_regs_t::DIVIDE_BY_2_PRESCALER_FUND;
    regs.r_counter               = R;
    regs.ablpw                   = adf4360_regs_t::ABLPW_3_0NS;
    regs.lock_detect_precision   = adf4360_regs_t::LOCK_DETECT_PRECISION_5CYCLES;
    regs.test_mode_bit           = 0;
    regs.band_select_clock_div   = bandsel_to_enum[BS];

    //write the registers
    std::vector<adf4360_regs_t::addr_t> addrs = list_of //correct power-up sequence to write registers (R, C, N)
        (adf4360_regs_t::ADDR_RCOUNTER)
        (adf4360_regs_t::ADDR_CONTROL)
        (adf4360_regs_t::ADDR_NCOUNTER)
    ;
    for(adf4360_regs_t::addr_t addr:  addrs){
        this->get_iface()->write_spi(
            unit, spi_config_t::EDGE_RISE,
            regs.get_reg(addr), 24
        );
    }

    //return the actual frequency
    if (_div2[unit]) actual_freq /= 2;
    UHD_LOGGER_TRACE("RFX") << boost::format(
        "RFX tune: actual frequency %f MHz"
    ) % (actual_freq/1e6) ;
    return actual_freq;
}