diff options
| author | Julian Arnold <julian.arnold@ettus.com> | 2015-03-05 15:25:13 -0800 | 
|---|---|---|
| committer | Martin Braun <martin.braun@ettus.com> | 2015-03-05 17:18:53 -0800 | 
| commit | be14725245cca756e19c48d84aedc54064e8706c (patch) | |
| tree | 8d366a8ad3ab05a87f05f714c215866907cf23b6 /host/lib/usrp | |
| parent | 99ab759233c85de000d16ad0f10660819e9456f1 (diff) | |
| download | uhd-be14725245cca756e19c48d84aedc54064e8706c.tar.gz uhd-be14725245cca756e19c48d84aedc54064e8706c.tar.bz2 uhd-be14725245cca756e19c48d84aedc54064e8706c.zip  | |
b2xx: AGC support
Diffstat (limited to 'host/lib/usrp')
| -rw-r--r-- | host/lib/usrp/b200/b200_impl.cpp | 10 | ||||
| -rw-r--r-- | host/lib/usrp/common/ad9361_ctrl.cpp | 21 | ||||
| -rw-r--r-- | host/lib/usrp/common/ad9361_ctrl.hpp | 6 | ||||
| -rw-r--r-- | host/lib/usrp/common/ad9361_driver/ad9361_device.cpp | 170 | ||||
| -rw-r--r-- | host/lib/usrp/common/ad9361_driver/ad9361_device.h | 12 | 
5 files changed, 195 insertions, 24 deletions
diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index ada25ad59..663696926 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -734,6 +734,16 @@ void b200_impl::setup_radio(const size_t dspno)                  .set("RX2");              _tree->create<sensor_value_t>(rf_fe_path / "sensors" / "rssi")                  .publish(boost::bind(&ad9361_ctrl::get_rssi, _codec_ctrl, key)); + +            //AGC setup +            const std::list<std::string> mode_strings = boost::assign::list_of("slow")("fast"); +            _tree->create<bool>(rf_fe_path / "gain" / "agc" / "enable") +                .subscribe(boost::bind((&ad9361_ctrl::set_agc), _codec_ctrl, key, _1)) +                .set(false); +            _tree->create<std::string>(rf_fe_path / "gain" / "agc" / "mode" / "value") +                .subscribe(boost::bind((&ad9361_ctrl::set_agc_mode), _codec_ctrl, key, _1)).set(mode_strings.front()); +            _tree->create<std::list<std::string> >(rf_fe_path / "gain" / "agc" / "mode" / "options") +                            .set(mode_strings);          }          if (key[0] == 'T')          { diff --git a/host/lib/usrp/common/ad9361_ctrl.cpp b/host/lib/usrp/common/ad9361_ctrl.cpp index ada74cda5..a0a5fa663 100644 --- a/host/lib/usrp/common/ad9361_ctrl.cpp +++ b/host/lib/usrp/common/ad9361_ctrl.cpp @@ -107,6 +107,27 @@ public:          return _device.set_gain(direction, chain, value);      } +    void set_agc(const std::string &which, bool enable) +    { +        boost::lock_guard<boost::mutex> lock(_mutex); + +        ad9361_device_t::chain_t chain =_get_chain_from_antenna(which); +         _device.set_agc(chain, enable); +    } + +    void set_agc_mode(const std::string &which, const std::string &mode) +    { +        boost::lock_guard<boost::mutex> lock(_mutex); +        ad9361_device_t::chain_t chain =_get_chain_from_antenna(which); +        if(mode == "slow") { +            _device.set_agc_mode(chain, ad9361_device_t::GAIN_MODE_SLOW_AGC); +        } else if (mode == "fast"){ +            _device.set_agc_mode(chain, ad9361_device_t::GAIN_MODE_FAST_AGC); +        } else { +            throw uhd::runtime_error("ad9361_ctrl got an invalid AGC option."); +        } +    } +      //! set a new clock rate, return the exact value      double set_clock_rate(const double rate)      { diff --git a/host/lib/usrp/common/ad9361_ctrl.hpp b/host/lib/usrp/common/ad9361_ctrl.hpp index 5396de225..0dd1b08d9 100644 --- a/host/lib/usrp/common/ad9361_ctrl.hpp +++ b/host/lib/usrp/common/ad9361_ctrl.hpp @@ -88,6 +88,12 @@ public:      //! set the gain for a particular gain element      virtual double set_gain(const std::string &which, const double value) = 0; +    //! Enable or disable the AGC module +    virtual void set_agc(const std::string &which, bool enable) = 0; + +    //! configure the AGC module to slow or fast mode +    virtual void set_agc_mode(const std::string &which, const std::string &mode) = 0; +      //! set a new clock rate, return the exact value      virtual double set_clock_rate(const double rate) = 0; diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp index e5938184c..ba66769dd 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp +++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp @@ -945,28 +945,58 @@ void ad9361_device_t::_program_gain_table() {  /* Setup gain control registers.   * - * This really only needs to be done once, at initialization. */ -void ad9361_device_t::_setup_gain_control() + * This really only needs to be done once, at initialization. + * If AGC is used the mode select bits (Reg 0x0FA) must be written manually */ +void ad9361_device_t::_setup_gain_control(bool agc)  { -    _io_iface->poke8(0x0FA, 0xE0); // Gain Control Mode Select -    _io_iface->poke8(0x0FB, 0x08); // Table, Digital Gain, Man Gain Ctrl -    _io_iface->poke8(0x0FC, 0x23); // Incr Step Size, ADC Overrange Size -    _io_iface->poke8(0x0FD, 0x4C); // Max Full/LMT Gain Table Index -    _io_iface->poke8(0x0FE, 0x44); // Decr Step Size, Peak Overload Time -    _io_iface->poke8(0x100, 0x6F); // Max Digital Gain -    _io_iface->poke8(0x104, 0x2F); // ADC Small Overload Threshold -    _io_iface->poke8(0x105, 0x3A); // ADC Large Overload Threshold -    _io_iface->poke8(0x107, 0x31); // Large LMT Overload Threshold -    _io_iface->poke8(0x108, 0x39); // Small LMT Overload Threshold -    _io_iface->poke8(0x109, 0x23); // Rx1 Full/LMT Gain Index -    _io_iface->poke8(0x10A, 0x58); // Rx1 LPF Gain Index -    _io_iface->poke8(0x10B, 0x00); // Rx1 Digital Gain Index -    _io_iface->poke8(0x10C, 0x23); // Rx2 Full/LMT Gain Index -    _io_iface->poke8(0x10D, 0x18); // Rx2 LPF Gain Index -    _io_iface->poke8(0x10E, 0x00); // Rx2 Digital Gain Index -    _io_iface->poke8(0x114, 0x30); // Low Power Threshold -    _io_iface->poke8(0x11A, 0x27); // Initial LMT Gain Limit -    _io_iface->poke8(0x081, 0x00); // Tx Symbol Gain Control +    /* The AGC mode configuration should be good for all cases. +     * However, non AGC configuration still used for backward compatibility. */ +    if (agc) { +        /*mode select bits must be written before hand!*/ +        _io_iface->poke8(0x0FB, 0x08); // Table, Digital Gain, Man Gain Ctrl +        _io_iface->poke8(0x0FC, 0x23); // Incr Step Size, ADC Overrange Size +        _io_iface->poke8(0x0FD, 0x4C); // Max Full/LMT Gain Table Index +        _io_iface->poke8(0x0FE, 0x44); // Decr Step Size, Peak Overload Time +        _io_iface->poke8(0x100, 0x6F); // Max Digital Gain +        _io_iface->poke8(0x101, 0x0A); // Max Digital Gain +        _io_iface->poke8(0x103, 0x08); // Max Digital Gain +        _io_iface->poke8(0x104, 0x2F); // ADC Small Overload Threshold +        _io_iface->poke8(0x105, 0x3A); // ADC Large Overload Threshold +        _io_iface->poke8(0x106, 0x22); // Max Digital Gain +        _io_iface->poke8(0x107, 0x2B); // Large LMT Overload Threshold +        _io_iface->poke8(0x108, 0x31); +        _io_iface->poke8(0x111, 0x0A); +        _io_iface->poke8(0x11A, 0x1C); +        _io_iface->poke8(0x120, 0x0C); +        _io_iface->poke8(0x121, 0x44); +        _io_iface->poke8(0x122, 0x44); +        _io_iface->poke8(0x123, 0x11); +        _io_iface->poke8(0x124, 0xF5); +        _io_iface->poke8(0x125, 0x3B); +        _io_iface->poke8(0x128, 0x03); +        _io_iface->poke8(0x129, 0x56); +        _io_iface->poke8(0x12A, 0x22); +    } else { +        _io_iface->poke8(0x0FA, 0xE0); // Gain Control Mode Select +        _io_iface->poke8(0x0FB, 0x08); // Table, Digital Gain, Man Gain Ctrl +        _io_iface->poke8(0x0FC, 0x23); // Incr Step Size, ADC Overrange Size +        _io_iface->poke8(0x0FD, 0x4C); // Max Full/LMT Gain Table Index +        _io_iface->poke8(0x0FE, 0x44); // Decr Step Size, Peak Overload Time +        _io_iface->poke8(0x100, 0x6F); // Max Digital Gain +        _io_iface->poke8(0x104, 0x2F); // ADC Small Overload Threshold +        _io_iface->poke8(0x105, 0x3A); // ADC Large Overload Threshold +        _io_iface->poke8(0x107, 0x31); // Large LMT Overload Threshold +        _io_iface->poke8(0x108, 0x39); // Small LMT Overload Threshold +        _io_iface->poke8(0x109, 0x23); // Rx1 Full/LMT Gain Index +        _io_iface->poke8(0x10A, 0x58); // Rx1 LPF Gain Index +        _io_iface->poke8(0x10B, 0x00); // Rx1 Digital Gain Index +        _io_iface->poke8(0x10C, 0x23); // Rx2 Full/LMT Gain Index +        _io_iface->poke8(0x10D, 0x18); // Rx2 LPF Gain Index +        _io_iface->poke8(0x10E, 0x00); // Rx2 Digital Gain Index +        _io_iface->poke8(0x114, 0x30); // Low Power Threshold +        _io_iface->poke8(0x11A, 0x27); // Initial LMT Gain Limit +        _io_iface->poke8(0x081, 0x00); // Tx Symbol Gain Control +    }  }  /* Setup the RX or TX synthesizers. @@ -1421,6 +1451,10 @@ void ad9361_device_t::initialize()      _tx2_gain = 0;      _use_dc_offset_correction = true;      _use_iq_balance_correction = true; +    _rx1_agc_mode = GAIN_MODE_SLOW_AGC; +    _rx2_agc_mode = GAIN_MODE_SLOW_AGC; +    _rx1_agc_enable = false; +    _rx2_agc_enable = false;      /* Reset the device. */      _io_iface->poke8(0x000, 0x01); @@ -1564,7 +1598,7 @@ void ad9361_device_t::initialize()      _program_mixer_gm_subtable();      _program_gain_table(); -    _setup_gain_control(); +    _setup_gain_control(false);      _calibrate_baseband_rx_analog_filter();      _calibrate_baseband_tx_analog_filter(); @@ -1690,7 +1724,7 @@ double ad9361_device_t::set_clock_rate(const double req_rate)      _program_mixer_gm_subtable();      _program_gain_table(); -    _setup_gain_control(); +    _setup_gain_control(false);      _reprogram_gains();      _calibrate_baseband_rx_analog_filter(); @@ -2067,4 +2101,94 @@ void ad9361_device_t::set_iq_balance_auto(direction_t direction, const bool on)      }  } +/* Sets the RX gain mode to be used. + * If a transition from an AGC to an non AGC mode occurs (or vice versa) + * the gain configuration will be reloaded. */ +void ad9361_device_t::_setup_agc(chain_t chain, gain_mode_t gain_mode) +{ +    boost::uint8_t gain_mode_reg = 0; +    boost::uint8_t gain_mode_prev = 0; +    boost::uint8_t gain_mode_bits_pos = 0; + +    gain_mode_reg = _io_iface->peek8(0x0FA); +    gain_mode_prev = (gain_mode_reg & 0x0F); + +    if (chain == CHAIN_1) { +        gain_mode_bits_pos = 0; +    } else if (chain == CHAIN_2) { +        gain_mode_bits_pos = 2; +    } else +    { +        throw uhd::runtime_error("[ad9361_device_t] Wrong value for chain"); +    } + +    gain_mode_reg = (gain_mode_reg & (~(0x03<<gain_mode_bits_pos))); //clear mode bits +    switch (gain_mode) { +        case GAIN_MODE_MANUAL: +            //leave bits cleared +            break; +        case GAIN_MODE_SLOW_AGC: +            gain_mode_reg = (gain_mode_reg | (0x02<<gain_mode_bits_pos)); +            break; +        case GAIN_MODE_FAST_AGC: +            gain_mode_reg = (gain_mode_reg | (0x01<<gain_mode_bits_pos)); +            break; +        default: +            throw uhd::runtime_error("[ad9361_device_t] Gain mode does not exist"); +    } +    _io_iface->poke8(0x0FA, gain_mode_reg); +    boost::uint8_t gain_mode_status = _io_iface->peek8(0x0FA); +    gain_mode_status = (gain_mode_status & 0x0F); +    /*Check if gain mode configuration needs to be reprogrammed*/ +    if (((gain_mode_prev == 0) && (gain_mode_status != 0)) || ((gain_mode_prev != 0) && (gain_mode_status == 0))) { +        if (gain_mode_status == 0) { +            /*load manual mode config*/ +            _setup_gain_control(false); +        } else { +            /*load agc mode config*/ +            _setup_gain_control(true); +        } +    } +} + +void ad9361_device_t::set_agc(chain_t chain, bool enable) +{ +    if(chain == CHAIN_1) { +        _rx1_agc_enable = enable; +        if(enable) { +            _setup_agc(chain, _rx1_agc_mode); +        } else { +            _setup_agc(chain, GAIN_MODE_MANUAL); +        } +    } else if (chain == CHAIN_2){ +        _rx2_agc_enable = enable; +        if(enable) { +            _setup_agc(chain, _rx2_agc_mode); +        } else { +            _setup_agc(chain, GAIN_MODE_MANUAL); +        } +    } else +    { +        throw uhd::runtime_error("[ad9361_device_t] Wrong value for chain"); +    } +} + +void ad9361_device_t::set_agc_mode(chain_t chain, gain_mode_t gain_mode) +{ +    if(chain == CHAIN_1) { +        _rx1_agc_mode = gain_mode; +        if(_rx1_agc_enable) { +            _setup_agc(chain, _rx1_agc_mode); +        } +    } else if(chain == CHAIN_2){ +        _rx2_agc_mode = gain_mode; +        if(_rx2_agc_enable) { +            _setup_agc(chain, _rx2_agc_mode); +        } +    } else +    { +        throw uhd::runtime_error("[ad9361_device_t] Wrong value for chain"); +    } +} +  }} diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.h b/host/lib/usrp/common/ad9361_driver/ad9361_device.h index 93dc413d5..1cfff9971 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_device.h +++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.h @@ -16,6 +16,7 @@ class ad9361_device_t : public boost::noncopyable  public:      enum direction_t { RX, TX };      enum chain_t { CHAIN_1, CHAIN_2 }; +    enum gain_mode_t {GAIN_MODE_MANUAL, GAIN_MODE_SLOW_AGC, GAIN_MODE_FAST_AGC};      ad9361_device_t(ad9361_params::sptr client, ad9361_io::sptr io_iface) :          _client_params(client), _io_iface(io_iface) {} @@ -78,6 +79,12 @@ public:      /* Turn on/off AD9361's RX IQ imbalance correction */      void set_iq_balance_auto(direction_t direction, const bool on); +    /* Configure AD9361's AGC module to use either fast or slow AGC mode. */ +    void set_agc_mode(chain_t chain, gain_mode_t gain_mode); + +    /* Enable AD9361's AGC gain mode. */ +    void set_agc(chain_t chain, bool enable); +      //Constants      static const double AD9361_MAX_GAIN;      static const double AD9361_MAX_CLOCK_RATE; @@ -101,7 +108,7 @@ private:    //Methods      void _calibrate_tx_quadrature();      void _program_mixer_gm_subtable();      void _program_gain_table(); -    void _setup_gain_control(); +    void _setup_gain_control(bool use_agc);      void _setup_synth(direction_t direction, double vcorate);      double _tune_bbvco(const double rate);      void _reprogram_gains(); @@ -109,6 +116,7 @@ private:    //Methods      double _setup_rates(const double rate);      double _get_temperature(const double cal_offset, const double timeout = 0.1);      void _configure_bb_rf_dc_tracking(const bool on); +    void _setup_agc(chain_t chain, gain_mode_t gain_mode);  private:    //Members      typedef struct { @@ -133,6 +141,8 @@ private:    //Members      double              _rx1_gain, _rx2_gain, _tx1_gain, _tx2_gain;      boost::int32_t      _tfir_factor;      boost::int32_t      _rfir_factor; +    gain_mode_t         _rx1_agc_mode, _rx2_agc_mode; +    bool                _rx1_agc_enable, _rx2_agc_enable;      //Register soft-copies      chip_regs_t         _regs;      //Synchronization  | 
