From 94c58baf4a2ba6c3a2c7899030f2de962212d937 Mon Sep 17 00:00:00 2001 From: Tom Tsou Date: Tue, 23 Jun 2015 10:33:15 -0700 Subject: ad9361: Enable single shot Rx Quad Cal Patch provides an alternative resolution to issue #807 "B210: severe distortion on In-phase data for some gain settings" Rx quadrature tracking, an active input-sensitive loop, causes problems on a handful of receive signals. Problematic signals include pulsed GMSK and near-DC tones among others. As an alternative, improve operation when active tracking is disabled. Run single shot quadrature calibration at the following events to provide calibrated image suppression. The corrections without active tracking are not input dependent. Rx quadrature single shot calibration points: 1. AD9361 initialization 2. Clock rate change 3. Tuning differences greater then 100 MHz when tracking is disabled Note that if tracking is enabled (default case), this patch has no effect during streaming. Only the non-default (user set) case is affected. Signed-off-by: Tom Tsou --- .../usrp/common/ad9361_driver/ad9361_device.cpp | 91 +++++++++++++++------- host/lib/usrp/common/ad9361_driver/ad9361_device.h | 3 +- 2 files changed, 63 insertions(+), 31 deletions(-) (limited to 'host/lib/usrp/common') 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& taps); std::vector _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 -- cgit v1.2.3