aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/common/ad9361_driver
diff options
context:
space:
mode:
authorTom Tsou <tom.tsou@ettus.com>2015-06-23 10:33:15 -0700
committerMartin Braun <martin.braun@ettus.com>2015-08-13 14:37:41 -0700
commit94c58baf4a2ba6c3a2c7899030f2de962212d937 (patch)
treee1a1e888193d38520de53d6365c6bd1585cf9b78 /host/lib/usrp/common/ad9361_driver
parent57fe541c9644e7488498d2c0311e38cf4564ec69 (diff)
downloaduhd-94c58baf4a2ba6c3a2c7899030f2de962212d937.tar.gz
uhd-94c58baf4a2ba6c3a2c7899030f2de962212d937.tar.bz2
uhd-94c58baf4a2ba6c3a2c7899030f2de962212d937.zip
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 <tom.tsou@ettus.com>
Diffstat (limited to 'host/lib/usrp/common/ad9361_driver')
-rw-r--r--host/lib/usrp/common/ad9361_driver/ad9361_device.cpp91
-rw-r--r--host/lib/usrp/common/ad9361_driver/ad9361_device.h3
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