diff options
| author | Nick Foster <nick@nerdnetworks.org> | 2010-09-28 13:52:09 -0700 | 
|---|---|---|
| committer | Nick Foster <nick@nerdnetworks.org> | 2010-09-28 13:52:09 -0700 | 
| commit | 15eacbd920a0527ec16c24baeb1d6b87f29d9110 (patch) | |
| tree | 7ed14b4522fa6236b193b21aaf9909a4e8091a20 /host/lib | |
| parent | a6f60ab4911fa756656a62ebe3a1093d52836a6e (diff) | |
| download | uhd-15eacbd920a0527ec16c24baeb1d6b87f29d9110.tar.gz uhd-15eacbd920a0527ec16c24baeb1d6b87f29d9110.tar.bz2 uhd-15eacbd920a0527ec16c24baeb1d6b87f29d9110.zip | |
TVRX: Don't have mboard impl modified for ADC buffer disable. The rest of TVRX should be in there. Not debugged.
Diffstat (limited to 'host/lib')
| -rw-r--r-- | host/lib/usrp/dboard/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | host/lib/usrp/dboard/db_tvrx.cpp | 219 | ||||
| -rw-r--r-- | host/lib/usrp/usrp1/codec_ctrl.cpp | 13 | ||||
| -rw-r--r-- | host/lib/usrp/usrp1/codec_ctrl.hpp | 3 | 
4 files changed, 147 insertions, 89 deletions
| diff --git a/host/lib/usrp/dboard/CMakeLists.txt b/host/lib/usrp/dboard/CMakeLists.txt index 3e995009e..8d3d11530 100644 --- a/host/lib/usrp/dboard/CMakeLists.txt +++ b/host/lib/usrp/dboard/CMakeLists.txt @@ -24,5 +24,6 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_wbx.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_dbsrx.cpp      ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_unknown.cpp +    ${CMAKE_SOURCE_DIR}/lib/usrp/dboard/db_tvrx.cpp  ) diff --git a/host/lib/usrp/dboard/db_tvrx.cpp b/host/lib/usrp/dboard/db_tvrx.cpp index ed6025433..2988367e2 100644 --- a/host/lib/usrp/dboard/db_tvrx.cpp +++ b/host/lib/usrp/dboard/db_tvrx.cpp @@ -39,9 +39,11 @@  #include <boost/assign/list_of.hpp>  #include <boost/format.hpp>  #include <boost/thread.hpp> +#include <boost/array.hpp>  #include <boost/math/special_functions/round.hpp>  #include <utility>  #include <cmath> +#include <cfloat>  #include <tuner_4937di5_regs.hpp>  using namespace uhd; @@ -55,12 +57,11 @@ static const bool tvrx_debug = true;  static const freq_range_t tvrx_freq_range(50e6, 860e6); -static const prop_names_t tvrx_antennas = ""; //only got one +static const std::string tvrx_antennas = std::string(""); //only got one -static const uhd::dict<std::string, gain_range_t> tvrx_gain_ranges = map_list_of -    ("RF", gain_range_t(-13.3, 50.3, float(50.3/4096))) //both gains are analog and controlled by DAC -    ("IF", gain_range_t(-1.5, 32.5, float(32.5/4096))) //the old driver used 1dB for both; i don't think that's right? -; +//a note on these: the gain of the TVRX varies over frequency. the gain ranges +//below correspond to the maximum and minimum gains over the entire frequency range. +//specifying a gain higher or lower than the TVRX can accomplish will of course just clip.  static const uhd::dict<std::string, freq_range_t> tvrx_freq_ranges = map_list_of      ("VHFLO", freq_range_t(50e6, 158e6)) @@ -68,63 +69,68 @@ static const uhd::dict<std::string, freq_range_t> tvrx_freq_ranges = map_list_of      ("UHF"  , freq_range_t(454e6, 860e6))  ; +static const boost::array<float, 17> vhflo_gains_db =  +    {{-6.00000, -6.00000, -6.00000, -4.00000, 0.00000, +     5.00000, 10.00000, 17.40000, 26.30000, 36.00000, +     43.00000, 48.00000, 49.50000, 50.10000, 50.30000, +     50.30000, 50.30000}}; +                                  +static const boost::array<float, 17> vhfhi_gains_db =  +    {{13.3000,  -13.3000,  -13.3000,   -1.0000,    7.7000, +    11.0000,   14.7000,   19.3000,   26.1000,   36.0000, +    42.7000,   46.0000,   47.0000,   47.8000,   48.2000, +    48.2000,   48.2000}}; +     +static const boost::array<float, 17> uhf_gains_db = +    {{-8.0000,   -8.0000,   -7.0000,    4.0000,   10.2000, +     14.5000,   17.5000,   20.0000,   24.5000,   30.8000, +     37.0000,   39.8000,   40.7000,   41.6000,   42.6000, +     43.2000,   43.8000}}; +      +static const boost::array<float, 17> tvrx_if_gains_db =  +    {{-1.50000,   -1.50000,   -1.50000,   -1.00000,    0.20000, +     2.10000,    4.30000,    6.40000,    9.00000,   12.00000, +     14.80000,   18.20000,   26.10000,   32.50000,  32.50000, +     32.50000,   32.50000}}; +  //gain linearization data  //this is from the datasheet and is dB vs. volts (below)  //i tried to curve fit this, but it's really just so nonlinear that you'd  //need dang near as many coefficients as to just map it like this and interp.  //these numbers are culled from the 4937DI5 datasheet and are probably totally inaccurate  //but if it's better than the old linear fit i'm happy -static const uhd::dict<std::string, std::vector<float> > tvrx_rf_gains_db = map_list_of -    ("VHFLO", std::vector<float>(-6.00000, -6.00000, -6.00000, -4.00000, 0.00000, -                                 5.00000, 10.00000, 17.40000, 26.30000, 36.00000, -                                 43.00000, 48.00000, 49.50000, 50.10000, 50.30000, -                                 50.30000, 50.30000)) -    ("VHFHI", std::vector<float>(-13.3000,  -13.3000,  -13.3000,   -1.0000,    7.7000, -                                 11.0000,   14.7000,   19.3000,   26.1000,   36.0000, -                                 42.7000,   46.0000,   47.0000,   47.8000,   48.2000, -                                 48.2000,   48.2000)) -    ("UHF"  , std::vector<float>(-8.0000,   -8.0000,   -7.0000,    4.0000,   10.2000, -                                 14.5000,   17.5000,   20.0000,   24.5000,   30.8000, -                                 37.0000,   39.8000,   40.7000,   41.6000,   42.6000, -                                 43.2000,   43.8000)) -; - -static const std::vector<float> tvrx_if_gains_db =  -              std::vector<float>(-1.50000,   -1.50000,   -1.50000,   -1.00000,    0.20000, -                                 2.10000,    4.30000,    6.40000,    9.00000,   12.00000, -                                 14.80000,   18.20000,   26.10000,   32.50000,  32.50000, -                                 32.50000,   32.50000) +static const uhd::dict<std::string, boost::array<float, 17> > tvrx_rf_gains_db = map_list_of +    ("VHFLO", vhflo_gains_db) +    ("VHFHI", vhfhi_gains_db) +    ("UHF"  , uhf_gains_db)  ;  //sample voltages for the above points -static const std::vector<float> tvrx_rf_gains_volts =  -              std::vector<float>(0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0); - - -/*! - * Execute a linear interpolation to find the voltage corresponding to a desired gain - * \param gain the desired gain in dB - * \param db_vector the vector of dB readings - * \param volts_vector the corresponding vector of voltages db_vector was sampled at - * \return a voltage to feed the TVRX analog gain - */ - -static float gain_interp(float gain, std::vector<float> db_vector, std::vector<float> volts_vector) { -    float volts; -    gain = std::clip<float>(gain, db_vector.front(), db_vector.back()); //let's not get carried away here -     -    boost::uint8_t gain_step = 0; -    for(int i = 0; i < db_vector.size()-1; i++) { -        if(gain > db_vector[i] && gain < db_vector.[i+1]) gain_step = i; +static const boost::array<float, 17> tvrx_gains_volts =  +    {{0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0, 2.2, 2.4, 2.6, 2.8, 3.0, 3.2, 3.4, 3.6, 3.8, 4.0}}; + +static uhd::dict<std::string, gain_range_t> get_tvrx_gain_ranges(void) { +    float rfmax = 0.0, rfmin = FLT_MAX; +    BOOST_FOREACH(const std::string range, tvrx_rf_gains_db.keys()) { +        float my_max = tvrx_rf_gains_db[range].back(); //we're assuming it's monotonic +        float my_min = tvrx_rf_gains_db[range].front(); //if it's not this is wrong wrong wrong +        if(my_max > rfmax) rfmax = my_max; +        if(my_min < rfmin) rfmin = my_min;      } -         -    return volts; +    float ifmin = tvrx_if_gains_db.front(); +    float ifmax = tvrx_if_gains_db.back(); +     +    return map_list_of +        ("RF", gain_range_t(rfmin, rfmax, (rfmax-rfmin)/4096.0)) +        ("IF", gain_range_t(ifmin, ifmax, (ifmax-ifmin)/4096.0)) +        ;  }  static const double opamp_gain = 1.22; //onboard DAC opamp gain -static const double tvrx_lo_freq = 43.75e6; //LO freq of TVRX module +static const double tvrx_if_freq = 43.75e6; //IF freq of TVRX module  static const boost::uint16_t reference_divider = 640; //clock reference divider to use +static const double reference_freq = 4.0e6;  /***********************************************************************   * The tvrx dboard class @@ -139,12 +145,14 @@ public:  private:      uhd::dict<std::string, float> _gains; +    double _lo_freq;      tuner_4937di5_regs_t _tuner_4937di5_regs;      boost::uint8_t _tuner_4937di5_addr(void){          return (this->get_iface()->get_special_props().mangle_i2c_addrs)? 0x60 : 0x61; //ok really? we could rename that call      };      void set_gain(float gain, const std::string &name); +    void set_freq(double freq);      void update_regs(void){          byte_vector_t regs_vector(4); @@ -192,12 +200,14 @@ tvrx::tvrx(ctor_args_t args) : rx_dboard_base(args){          this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0x0); // All Inputs      } -    //send initial register settings -    //HAAAAY GUYYYYYSSS +    //send initial register settings if necessary +     +    //set default freq +    set_freq(tvrx_freq_range.min);      //set default gains -    BOOST_FOREACH(const std::string &name, tvrx_gain_ranges.keys()){ -        set_gain(tvrx_gain_ranges[name].min, name); +    BOOST_FOREACH(const std::string &name, get_tvrx_gain_ranges().keys()){ +        set_gain(get_tvrx_gain_ranges()[name].min, name);      }  } @@ -212,7 +222,7 @@ tvrx::~tvrx(void){  static std::string get_band(double freq) {      BOOST_FOREACH(const std::string &band, tvrx_freq_ranges.keys()) {          if(freq >= tvrx_freq_ranges[band].min && freq <= tvrx_freq_ranges[band].max) -            return name; +            return band;      }      UHD_THROW_INVALID_CODE_PATH();  } @@ -220,17 +230,34 @@ static std::string get_band(double freq) {  /***********************************************************************   * Gain Handling   **********************************************************************/ -/*  - * Gain accuracy on this thing is basically a crap shoot. In other words, there is none. - * The old driver basically picked a linear approximation of the median gain, but the actual - * gain slope is heavily nonlinear and varies both with gain and with frequency. - * It also probably varies markedly over temperature, but there's only so much we can do. - * The best approximation to the RF gain data is fifth-order. If we ignore the curve portions - * below 0dB (yes, it's a pad below a certain gain value) and if we ignore the curve portions - * near the max-gain asymptotes, it looks pretty close to third-order. This is less insane to - * approximate. +/*! + * Execute a linear interpolation to find the voltage corresponding to a desired gain + * \param gain the desired gain in dB + * \param db_vector the vector of dB readings + * \param volts_vector the corresponding vector of voltages db_vector was sampled at + * \return a voltage to feed the TVRX analog gain   */ +static float gain_interp(float gain, boost::array<float, 17> db_vector, boost::array<float, 17> volts_vector) { +    float volts; +    gain = std::clip<float>(gain, db_vector.front(), db_vector.back()); //let's not get carried away here +     +    boost::uint8_t gain_step = 0; +    //find which bin we're in +    for(size_t i = 0; i < db_vector.size()-1; i++) { +        if(gain > db_vector[i] && gain < db_vector[i+1]) gain_step = i; +    } +     +    //find the current slope for linear interpolation +    float slope = (volts_vector[gain_step + 1] - volts_vector[gain_step])  +                / (db_vector[gain_step + 1] - db_vector[gain_step]); + +    //use the volts per dB slope to find the final interpolated voltage +    volts = volts_vector[gain_step] + (slope * (gain - db_vector[gain_step])); +     +    return volts; +} +  /*!   * Convert a requested gain for the RF gain into a DAC voltage.   * The gain passed into the function will be set to the actual value. @@ -238,22 +265,18 @@ static std::string get_band(double freq) {   * \return dac voltage value   */ -static float rf_gain_to_voltage(float &gain){ +static float rf_gain_to_voltage(float gain, double lo_freq){      //clip the input -    gain = std::clip<float>(gain, tvrx_gain_ranges["RF"].min, tvrx_gain_ranges["RF"].max); +    gain = std::clip<float>(gain, get_tvrx_gain_ranges()["RF"].min, get_tvrx_gain_ranges()["RF"].max); -    //voltage level constants -    static const float max_volts = float(4.0), min_volts = float(0.6); -    static const float slope = (max_volts-min_volts)/tvrx_gain_ranges["RF"].max; +    //first we need to find out what band we're in, because gains are different across different bands +    std::string band = get_band(lo_freq + tvrx_if_freq);      //this is the voltage at the TVRX gain input -    float gain_volts = gain*slope + min_volts +    float gain_volts = gain_interp(gain, tvrx_rf_gains_db[band], tvrx_gains_volts);      //this is the voltage at the USRP DAC output      float dac_volts = gain_volts / opamp_gain; -    //the actual gain setting -    gain = (dac_volts - min_volts)/slope; -      if (tvrx_debug) std::cerr << boost::format(          "tvrx RF AGC gain: %f dB, dac_volts: %f V"      ) % gain % dac_volts << std::endl; @@ -268,22 +291,13 @@ static float rf_gain_to_voltage(float &gain){   * \return dac voltage value   */ -static float if_gain_to_voltage(float &gain){ +static float if_gain_to_voltage(float gain){      //clip the input -    gain = std::clip<float>(gain, tvrx_gain_ranges["IF"].min, tvrx_gain_ranges["IF"].max); - -    //voltage level constants -    static const float max_volts = float(4.0), min_volts = float(0.0); -    static const float slope = (max_volts-min_volts)/tvrx_gain_ranges["IF"].max; - -    //this is the voltage at the TVRX gain input -    float gain_volts = gain*slope + 1.25; -    //this is the voltage at the USRP DAC output +    gain = std::clip<float>(gain, get_tvrx_gain_ranges()["IF"].min, get_tvrx_gain_ranges()["IF"].max); +     +    float gain_volts = gain_interp(gain, tvrx_if_gains_db, tvrx_gains_volts);      float dac_volts = gain_volts / opamp_gain; -    //the actual gain setting -    gain = (dac_volts - min_volts)/slope; -      if (tvrx_debug) std::cerr << boost::format(          "tvrx IF AGC gain: %f dB, dac_volts: %f V"      ) % gain % dac_volts << std::endl; @@ -292,9 +306,9 @@ static float if_gain_to_voltage(float &gain){  }  void tvrx::set_gain(float gain, const std::string &name){ -    assert_has(tvrx_gain_ranges.keys(), name, "tvrx gain name"); +    assert_has(get_tvrx_gain_ranges().keys(), name, "tvrx gain name");      if (name == "RF"){ -        this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, rf_gain_to_voltage(gain)); +        this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_A, rf_gain_to_voltage(gain, _lo_freq));      }      else if(name == "IF"){          this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, dboard_iface::AUX_DAC_B, if_gain_to_voltage(gain)); @@ -309,9 +323,36 @@ void tvrx::set_gain(float gain, const std::string &name){   */  void tvrx::set_freq(double freq) { +    freq = std::clip<float>(freq, tvrx_freq_range.min, tvrx_freq_range.max); +    std::string prev_band = get_band(_lo_freq + tvrx_if_freq); +    std::string new_band = get_band(freq); +    double 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(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_ON; +    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"); +    _lo_freq = actual_lo_freq; //for rx props  }  /*********************************************************************** @@ -336,16 +377,16 @@ void tvrx::rx_get(const wax::obj &key_, wax::obj &val){          return;      case SUBDEV_PROP_GAIN_RANGE: -        assert_has(tvrx_gain_ranges.keys(), key.name, "tvrx gain name"); -        val = tvrx_gain_ranges[key.name]; +        assert_has(get_tvrx_gain_ranges().keys(), key.name, "tvrx gain name"); +        val = get_tvrx_gain_ranges()[key.name];          return;      case SUBDEV_PROP_GAIN_NAMES: -        val = prop_names_t(tvrx_gain_ranges.keys()); +        val = prop_names_t(get_tvrx_gain_ranges().keys());          return;      case SUBDEV_PROP_FREQ: -        val = tvrx_lo_freq; +        val = _lo_freq - tvrx_if_freq;          return;      case SUBDEV_PROP_FREQ_RANGE: diff --git a/host/lib/usrp/usrp1/codec_ctrl.cpp b/host/lib/usrp/usrp1/codec_ctrl.cpp index 08f2d2a8e..3ab02eeeb 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.cpp +++ b/host/lib/usrp/usrp1/codec_ctrl.cpp @@ -61,6 +61,9 @@ public:      float get_tx_pga_gain(void);      void set_rx_pga_gain(float, char);      float get_rx_pga_gain(char); +     +    //rx adc buffer control +    void bypass_adc_buffers(bool bypass);  private:      usrp1_iface::sptr _iface; @@ -419,6 +422,16 @@ void usrp1_codec_ctrl_impl::set_duc_freq(double freq)  }  /*********************************************************************** + * Codec Control ADC buffer bypass + * Enable this for DC-coupled daughterboards (TVRX) + **********************************************************************/ +void usrp1_codec_ctrl_impl::bypass_adc_buffers(bool bypass) { +    _ad9862_regs.byp_buffer_a = bypass; +    _ad9862_regs.byp_buffer_b = bypass; +    this->send_reg(2); +} + +/***********************************************************************   * Codec Control Make   **********************************************************************/  usrp1_codec_ctrl::sptr usrp1_codec_ctrl::make(usrp1_iface::sptr iface, diff --git a/host/lib/usrp/usrp1/codec_ctrl.hpp b/host/lib/usrp/usrp1/codec_ctrl.hpp index 259d10ef4..e2e8a010d 100644 --- a/host/lib/usrp/usrp1/codec_ctrl.hpp +++ b/host/lib/usrp/usrp1/codec_ctrl.hpp @@ -92,6 +92,9 @@ public:      //! Set the TX modulator frequency      virtual void set_duc_freq(double freq) = 0; +     +    //! Enable or disable ADC buffer bypass +    virtual void bypass_adc_buffers(bool bypass) = 0;  };  #endif /* INCLUDED_USRP1_CODEC_CTRL_HPP */ | 
