diff options
| author | Josh Blum <josh@joshknows.com> | 2010-04-22 18:18:44 -0700 | 
|---|---|---|
| committer | Josh Blum <josh@joshknows.com> | 2010-04-22 18:18:44 -0700 | 
| commit | 3551ef506737576d15b86b151bce3ae225d36092 (patch) | |
| tree | 5c77bc7f20befe6bc8db42d4068c3098ec55e2cd /host/lib | |
| parent | fd1067907d6e19249129d52bb7dcfd3f7b21d7d1 (diff) | |
| download | uhd-3551ef506737576d15b86b151bce3ae225d36092.tar.gz uhd-3551ef506737576d15b86b151bce3ae225d36092.tar.bz2 uhd-3551ef506737576d15b86b151bce3ae225d36092.zip | |
filled in xcvr tuning, set gain, spi reset
Diffstat (limited to 'host/lib')
| -rwxr-xr-x | host/lib/ic_reg_maps/gen_max2829_regs.py | 2 | ||||
| -rw-r--r-- | host/lib/usrp/dboard/db_xcvr2450.cpp | 165 | 
2 files changed, 152 insertions, 15 deletions
| diff --git a/host/lib/ic_reg_maps/gen_max2829_regs.py b/host/lib/ic_reg_maps/gen_max2829_regs.py index 91a711ecc..46b48dfe7 100755 --- a/host/lib/ic_reg_maps/gen_max2829_regs.py +++ b/host/lib/ic_reg_maps/gen_max2829_regs.py @@ -44,7 +44,7 @@ mimo_select           2[13]         0                 normal, mimo  ########################################################################  ## Integer Divider Ratio (3)  ######################################################################## -id_ratio_word         3[0:7]        a2 +int_div_ratio_word    3[0:7]        a2  frac_div_ratio_lsb    3[12:13]      0  ########################################################################  ## Fractional Divider Ratio (4) diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp index 8002acc01..fbce4b932 100644 --- a/host/lib/usrp/dboard/db_xcvr2450.cpp +++ b/host/lib/usrp/dboard/db_xcvr2450.cpp @@ -68,16 +68,19 @@ using namespace boost::assign;  /***********************************************************************   * The XCVR 2450 constants   **********************************************************************/ +static const bool xcvr2450_debug = true; +  static const freq_range_t xcvr_freq_range(2.4e9, 6.0e9);  static const prop_names_t xcvr_antennas = list_of("J1")("J2");  static const uhd::dict<std::string, gain_range_t> xcvr_tx_gain_ranges = map_list_of      ("VGA", gain_range_t(0, 30, 0.5)) +    ("BB", gain_range_t(0, 5, 1.5))  ;  static const uhd::dict<std::string, gain_range_t> xcvr_rx_gain_ranges = map_list_of -    ("RF LNA", gain_range_t(0, 30.5, 15)) -    ("BB VGA", gain_range_t(0, 62, 2.0)) +    ("LNA", gain_range_t(0, 30.5, 15)) +    ("VGA", gain_range_t(0, 62, 2.0))  ;  /*********************************************************************** @@ -108,6 +111,14 @@ private:      void set_rx_gain(float gain, const std::string &name);      void update_atr(void); +    void spi_reset(void); +    void send_reg(boost::uint8_t addr){ +        this->get_iface()->write_spi( +            dboard_iface::UNIT_RX, +            spi_config_t::EDGE_RISE, +            _max2829_regs.get_reg(addr), 24 +        ); +    }  };  /*********************************************************************** @@ -134,22 +145,54 @@ xcvr2450::xcvr2450(ctor_args_t const& args) : xcvr_dboard_base(args){      this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, TXIO_MASK);      this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, RXIO_MASK); +    spi_reset(); //prepare the spi + +    //setup the misc max2829 registers +    _max2829_regs.mimo_select         = max2829_regs_t::MIMO_SELECT_MIMO; +    _max2829_regs.band_sel_mimo       = max2829_regs_t::BAND_SEL_MIMO_MIMO; +    _max2829_regs.pll_cp_select       = max2829_regs_t::PLL_CP_SELECT_4MA; +    _max2829_regs.rssi_high_bw        = max2829_regs_t::RSSI_HIGH_BW_6MHZ; +    _max2829_regs.tx_lpf_coarse_adj   = max2829_regs_t::TX_LPF_COARSE_ADJ_12MHZ; +    _max2829_regs.rx_lpf_coarse_adj   = max2829_regs_t::RX_LPF_COARSE_ADJ_9_5MHZ; +    _max2829_regs.rx_lpf_fine_adj     = max2829_regs_t::RX_LPF_FINE_ADJ_95; +    _max2829_regs.rx_vga_gain_spi     = max2829_regs_t::RX_VGA_GAIN_SPI_SPI; +    _max2829_regs.rssi_output_range   = max2829_regs_t::RSSI_OUTPUT_RANGE_HIGH; +    _max2829_regs.rssi_op_mode        = max2829_regs_t::RSSI_OP_MODE_ENABLED; +    _max2829_regs.rssi_pin_fcn        = max2829_regs_t::RSSI_PIN_FCN_RSSI; +    _max2829_regs.rx_highpass         = max2829_regs_t::RX_HIGHPASS_100HZ; +    _max2829_regs.tx_vga_gain_spi     = max2829_regs_t::TX_VGA_GAIN_SPI_SPI; +    _max2829_regs.pa_driver_linearity = max2829_regs_t::PA_DRIVER_LINEARITY_78; +    _max2829_regs.tx_vga_linearity    = max2829_regs_t::TX_VGA_LINEARITY_78; +    _max2829_regs.tx_upconv_linearity = max2829_regs_t::TX_UPCONV_LINEARITY_78; + +    //send initial register settings +    for(boost::uint8_t reg = 0; reg <= 0xC; reg++){ +        this->send_reg(reg); +    } +      //set defaults for LO, gains, antennas      set_lo_freq(2.45e9);      set_rx_ant("J1");      set_tx_ant("J2"); -    set_rx_gain(0, "RF LNA"); -    set_rx_gain(0, "BB VGA"); +    set_rx_gain(0, "LNA"); +    set_rx_gain(0, "VGA");      set_tx_gain(0, "VGA"); +    set_tx_gain(0, "BB");  }  xcvr2450::~xcvr2450(void){ -    /* NOP */ +    spi_reset(); +} + +void xcvr2450::spi_reset(void){ +    //spi reset mode: global enable = off, tx and rx enable = on +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE, TX_ENB_TXIO); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, RX_ENB_RXIO);  }  void xcvr2450::update_atr(void){      //calculate tx atr pins -    int band_sel   = (_lo_freq > 4e9)? HB_PA_TXIO : LB_PA_TXIO; +    int band_sel   = (_lo_freq > 3e9)? HB_PA_TXIO : LB_PA_TXIO;      int tx_ant_sel = (_tx_ant == "J1")? ANTSEL_TX1_RX2_TXIO : ANTSEL_TX2_RX1_TXIO;      int rx_ant_sel = (_rx_ant == "J1")? ANTSEL_TX1_RX2_TXIO : ANTSEL_TX2_RX1_TXIO;      int xx_ant_sel = tx_ant_sel; //prefer the tx antenna selection for full duplex (rx will get the other antenna) @@ -172,8 +215,57 @@ void xcvr2450::update_atr(void){   * Tuning   **********************************************************************/  void xcvr2450::set_lo_freq(double target_freq){ -    //TODO -    //set _ad9515div +    //variables used in the calculation below +    double scaler = (_lo_freq > 3e9)? (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(R = 1; R <= 7; R++){ +        for(_ad9515div = 2; _ad9515div <= 3; _ad9515div++){ +            double N = (target_freq*scaler*R*_ad9515div)/ref_freq; +            intdiv = int(std::floor(N)); +            fracdiv = (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 = (scaler*R*_ad9515div)/(N*ref_freq); + +    if (xcvr2450_debug) std::cerr << boost::format( +        "XCVR2450 tune: R=%d, N=%f, ad9515=%d, scaler=%f\n" +        "               Target Freq=%fMHz, Actual Freq=%fMHz" +    ) % R % N % _ad9515div % scaler % (target_freq/1e6) % (_lo_freq/1e6) << std::endl; + +    //high-high band or low-high band? +    if(_lo_freq > (5.35e9 + 4.47e9)/2.0){ +        _max2829_regs.band_select_802_11a = max2829_regs_t::BAND_SELECT_802_11A_5_47GHZ_TO_5_875GHZ; +    }else{ +        _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.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);  }  /*********************************************************************** @@ -181,12 +273,14 @@ void xcvr2450::set_lo_freq(double target_freq){   **********************************************************************/  void xcvr2450::set_tx_ant(const std::string &ant){      assert_has(xcvr_antennas, ant, "xcvr antenna name"); -    //TODO +   _tx_ant = ant; +    this->update_atr(); //sets the atr to the new antenna setting  }  void xcvr2450::set_rx_ant(const std::string &ant){      assert_has(xcvr_antennas, ant, "xcvr antenna name"); -    //TODO +    _rx_ant = ant; +    this->update_atr(); //sets the atr to the new antenna setting  }  /*********************************************************************** @@ -212,12 +306,37 @@ static int gain_to_tx_vga_reg(float &gain){  }  /*! + * Convert a requested gain for the tx bb into the integer register value. + * The gain passed into the function will be set to the actual value. + * \param gain the requested gain in dB + * \return gain enum value + */ +static max2829_regs_t::tx_baseband_gain_t gain_to_tx_bb_reg(float &gain){ +    int reg = std::clip(boost::math::iround(gain*3/5.0), 0, 3); +    switch(reg){ +    case 0: +        gain = 0; +        return max2829_regs_t::TX_BASEBAND_GAIN_0DB; +    case 1: +        gain = 2; +        return max2829_regs_t::TX_BASEBAND_GAIN_2DB; +    case 2: +        gain = 3.5; +        return max2829_regs_t::TX_BASEBAND_GAIN_3_5DB; +    case 3: +        gain = 5; +        return max2829_regs_t::TX_BASEBAND_GAIN_5DB; +    } +    ASSERT_THROW(false); +} + +/*!   * Convert a requested gain for the rx vga into the integer register value.   * The gain passed into the function will be set to the actual value.   * \param gain the requested gain in dB   * \return 5 bit the register value   */ -static int gain_to_rx_bb_vga_reg(float &gain){ +static int gain_to_rx_vga_reg(float &gain){      int reg = std::clip(boost::math::iround(gain/2.0), 0, 31);      gain = reg*2;      return reg; @@ -229,7 +348,7 @@ static int gain_to_rx_bb_vga_reg(float &gain){   * \param gain the requested gain in dB   * \return 2 bit the register value   */ -static int gain_to_rx_rf_lna_reg(float &gain){ +static int gain_to_rx_lna_reg(float &gain){      int reg = std::clip(boost::math::iround(gain*2/30.5) + 1, 0, 3);      switch(reg){      case 0: @@ -242,12 +361,30 @@ static int gain_to_rx_rf_lna_reg(float &gain){  void xcvr2450::set_tx_gain(float gain, const std::string &name){      assert_has(xcvr_tx_gain_ranges.keys(), name, "xcvr tx gain name"); -    //TODO +    if (name == "VGA"){ +        _max2829_regs.tx_vga_gain = gain_to_tx_vga_reg(gain); +        send_reg(0xC); +    } +    else if(name == "BB"){ +        _max2829_regs.tx_baseband_gain = gain_to_tx_bb_reg(gain); +        send_reg(0x9); +    } +    else ASSERT_THROW(false); +    _tx_gains[name] = gain;  }  void xcvr2450::set_rx_gain(float gain, const std::string &name){      assert_has(xcvr_rx_gain_ranges.keys(), name, "xcvr rx gain name"); -    //TODO +    if (name == "VGA"){ +        _max2829_regs.rx_vga_gain = gain_to_rx_vga_reg(gain); +        send_reg(0xB); +    } +    else if(name == "LNA"){ +        _max2829_regs.rx_lna_gain = gain_to_rx_lna_reg(gain); +        send_reg(0xB); +    } +    else ASSERT_THROW(false); +    _rx_gains[name] = gain;  }  /*********************************************************************** | 
