diff options
Diffstat (limited to 'host/lib/usrp')
-rw-r--r-- | host/lib/usrp/common/ad9361_driver/ad9361_device.cpp | 91 | ||||
-rw-r--r-- | host/lib/usrp/common/ad9361_driver/ad9361_device.h | 3 |
2 files changed, 63 insertions, 31 deletions
diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp index 29241f6ba..c488d0848 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp +++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp @@ -785,11 +785,21 @@ void ad9361_device_t::_configure_bb_rf_dc_tracking(const bool on) } } -/* Start the RX quadrature calibration. +void ad9361_device_t::_configure_rx_iq_tracking() +{ + if (_use_iq_balance_tracking) + _io_iface->poke8(0x169, 0xcf); // Enable Rx IQ tracking + else + _io_iface->poke8(0x169, 0xc0); // Disable Rx IQ tracking +} + +/* Single shot Rx quadrature calibration * - * Note that we are using AD9361's 'tracking' feature for RX quadrature - * calibration, so once it starts it continues to free-run during operation. - * It should be re-run for large frequency changes. */ + * Procedure documented in "AD9361 Calibration Guide". Prior to calibration, + * state should be set to ALERT, FDD, and Dual Synth Mode. Rx quadrature + * tracking will be disabled, so run before or instead of enabling Rx + * quadrature tracking. + */ void ad9361_device_t::_calibrate_rx_quadrature() { /* Configure RX Quadrature calibration settings. */ @@ -797,11 +807,27 @@ void ad9361_device_t::_calibrate_rx_quadrature() _io_iface->poke8(0x16e, 0x25); // RX Gain index to use for cal _io_iface->poke8(0x16a, 0x75); // Set Kexp phase _io_iface->poke8(0x16b, 0x95); // Set Kexp amplitude + _io_iface->poke8(0x057, 0x33); // Power down Tx mixer + _io_iface->poke8(0x169, 0xc0); // Disable tracking and free run mode - if(_use_iq_balance_correction) - { - _io_iface->poke8(0x169, 0xcf); // Continuous tracking mode. Gets disabled in _tx_quadrature_cal_routine! + /* Place Tx LO within passband of Rx spectrum */ + double current_tx_freq = _tx_freq; + _tune_helper(TX, _rx_freq + _rx_bb_lp_bw / 2.0); + + size_t count = 0; + _io_iface->poke8(0x016, 0x20); + while (_io_iface->peek8(0x016) & 0x20) { + if (count > 100) { + throw uhd::runtime_error("[ad9361_device_t] Rx Quadrature Calibration Failure"); + break; + } + count++; + boost::this_thread::sleep(boost::posix_time::milliseconds(5)); } + + _io_iface->poke8(0x057, 0x30); // Re-enable Tx mixers + + _tune_helper(TX, current_tx_freq); } /* TX quadrature calibration routine. @@ -1517,7 +1543,7 @@ void ad9361_device_t::initialize() _tx1_gain = 0; _tx2_gain = 0; _use_dc_offset_correction = true; - _use_iq_balance_correction = true; + _use_iq_balance_tracking = true; _rx1_agc_mode = GAIN_MODE_SLOW_AGC; _rx2_agc_mode = GAIN_MODE_SLOW_AGC; _rx1_agc_enable = false; @@ -1692,6 +1718,9 @@ void ad9361_device_t::initialize() _calibrate_rx_quadrature(); _configure_bb_rf_dc_tracking(_use_dc_offset_correction); + if (_use_iq_balance_tracking) + _configure_rx_iq_tracking(); + // cals done, set PPORT config switch (_client_params->get_digital_interface_mode()) { case AD9361_DDR_FDD_LVCMOS: { @@ -1819,6 +1848,9 @@ double ad9361_device_t::set_clock_rate(const double req_rate) _calibrate_rx_quadrature(); _configure_bb_rf_dc_tracking(_use_dc_offset_correction); + if (_use_iq_balance_tracking) + _configure_rx_iq_tracking(); + // cals done, set PPORT config switch (_client_params->get_digital_interface_mode()) { case AD9361_DDR_FDD_LVCMOS: { @@ -1975,8 +2007,13 @@ double ad9361_device_t::tune(direction_t direction, const double value) /* Run the calibration algorithms. */ _calibrate_rf_dc_offset(); _calibrate_tx_quadrature(); - _calibrate_rx_quadrature(); _configure_bb_rf_dc_tracking(_use_dc_offset_correction); + + if (_use_iq_balance_tracking) + _configure_rx_iq_tracking(); + else + _calibrate_rx_quadrature(); + _last_calibration_freq = tune_freq; } @@ -2167,32 +2204,26 @@ void ad9361_device_t::set_dc_offset_auto(direction_t direction, const bool on) } } +/* + * Enable/Disable IQ balance tracking + * + * Run static Rx quadrature calibration after disabling quadrature tracking. + * This avoids the situation where a user might disable tracking when the loop + * is in a confused state (e.g. at or near saturation). Otherwise, the + * calibration setting could be forced to and left in a bad state. + */ void ad9361_device_t::set_iq_balance_auto(direction_t direction, const bool on) { - if(direction == RX) - { - _use_iq_balance_correction = on; - if(on) - { - //disable force registers and enable tracking - _io_iface->poke8(0x182, (_io_iface->peek8(0x182) & (~ ( (1<<1) | (1<<0) | (1<<5) | (1<<4) )))); + if (direction == RX) { + _use_iq_balance_tracking = on; + _configure_rx_iq_tracking(); + if (!on) { + _io_iface->poke8(0x014, 0x05); // ALERT mode _calibrate_rx_quadrature(); - } else { - //disable IQ tracking - _io_iface->poke8(0x169, 0xc0); - //clear current config values - _io_iface->poke8(0x182, (_io_iface->peek8(0x182) | ((1 << 1) | (1 << 0) | (1 << 5) | (1 << 4)))); //Set Rx2 input B&C force enable bit - _io_iface->poke8(0x17B, 0x00); - _io_iface->poke8(0x17C, 0x00); - _io_iface->poke8(0x179, 0x00); - _io_iface->poke8(0x17A, 0x00); - _io_iface->poke8(0x170, 0x00); - _io_iface->poke8(0x171, 0x00); - _io_iface->poke8(0x172, 0x00); - _io_iface->poke8(0x173, 0x00); + _io_iface->poke8(0x014, 0x21); // FDD mode } } else { - throw uhd::runtime_error("[ad9361_device_t] [set_iq_balance_auto] INVALID_CODE_PATH"); + throw uhd::runtime_error("[ad9361_device_t] [set_iq_balance_auto] Tx IQ tracking not supported"); } } diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.h b/host/lib/usrp/common/ad9361_driver/ad9361_device.h index 98369c2fc..8281ec9e5 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_device.h +++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.h @@ -187,6 +187,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 _configure_rx_iq_tracking(); void _setup_agc(chain_t chain, gain_mode_t gain_mode); void _set_fir_taps(direction_t direction, chain_t chain, const std::vector<boost::int16_t>& taps); std::vector<boost::int16_t> _get_fir_taps(direction_t direction, chain_t chain); @@ -259,7 +260,7 @@ private: //Members //Synchronization boost::recursive_mutex _mutex; bool _use_dc_offset_correction; - bool _use_iq_balance_correction; + bool _use_iq_balance_tracking; }; }} //namespace |