summaryrefslogtreecommitdiffstats
path: root/host/lib
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib')
-rw-r--r--host/lib/usrp/common/adf435x_common.cpp35
-rw-r--r--host/lib/usrp/common/adf435x_common.hpp6
-rw-r--r--host/lib/usrp/dboard/db_cbx.cpp6
-rw-r--r--host/lib/usrp/dboard/db_sbx_version3.cpp8
-rw-r--r--host/lib/usrp/dboard/db_sbx_version4.cpp8
-rw-r--r--host/lib/usrp/dboard/db_wbx_version2.cpp33
-rw-r--r--host/lib/usrp/dboard/db_wbx_version3.cpp33
-rw-r--r--host/lib/usrp/dboard/db_wbx_version4.cpp34
-rw-r--r--host/lib/usrp/gps_ctrl.cpp47
-rw-r--r--host/lib/usrp/x300/x300_clock_ctrl.cpp6
-rw-r--r--host/lib/usrp/x300/x300_impl.cpp275
-rw-r--r--host/lib/usrp/x300/x300_impl.hpp51
12 files changed, 359 insertions, 183 deletions
diff --git a/host/lib/usrp/common/adf435x_common.cpp b/host/lib/usrp/common/adf435x_common.cpp
index e9d018fec..f0df6a334 100644
--- a/host/lib/usrp/common/adf435x_common.cpp
+++ b/host/lib/usrp/common/adf435x_common.cpp
@@ -25,8 +25,8 @@ using namespace uhd;
* ADF 4350/4351 Tuning Utility
**********************************************************************/
adf435x_tuning_settings tune_adf435x_synth(
- double target_freq,
- double ref_freq,
+ const double target_freq,
+ const double ref_freq,
const adf435x_tuning_constraints& constraints,
double& actual_freq)
{
@@ -66,9 +66,10 @@ adf435x_tuning_settings tune_adf435x_synth(
* f_pfd = f_ref*(1+D)/(R*(1+T))
* f_vco = (N + (FRAC/MOD))*f_pfd
* N = f_vco/f_pfd - FRAC/MOD = f_vco*((R*(T+1))/(f_ref*(1+D))) - FRAC/MOD
- * f_rf = f_vco/RFdiv)
- * f_actual = f_rf/2
+ * f_actual = f_vco/RFdiv)
*/
+ double feedback_freq = constraints.feedback_after_divider ? target_freq : vco_freq;
+
for(R = 1; R <= 1023; R+=1){
//PFD input frequency = f_ref/R ... ignoring Reference doubler/divide-by-2 (D & T)
pfd_freq = ref_freq*(D?2:1)/(R*(T?2:1));
@@ -76,10 +77,8 @@ adf435x_tuning_settings tune_adf435x_synth(
//keep the PFD frequency at or below 25MHz (Loop Filter Bandwidth)
if (pfd_freq > constraints.pfd_freq_max) continue;
- //ignore fractional part of tuning
- //N is computed from target_freq and not vco_freq because the feedback
- //mode is set to FEEDBACK_SELECT_DIVIDED
- N = boost::uint16_t(std::floor(target_freq/pfd_freq));
+ //First, ignore fractional part of tuning
+ N = boost::uint16_t(std::floor(feedback_freq/pfd_freq));
//keep N > minimum int divider requirement
if (N < static_cast<boost::uint16_t>(constraints.int_range.start())) continue;
@@ -94,9 +93,7 @@ adf435x_tuning_settings tune_adf435x_synth(
//Fractional-N calculation
MOD = 4095; //max fractional accuracy
- //N is computed from target_freq and not vco_freq because the feedback
- //mode is set to FEEDBACK_SELECT_DIVIDED
- FRAC = static_cast<boost::uint16_t>((target_freq/pfd_freq - N)*MOD);
+ FRAC = static_cast<boost::uint16_t>((feedback_freq/pfd_freq - N)*MOD);
if (constraints.force_frac0) {
if (FRAC > (MOD / 2)) { //Round integer such that actual freq is closest to target
N++;
@@ -114,8 +111,14 @@ adf435x_tuning_settings tune_adf435x_synth(
//Typical phase resync time documented in data sheet pg.24
static const double PHASE_RESYNC_TIME = 400e-6;
- //actual frequency calculation
- actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(D?2:1)/(R*(T?2:1)));
+ //If feedback after divider, then compensation for the divider is pulled into the INT value
+ int rf_div_compensation = constraints.feedback_after_divider ? 1 : RFdiv;
+
+ //Compute the actual frequency in terms of ref_freq, N, FRAC, MOD, D, R and T.
+ actual_freq = (
+ double((N + (double(FRAC)/double(MOD))) *
+ (ref_freq*(D?2:1)/(R*(T?2:1))))
+ ) / rf_div_compensation;
//load the settings
adf435x_tuning_settings settings;
@@ -128,15 +131,13 @@ adf435x_tuning_settings tune_adf435x_synth(
settings.r_doubler_en = D;
settings.band_select_clock_div = BS;
settings.rf_divider = RFdiv;
- settings.feedback_after_divider = true;
std::string tuning_str = (constraints.force_frac0) ? "Integer-N" : "Fractional";
-
UHD_LOGV(often)
<< boost::format("ADF 435X Frequencies (MHz): REQUESTED=%0.9f, ACTUAL=%0.9f"
) % (target_freq/1e6) % (actual_freq/1e6) << std::endl
- << boost::format("ADF 435X Intermediates (MHz): VCO=%0.2f, PFD=%0.2f, BAND=%0.2f, REF=%0.2f"
- ) % (vco_freq/1e6) % (pfd_freq/1e6) % (pfd_freq/BS/1e6) % (ref_freq/1e6) << std::endl
+ << boost::format("ADF 435X Intermediates (MHz): Feedback=%0.2f, VCO=%0.2f, PFD=%0.2f, BAND=%0.2f, REF=%0.2f"
+ ) % (feedback_freq/1e6) % (vco_freq/1e6) % (pfd_freq/1e6) % (pfd_freq/BS/1e6) % (ref_freq/1e6) << std::endl
<< boost::format("ADF 435X Tuning: %s") % tuning_str.c_str() << std::endl
<< boost::format("ADF 435X Settings: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d"
) % R % BS % N % FRAC % MOD % T % D % RFdiv << std::endl;
diff --git a/host/lib/usrp/common/adf435x_common.hpp b/host/lib/usrp/common/adf435x_common.hpp
index 715b1fd53..617b9d97f 100644
--- a/host/lib/usrp/common/adf435x_common.hpp
+++ b/host/lib/usrp/common/adf435x_common.hpp
@@ -33,6 +33,7 @@
struct adf435x_tuning_constraints {
bool force_frac0;
+ bool feedback_after_divider;
double ref_doubler_threshold;
double pfd_freq_max;
double band_sel_freq_max;
@@ -50,12 +51,11 @@ struct adf435x_tuning_settings {
boost::uint16_t clock_divider_12_bit;
boost::uint8_t band_select_clock_div;
boost::uint16_t rf_divider;
- bool feedback_after_divider;
};
adf435x_tuning_settings tune_adf435x_synth(
- double target_freq,
- double ref_freq,
+ const double target_freq,
+ const double ref_freq,
const adf435x_tuning_constraints& constraints,
double& actual_freq
);
diff --git a/host/lib/usrp/dboard/db_cbx.cpp b/host/lib/usrp/dboard/db_cbx.cpp
index ae41a7971..78ecd9794 100644
--- a/host/lib/usrp/dboard/db_cbx.cpp
+++ b/host/lib/usrp/dboard/db_cbx.cpp
@@ -18,7 +18,7 @@
#include "max2870_regs.hpp"
#include "db_sbx_common.hpp"
-
+#include <boost/algorithm/string.hpp>
using namespace uhd;
using namespace uhd::usrp;
@@ -47,14 +47,14 @@ double sbx_xcvr::cbx::set_lo_freq(dboard_iface::unit_t unit, double target_freq)
) % (target_freq/1e6) << std::endl;
/*
- * If the user sets 'mode_n=int-n' in the tuning args, the user wishes to
+ * If the user sets 'mode_n=integer' in the tuning args, the user wishes to
* tune in Integer-N mode, which can result in better spur
* performance on some mixers. The default is fractional tuning.
*/
property_tree::sptr subtree = (unit == dboard_iface::UNIT_RX) ? self_base->get_rx_subtree()
: self_base->get_tx_subtree();
device_addr_t tune_args = subtree->access<device_addr_t>("tune_args").get();
- bool is_int_n = (tune_args.get("mode_n","") == "int-n");
+ bool is_int_n = boost::iequals(tune_args.get("mode_n",""), "integer");
//clip the input
target_freq = cbx_freq_range.clip(target_freq);
diff --git a/host/lib/usrp/dboard/db_sbx_version3.cpp b/host/lib/usrp/dboard/db_sbx_version3.cpp
index ef0126557..463de5e15 100644
--- a/host/lib/usrp/dboard/db_sbx_version3.cpp
+++ b/host/lib/usrp/dboard/db_sbx_version3.cpp
@@ -20,6 +20,7 @@
#include "db_sbx_common.hpp"
#include "../common/adf435x_common.hpp"
#include <uhd/types/tune_request.hpp>
+#include <boost/algorithm/string.hpp>
using namespace uhd;
using namespace uhd::usrp;
@@ -47,14 +48,14 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
) % (target_freq/1e6) << std::endl;
/*
- * If the user sets 'mode_n=int-n' in the tuning args, the user wishes to
+ * If the user sets 'mode_n=integer' in the tuning args, the user wishes to
* tune in Integer-N mode, which can result in better spur
* performance on some mixers. The default is fractional tuning.
*/
property_tree::sptr subtree = (unit == dboard_iface::UNIT_RX) ? self_base->get_rx_subtree()
: self_base->get_tx_subtree();
device_addr_t tune_args = subtree->access<device_addr_t>("tune_args").get();
- bool is_int_n = (tune_args.get("mode_n","") == "int-n");
+ bool is_int_n = boost::iequals(tune_args.get("mode_n",""), "integer");
//clip the input
target_freq = sbx_freq_range.clip(target_freq);
@@ -84,6 +85,7 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
tuning_constraints.int_range = uhd::range_t(prescaler_to_min_int_div[prescaler], 4095); //INT is a 12-bit field
tuning_constraints.pfd_freq_max = 25e6;
tuning_constraints.rf_divider_range = uhd::range_t(1, 16);
+ tuning_constraints.feedback_after_divider = true;
double actual_freq;
adf435x_tuning_settings tuning_settings = tune_adf435x_synth(
@@ -102,7 +104,7 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
regs.int_16_bit = tuning_settings.int_16_bit;
regs.mod_12_bit = tuning_settings.mod_12_bit;
regs.clock_divider_12_bit = tuning_settings.clock_divider_12_bit;
- regs.feedback_select = tuning_settings.feedback_after_divider ?
+ regs.feedback_select = tuning_constraints.feedback_after_divider ?
adf4350_regs_t::FEEDBACK_SELECT_DIVIDED :
adf4350_regs_t::FEEDBACK_SELECT_FUNDAMENTAL;
regs.clock_div_mode = adf4350_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE;
diff --git a/host/lib/usrp/dboard/db_sbx_version4.cpp b/host/lib/usrp/dboard/db_sbx_version4.cpp
index 6c0cebb4b..ff4e19163 100644
--- a/host/lib/usrp/dboard/db_sbx_version4.cpp
+++ b/host/lib/usrp/dboard/db_sbx_version4.cpp
@@ -20,6 +20,7 @@
#include "db_sbx_common.hpp"
#include "../common/adf435x_common.hpp"
#include <uhd/types/tune_request.hpp>
+#include <boost/algorithm/string.hpp>
using namespace uhd;
using namespace uhd::usrp;
@@ -48,14 +49,14 @@ double sbx_xcvr::sbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
) % (target_freq/1e6) << std::endl;
/*
- * If the user sets 'mode_n=int-n' in the tuning args, the user wishes to
+ * If the user sets 'mode_n=integer' in the tuning args, the user wishes to
* tune in Integer-N mode, which can result in better spur
* performance on some mixers. The default is fractional tuning.
*/
property_tree::sptr subtree = (unit == dboard_iface::UNIT_RX) ? self_base->get_rx_subtree()
: self_base->get_tx_subtree();
device_addr_t tune_args = subtree->access<device_addr_t>("tune_args").get();
- bool is_int_n = (tune_args.get("mode_n","") == "int-n");
+ bool is_int_n = boost::iequals(tune_args.get("mode_n",""), "integer");
//clip the input
target_freq = sbx_freq_range.clip(target_freq);
@@ -87,6 +88,7 @@ double sbx_xcvr::sbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
tuning_constraints.int_range = uhd::range_t(prescaler_to_min_int_div[prescaler], 4095); //INT is a 12-bit field
tuning_constraints.pfd_freq_max = 25e6;
tuning_constraints.rf_divider_range = uhd::range_t(1, 64);
+ tuning_constraints.feedback_after_divider = true;
double actual_freq;
adf435x_tuning_settings tuning_settings = tune_adf435x_synth(
@@ -105,7 +107,7 @@ double sbx_xcvr::sbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
regs.int_16_bit = tuning_settings.int_16_bit;
regs.mod_12_bit = tuning_settings.mod_12_bit;
regs.clock_divider_12_bit = tuning_settings.clock_divider_12_bit;
- regs.feedback_select = tuning_settings.feedback_after_divider ?
+ regs.feedback_select = tuning_constraints.feedback_after_divider ?
adf4351_regs_t::FEEDBACK_SELECT_DIVIDED :
adf4351_regs_t::FEEDBACK_SELECT_FUNDAMENTAL;
regs.clock_div_mode = adf4351_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE;
diff --git a/host/lib/usrp/dboard/db_wbx_version2.cpp b/host/lib/usrp/dboard/db_wbx_version2.cpp
index 2afdce4cd..c5945483d 100644
--- a/host/lib/usrp/dboard/db_wbx_version2.cpp
+++ b/host/lib/usrp/dboard/db_wbx_version2.cpp
@@ -30,6 +30,7 @@
#include <boost/assign/list_of.hpp>
#include <boost/format.hpp>
#include <boost/math/special_functions/round.hpp>
+#include <boost/algorithm/string.hpp>
using namespace uhd;
using namespace uhd::usrp;
@@ -169,14 +170,14 @@ double wbx_base::wbx_version2::set_lo_freq(dboard_iface::unit_t unit, double tar
) % (target_freq/1e6) << std::endl;
/*
- * If the user sets 'mode_n=int-n' in the tuning args, the user wishes to
+ * If the user sets 'mode_n=integer' in the tuning args, the user wishes to
* tune in Integer-N mode, which can result in better spur
* performance on some mixers. The default is fractional tuning.
*/
property_tree::sptr subtree = (unit == dboard_iface::UNIT_RX) ? self_base->get_rx_subtree()
: self_base->get_tx_subtree();
device_addr_t tune_args = subtree->access<device_addr_t>("tune_args").get();
- bool is_int_n = (tune_args.get("mode_n","") == "int-n");
+ bool is_int_n = boost::iequals(tune_args.get("mode_n",""), "integer");
//map prescaler setting to mininmum integer divider (N) values (pg.18 prescaler)
static const uhd::dict<int, int> prescaler_to_min_int_div = map_list_of
@@ -193,7 +194,15 @@ double wbx_base::wbx_version2::set_lo_freq(dboard_iface::unit_t unit, double tar
(16, adf4350_regs_t::RF_DIVIDER_SELECT_DIV16)
;
- adf4350_regs_t::prescaler_t prescaler = target_freq > 3e9 ? adf4350_regs_t::PRESCALER_8_9 : adf4350_regs_t::PRESCALER_4_5;
+ double reference_freq = self_base->get_iface()->get_clock_rate(unit);
+ //The mixer has a divide-by-2 stage on the LO port so the synthesizer
+ //frequency must 2x the target frequency
+ double synth_target_freq = target_freq * 2;
+ //TODO: Document why the following has to be true
+ bool div_resync_enabled = (target_freq > reference_freq);
+
+ adf4350_regs_t::prescaler_t prescaler =
+ synth_target_freq > 3e9 ? adf4350_regs_t::PRESCALER_8_9 : adf4350_regs_t::PRESCALER_4_5;
adf435x_tuning_constraints tuning_constraints;
tuning_constraints.force_frac0 = is_int_n;
@@ -202,11 +211,17 @@ double wbx_base::wbx_version2::set_lo_freq(dboard_iface::unit_t unit, double tar
tuning_constraints.int_range = uhd::range_t(prescaler_to_min_int_div[prescaler], 4095);
tuning_constraints.pfd_freq_max = 25e6;
tuning_constraints.rf_divider_range = uhd::range_t(1, 16);
+ //When divider resync is enabled, a 180 deg phase error is introduced when syncing
+ //multiple WBX boards. Switching to fundamental mode works arounds this issue.
+ tuning_constraints.feedback_after_divider = div_resync_enabled;
- double actual_freq;
+ double synth_actual_freq = 0;
adf435x_tuning_settings tuning_settings = tune_adf435x_synth(
- target_freq, self_base->get_iface()->get_clock_rate(unit),
- tuning_constraints, actual_freq);
+ synth_target_freq, reference_freq, tuning_constraints, synth_actual_freq);
+
+ //The mixer has a divide-by-2 stage on the LO port so the synthesizer
+ //actual_freq must /2 the synth_actual_freq
+ double actual_freq = synth_actual_freq / 2;
//load the register values
adf4350_regs_t regs;
@@ -222,10 +237,12 @@ double wbx_base::wbx_version2::set_lo_freq(dboard_iface::unit_t unit, double tar
regs.int_16_bit = tuning_settings.int_16_bit;
regs.mod_12_bit = tuning_settings.mod_12_bit;
regs.clock_divider_12_bit = tuning_settings.clock_divider_12_bit;
- regs.feedback_select = tuning_settings.feedback_after_divider ?
+ regs.feedback_select = tuning_constraints.feedback_after_divider ?
adf4350_regs_t::FEEDBACK_SELECT_DIVIDED :
adf4350_regs_t::FEEDBACK_SELECT_FUNDAMENTAL;
- regs.clock_div_mode = adf4350_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE;
+ regs.clock_div_mode = div_resync_enabled ?
+ adf4350_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE :
+ adf4350_regs_t::CLOCK_DIV_MODE_FAST_LOCK;
regs.prescaler = prescaler;
regs.r_counter_10_bit = tuning_settings.r_counter_10_bit;
regs.reference_divide_by_2 = tuning_settings.r_divide_by_2_en ?
diff --git a/host/lib/usrp/dboard/db_wbx_version3.cpp b/host/lib/usrp/dboard/db_wbx_version3.cpp
index e30d6c665..80ecb426b 100644
--- a/host/lib/usrp/dboard/db_wbx_version3.cpp
+++ b/host/lib/usrp/dboard/db_wbx_version3.cpp
@@ -29,6 +29,7 @@
#include <boost/assign/list_of.hpp>
#include <boost/format.hpp>
#include <boost/math/special_functions/round.hpp>
+#include <boost/algorithm/string.hpp>
using namespace uhd;
using namespace uhd::usrp;
@@ -200,14 +201,14 @@ double wbx_base::wbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
) % (target_freq/1e6) << std::endl;
/*
- * If the user sets 'mode_n=int-n' in the tuning args, the user wishes to
+ * If the user sets 'mode_n=integer' in the tuning args, the user wishes to
* tune in Integer-N mode, which can result in better spur
* performance on some mixers. The default is fractional tuning.
*/
property_tree::sptr subtree = (unit == dboard_iface::UNIT_RX) ? self_base->get_rx_subtree()
: self_base->get_tx_subtree();
device_addr_t tune_args = subtree->access<device_addr_t>("tune_args").get();
- bool is_int_n = (tune_args.get("mode_n","") == "int-n");
+ bool is_int_n = boost::iequals(tune_args.get("mode_n",""), "integer");
//map prescaler setting to mininmum integer divider (N) values (pg.18 prescaler)
static const uhd::dict<int, int> prescaler_to_min_int_div = map_list_of
@@ -224,7 +225,15 @@ double wbx_base::wbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
(16, adf4350_regs_t::RF_DIVIDER_SELECT_DIV16)
;
- adf4350_regs_t::prescaler_t prescaler = target_freq > 3e9 ? adf4350_regs_t::PRESCALER_8_9 : adf4350_regs_t::PRESCALER_4_5;
+ double reference_freq = self_base->get_iface()->get_clock_rate(unit);
+ //The mixer has a divide-by-2 stage on the LO port so the synthesizer
+ //frequency must 2x the target frequency
+ double synth_target_freq = target_freq * 2;
+ //TODO: Document why the following has to be true
+ bool div_resync_enabled = (target_freq > reference_freq);
+
+ adf4350_regs_t::prescaler_t prescaler =
+ synth_target_freq > 3e9 ? adf4350_regs_t::PRESCALER_8_9 : adf4350_regs_t::PRESCALER_4_5;
adf435x_tuning_constraints tuning_constraints;
tuning_constraints.force_frac0 = is_int_n;
@@ -233,11 +242,17 @@ double wbx_base::wbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
tuning_constraints.int_range = uhd::range_t(prescaler_to_min_int_div[prescaler], 4095);
tuning_constraints.pfd_freq_max = 25e6;
tuning_constraints.rf_divider_range = uhd::range_t(1, 16);
+ //When divider resync is enabled, a 180 deg phase error is introduced when syncing
+ //multiple WBX boards. Switching to fundamental mode works arounds this issue.
+ tuning_constraints.feedback_after_divider = div_resync_enabled;
- double actual_freq;
+ double synth_actual_freq = 0;
adf435x_tuning_settings tuning_settings = tune_adf435x_synth(
- target_freq, self_base->get_iface()->get_clock_rate(unit),
- tuning_constraints, actual_freq);
+ synth_target_freq, reference_freq, tuning_constraints, synth_actual_freq);
+
+ //The mixer has a divide-by-2 stage on the LO port so the synthesizer
+ //actual_freq must /2 the synth_actual_freq
+ double actual_freq = synth_actual_freq / 2;
//load the register values
adf4350_regs_t regs;
@@ -253,10 +268,12 @@ double wbx_base::wbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar
regs.int_16_bit = tuning_settings.int_16_bit;
regs.mod_12_bit = tuning_settings.mod_12_bit;
regs.clock_divider_12_bit = tuning_settings.clock_divider_12_bit;
- regs.feedback_select = tuning_settings.feedback_after_divider ?
+ regs.feedback_select = tuning_constraints.feedback_after_divider ?
adf4350_regs_t::FEEDBACK_SELECT_DIVIDED :
adf4350_regs_t::FEEDBACK_SELECT_FUNDAMENTAL;
- regs.clock_div_mode = adf4350_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE;
+ regs.clock_div_mode = div_resync_enabled ?
+ adf4350_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE :
+ adf4350_regs_t::CLOCK_DIV_MODE_FAST_LOCK;
regs.prescaler = prescaler;
regs.r_counter_10_bit = tuning_settings.r_counter_10_bit;
regs.reference_divide_by_2 = tuning_settings.r_divide_by_2_en ?
diff --git a/host/lib/usrp/dboard/db_wbx_version4.cpp b/host/lib/usrp/dboard/db_wbx_version4.cpp
index dc1ae4df8..80ff3f998 100644
--- a/host/lib/usrp/dboard/db_wbx_version4.cpp
+++ b/host/lib/usrp/dboard/db_wbx_version4.cpp
@@ -29,6 +29,7 @@
#include <boost/assign/list_of.hpp>
#include <boost/format.hpp>
#include <boost/math/special_functions/round.hpp>
+#include <boost/algorithm/string.hpp>
using namespace uhd;
using namespace uhd::usrp;
@@ -208,14 +209,14 @@ double wbx_base::wbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
) % (target_freq/1e6) << std::endl;
/*
- * If the user sets 'mode_n=int-n' in the tuning args, the user wishes to
+ * If the user sets 'mode_n=integer' in the tuning args, the user wishes to
* tune in Integer-N mode, which can result in better spur
* performance on some mixers. The default is fractional tuning.
*/
property_tree::sptr subtree = (unit == dboard_iface::UNIT_RX) ? self_base->get_rx_subtree()
: self_base->get_tx_subtree();
device_addr_t tune_args = subtree->access<device_addr_t>("tune_args").get();
- bool is_int_n = (tune_args.get("mode_n","") == "int-n");
+ bool is_int_n = boost::iequals(tune_args.get("mode_n",""), "integer");
//map prescaler setting to mininmum integer divider (N) values (pg.18 prescaler)
static const uhd::dict<int, int> prescaler_to_min_int_div = map_list_of
@@ -234,7 +235,15 @@ double wbx_base::wbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
(64, adf4351_regs_t::RF_DIVIDER_SELECT_DIV64)
;
- adf4351_regs_t::prescaler_t prescaler = target_freq > 3e9 ? adf4351_regs_t::PRESCALER_8_9 : adf4351_regs_t::PRESCALER_4_5;
+ double reference_freq = self_base->get_iface()->get_clock_rate(unit);
+ //The mixer has a divide-by-2 stage on the LO port so the synthesizer
+ //frequency must 2x the target frequency
+ double synth_target_freq = target_freq * 2;
+ //TODO: Document why the following has to be true
+ bool div_resync_enabled = (target_freq > reference_freq);
+
+ adf4351_regs_t::prescaler_t prescaler =
+ synth_target_freq > 3e9 ? adf4351_regs_t::PRESCALER_8_9 : adf4351_regs_t::PRESCALER_4_5;
adf435x_tuning_constraints tuning_constraints;
tuning_constraints.force_frac0 = is_int_n;
@@ -243,11 +252,17 @@ double wbx_base::wbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
tuning_constraints.int_range = uhd::range_t(prescaler_to_min_int_div[prescaler], 4095);
tuning_constraints.pfd_freq_max = 25e6;
tuning_constraints.rf_divider_range = uhd::range_t(1, 64);
+ //When divider resync is enabled, a 180 deg phase error is introduced when syncing
+ //multiple WBX boards. Switching to fundamental mode works arounds this issue.
+ tuning_constraints.feedback_after_divider = div_resync_enabled;
- double actual_freq;
+ double synth_actual_freq = 0;
adf435x_tuning_settings tuning_settings = tune_adf435x_synth(
- target_freq, self_base->get_iface()->get_clock_rate(unit),
- tuning_constraints, actual_freq);
+ synth_target_freq, reference_freq, tuning_constraints, synth_actual_freq);
+
+ //The mixer has a divide-by-2 stage on the LO port so the synthesizer
+ //actual_freq must /2 the synth_actual_freq
+ double actual_freq = synth_actual_freq / 2;
//load the register values
adf4351_regs_t regs;
@@ -263,10 +278,12 @@ double wbx_base::wbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
regs.int_16_bit = tuning_settings.int_16_bit;
regs.mod_12_bit = tuning_settings.mod_12_bit;
regs.clock_divider_12_bit = tuning_settings.clock_divider_12_bit;
- regs.feedback_select = tuning_settings.feedback_after_divider ?
+ regs.feedback_select = tuning_constraints.feedback_after_divider ?
adf4351_regs_t::FEEDBACK_SELECT_DIVIDED :
adf4351_regs_t::FEEDBACK_SELECT_FUNDAMENTAL;
- regs.clock_div_mode = adf4351_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE;
+ regs.clock_div_mode = div_resync_enabled ?
+ adf4351_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE :
+ adf4351_regs_t::CLOCK_DIV_MODE_FAST_LOCK;
regs.prescaler = prescaler;
regs.r_counter_10_bit = tuning_settings.r_counter_10_bit;
regs.reference_divide_by_2 = tuning_settings.r_divide_by_2_en ?
@@ -307,5 +324,6 @@ double wbx_base::wbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar
UHD_LOGV(often) << boost::format(
"%s tune: actual frequency %f Mhz"
) % board_name.c_str() % (actual_freq/1e6) << std::endl;
+
return actual_freq;
}
diff --git a/host/lib/usrp/gps_ctrl.cpp b/host/lib/usrp/gps_ctrl.cpp
index 4bf8eb3a3..c0d44abd5 100644
--- a/host/lib/usrp/gps_ctrl.cpp
+++ b/host/lib/usrp/gps_ctrl.cpp
@@ -30,6 +30,7 @@
#include "boost/tuple/tuple.hpp"
#include "boost/foreach.hpp"
+#include <boost/container/vector.hpp>
using namespace uhd;
using namespace boost::gregorian;
@@ -68,34 +69,36 @@ private:
return std::string();
}
- std::string msg = _recv();
+ const std::list<std::string> list = boost::assign::list_of("GPGGA")("GPRMC")("SERVO");
static const boost::regex status_regex("\\d\\d-\\d\\d-\\d\\d");
+ std::map<std::string,std::string> msgs;
+
+ // Get all GPSDO messages available
+ // Creating a map here because we only want the latest of each message type
+ for (std::string msg = _recv(); msg.length() > 6; msg = _recv())
+ {
+ // Look for SERVO message
+ if (boost::regex_search(msg, status_regex, boost::regex_constants::match_continuous))
+ msgs["SERVO"] = msg;
+ else
+ msgs[msg.substr(1,5)] = msg;
+ }
+
boost::system_time time = boost::get_system_time();
- if(msg.size() < 6)
- return std::string();
- std::string nmea = msg.substr(1,5);
- const std::list<std::string> list = boost::assign::list_of("GPGGA")("GPRMC");
+ // Update sensors with newly read data
BOOST_FOREACH(std::string key, list) {
- // beginning matches one of the NMEA keys
- if(!nmea.compare(key)) {
- sensors[key] = boost::make_tuple(msg, time, !sensor.compare(key));
- // if this was what we're looking for return it
- return (!sensor.compare(key))? msg : std::string();
- }
+ if (msgs[key].length())
+ sensors[key] = boost::make_tuple(msgs[key], time, !sensor.compare(key));
}
- //We're still here so it's not one of the NMEA strings from above
- if(boost::regex_search(msg, status_regex, boost::regex_constants::match_continuous)) {
- trim(msg);
- sensors["SERVO"] = boost::make_tuple(msg, time, false);
- if(!sensor.compare("SERVO"))
- return msg;
- else
- return std::string();
- }
+ // Return requested sensor if it was updated
+ if (msgs[sensor].length())
+ return msgs[sensor];
+
return std::string();
}
+
public:
gps_ctrl_impl(uart_iface::sptr uart){
_uart = uart;
@@ -332,8 +335,8 @@ private:
}
}
- std::string _recv(void){
- return _uart->read_uart(GPS_TIMEOUT_DELAY_MS/1000.);
+ std::string _recv(double timeout = GPS_TIMEOUT_DELAY_MS/1000.){
+ return _uart->read_uart(timeout);
}
void _send(const std::string &buf){
diff --git a/host/lib/usrp/x300/x300_clock_ctrl.cpp b/host/lib/usrp/x300/x300_clock_ctrl.cpp
index 1a4cd4668..a986928a7 100644
--- a/host/lib/usrp/x300/x300_clock_ctrl.cpp
+++ b/host/lib/usrp/x300/x300_clock_ctrl.cpp
@@ -24,6 +24,8 @@
#include <cmath>
#include <cstdlib>
+static const double X300_REF_CLK_OUT_RATE = 10e6;
+
using namespace uhd;
class x300_clock_ctrl_impl : public x300_clock_ctrl {
@@ -66,7 +68,7 @@ double get_sysref_clock_rate(void) {
double get_refout_clock_rate(void) {
//We support only one reference output rate
- return 10e6;
+ return X300_REF_CLK_OUT_RATE;
}
void set_dboard_rate(const x300_clock_which_t, double rate) {
@@ -292,7 +294,7 @@ void set_master_clock_rate(double clock_rate) {
_lmk04816_regs.CLKout8_9_DIV = vco_div;
// Register 5
_lmk04816_regs.CLKout10_11_PD = lmk04816_regs_t::CLKOUT10_11_PD_NORMAL;
- _lmk04816_regs.CLKout10_11_DIV = vco_div;
+ _lmk04816_regs.CLKout10_11_DIV = vco_div * static_cast<int>(clock_rate/X300_REF_CLK_OUT_RATE);
// Register 6
_lmk04816_regs.CLKout0_TYPE = lmk04816_regs_t::CLKOUT0_TYPE_LVDS; //FPGA
diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp
index f62967018..b20897fc6 100644
--- a/host/lib/usrp/x300/x300_impl.cpp
+++ b/host/lib/usrp/x300/x300_impl.cpp
@@ -34,6 +34,7 @@
#include <boost/assign/list_of.hpp>
#include <fstream>
#include <uhd/transport/udp_zero_copy.hpp>
+#include <uhd/transport/udp_constants.hpp>
#include <uhd/transport/nirio_zero_copy.hpp>
#include <uhd/transport/nirio/niusrprio_session.h>
#include <uhd/utils/platform.hpp>
@@ -399,34 +400,25 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)
if (key.find("send") != std::string::npos) mb.send_args[key] = dev_addr[key];
}
- const std::vector<std::string> DB_NAMES = boost::assign::list_of("A")("B");
-
- //create basic communication
- UHD_MSG(status) << "Setup basic communication..." << std::endl;
- if (mb.xport_path == "nirio") {
- mb.zpu_ctrl = x300_make_ctrl_iface_pcie(mb.rio_fpga_interface->get_kernel_proxy());
- } else {
- mb.zpu_ctrl = x300_make_ctrl_iface_enet(udp_simple::make_connected(mb.addr,
- BOOST_STRINGIZE(X300_FW_COMMS_UDP_PORT)));
- }
-
- if (mb.xport_path == "eth")
- {
- mtu_result_t user_set;
- user_set.recv_mtu = dev_addr.has_key("recv_frame_size") \
- ? boost::lexical_cast<size_t>(dev_addr["recv_frame_size"]) \
- : X300_ETH_DATA_FRAME_SIZE;
- user_set.send_mtu = dev_addr.has_key("send_frame_size") \
- ? boost::lexical_cast<size_t>(dev_addr["send_frame_size"]) \
- : X300_ETH_DATA_FRAME_SIZE;
-
- // Detect the MTU on the path to the USRP
- mtu_result_t result;
- try {
- result = determine_mtu(mb.addr, user_set);
- } catch(std::exception &e) {
- UHD_MSG(error) << e.what() << std::endl;
- }
+ if (mb.xport_path == "eth" ) {
+ /* This is an ETH connection. Figure out what the maximum supported frame
+ * size is for the transport in the up and down directions. The frame size
+ * depends on the host PIC's NIC's MTU settings. To determine the frame size,
+ * we test for support up to an expected "ceiling". If the user
+ * specified a frame size, we use that frame size as the ceiling. If no
+ * frame size was specified, we use the maximum UHD frame size.
+ *
+ * To optimize performance, the frame size should be greater than or equal
+ * to the frame size that UHD uses so that frames don't get split across
+ * multiple transmission units - this is why the limits passed into the
+ * 'determine_max_frame_size' function are actually frame sizes. */
+ frame_size_t req_max_frame_size;
+ req_max_frame_size.recv_frame_size = (mb.recv_args.has_key("recv_frame_size")) \
+ ? boost::lexical_cast<size_t>(mb.recv_args["recv_frame_size"]) \
+ : X300_10GE_DATA_FRAME_MAX_SIZE;
+ req_max_frame_size.send_frame_size = (mb.send_args.has_key("send_frame_size")) \
+ ? boost::lexical_cast<size_t>(mb.send_args["send_frame_size"]) \
+ : X300_10GE_DATA_FRAME_MAX_SIZE;
#if defined UHD_PLATFORM_LINUX
const std::string mtu_tool("ip link");
@@ -436,23 +428,47 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)
const std::string mtu_tool("ifconfig");
#endif
- if(result.recv_mtu < user_set.recv_mtu) {
+ // Detect the frame size on the path to the USRP
+ try {
+ max_frame_sizes = determine_max_frame_size(mb.addr, req_max_frame_size);
+ } catch(std::exception &e) {
+ UHD_MSG(error) << e.what() << std::endl;
+ }
+
+ if ((mb.recv_args.has_key("recv_frame_size"))
+ && (req_max_frame_size.recv_frame_size < max_frame_sizes.recv_frame_size)) {
UHD_MSG(warning)
- << boost::format("The receive path contains entities that do not support MTUs >= one recv frame's size (%lu).")
- % user_set.recv_mtu << std::endl
- << boost::format("Please verify your NIC's MTU setting using '%s' or set the recv_frame_size argument.")
- % mtu_tool << std::endl;
+ << boost::format("You requested a receive frame size of (%lu) but your NIC's max frame size is (%lu).")
+ % req_max_frame_size.recv_frame_size << max_frame_sizes.recv_frame_size << std::endl
+ << boost::format("Please verify your NIC's MTU setting using '%s' or set the recv_frame_size argument appropriately.")
+ % mtu_tool << std::endl
+ << "UHD will use the auto-detected max frame size for this connection."
+ << std::endl;
}
- if(result.send_mtu < user_set.send_mtu) {
+ if ((mb.recv_args.has_key("send_frame_size"))
+ && (req_max_frame_size.send_frame_size < max_frame_sizes.send_frame_size)) {
UHD_MSG(warning)
- << boost::format("The send path contains entities that do not support MTUs >= one send frame's size (%lu).")
- % user_set.send_mtu << std::endl
- << boost::format("Please verify your NIC's MTU setting using '%s' or set the send_frame_size argument.")
- % mtu_tool << std::endl;
+ << boost::format("You requested a send frame size of (%lu) but your NIC's max frame size is (%lu).")
+ % req_max_frame_size.send_frame_size << max_frame_sizes.send_frame_size << std::endl
+ << boost::format("Please verify your NIC's MTU setting using '%s' or set the send_frame_size argument appropriately.")
+ % mtu_tool << std::endl
+ << "UHD will use the auto-detected max frame size for this connection."
+ << std::endl;
}
}
+ const std::vector<std::string> DB_NAMES = boost::assign::list_of("A")("B");
+
+ //create basic communication
+ UHD_MSG(status) << "Setup basic communication..." << std::endl;
+ if (mb.xport_path == "nirio") {
+ mb.zpu_ctrl = x300_make_ctrl_iface_pcie(mb.rio_fpga_interface->get_kernel_proxy());
+ } else {
+ mb.zpu_ctrl = x300_make_ctrl_iface_enet(udp_simple::make_connected(mb.addr,
+ BOOST_STRINGIZE(X300_FW_COMMS_UDP_PORT)));
+ }
+
mb.claimer_task = uhd::task::make(boost::bind(&x300_impl::claimer_loop, this, mb.zpu_ctrl));
//extract the FW path for the X300
@@ -469,6 +485,9 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)
this->check_fw_compat(mb_path, mb.zpu_ctrl);
this->check_fpga_compat(mb_path, mb.zpu_ctrl);
+ //store which FPGA image is loaded
+ mb.loaded_fpga_image = get_fpga_option(mb.zpu_ctrl);
+
//low speed perif access
mb.zpu_spi = spi_core_3000::make(mb.zpu_ctrl, SR_ADDR(SET0_BASE, ZPU_SR_SPI),
SR_ADDR(SET0_BASE, ZPU_RB_SPI));
@@ -1030,8 +1049,6 @@ x300_impl::both_xports_t x300_impl::make_transport(
)
{
mboard_members_t &mb = _mb[mb_index];
- const std::string& addr = mb.addr;
- const std::string& xport_path = mb.xport_path;
both_xports_t xports;
sid_config_t config;
@@ -1047,47 +1064,122 @@ x300_impl::both_xports_t x300_impl::make_transport(
(prefix != X300_RADIO_DEST_PREFIX_CTRL) ? args : DEFAULT_XPORT_ARGS;
zero_copy_xport_params default_buff_args;
- if (xport_path == "nirio") {
+
+ if (mb.xport_path == "nirio") {
default_buff_args.send_frame_size =
- (prefix == X300_RADIO_DEST_PREFIX_TX) ? X300_PCIE_DATA_FRAME_SIZE : X300_PCIE_MSG_FRAME_SIZE;
+ (prefix == X300_RADIO_DEST_PREFIX_TX)
+ ? X300_PCIE_DATA_FRAME_SIZE
+ : X300_PCIE_MSG_FRAME_SIZE;
+
default_buff_args.recv_frame_size =
- (prefix == X300_RADIO_DEST_PREFIX_RX) ? X300_PCIE_DATA_FRAME_SIZE : X300_PCIE_MSG_FRAME_SIZE;
+ (prefix == X300_RADIO_DEST_PREFIX_RX)
+ ? X300_PCIE_DATA_FRAME_SIZE
+ : X300_PCIE_MSG_FRAME_SIZE;
+
default_buff_args.num_send_frames =
- (prefix == X300_RADIO_DEST_PREFIX_TX) ? X300_PCIE_DATA_NUM_FRAMES : X300_PCIE_MSG_NUM_FRAMES;
+ (prefix == X300_RADIO_DEST_PREFIX_TX)
+ ? X300_PCIE_DATA_NUM_FRAMES
+ : X300_PCIE_MSG_NUM_FRAMES;
+
default_buff_args.num_recv_frames =
- (prefix == X300_RADIO_DEST_PREFIX_RX) ? X300_PCIE_DATA_NUM_FRAMES : X300_PCIE_MSG_NUM_FRAMES;
+ (prefix == X300_RADIO_DEST_PREFIX_RX)
+ ? X300_PCIE_DATA_NUM_FRAMES
+ : X300_PCIE_MSG_NUM_FRAMES;
xports.recv = nirio_zero_copy::make(
- mb.rio_fpga_interface, get_pcie_dma_channel(destination, prefix), default_buff_args, xport_args);
+ mb.rio_fpga_interface,
+ get_pcie_dma_channel(destination, prefix),
+ default_buff_args,
+ xport_args);
+
xports.send = xports.recv;
//For the nirio transport, buffer size is depends on the frame size and num frames
xports.recv_buff_size = xports.recv->get_num_recv_frames() * xports.recv->get_recv_frame_size();
xports.send_buff_size = xports.send->get_num_send_frames() * xports.send->get_send_frame_size();
- } else {
+ } else if (mb.xport_path == "eth") {
+
+ /* Determine what the recommended frame size is for this
+ * connection type.*/
+ size_t eth_data_rec_frame_size = 0;
+
+ if (mb.loaded_fpga_image == "HGS") {
+ if (mb.router_dst_here == X300_XB_DST_E0) {
+ eth_data_rec_frame_size = X300_1GE_DATA_FRAME_MAX_SIZE;
+ } else if (mb.router_dst_here == X300_XB_DST_E1) {
+ eth_data_rec_frame_size = X300_10GE_DATA_FRAME_MAX_SIZE;
+ }
+ } else if (mb.loaded_fpga_image == "XGS") {
+ eth_data_rec_frame_size = X300_10GE_DATA_FRAME_MAX_SIZE;
+ }
+
+ if (eth_data_rec_frame_size == 0) {
+ throw uhd::runtime_error("Unable to determine ETH link type.");
+ }
+
+ /* Print a warning if the system's max available frame size is less than the most optimal
+ * frame size for this type of connection. */
+ if (max_frame_sizes.send_frame_size < eth_data_rec_frame_size) {
+ UHD_MSG(warning)
+ << boost::format("For this connection, UHD recommends a send frame size of at least %lu for best\nperformance, but your system's MTU will only allow %lu.")
+ % eth_data_rec_frame_size
+ % max_frame_sizes.send_frame_size
+ << std::endl
+ << "This will negatively impact your maximum achievable sample rate."
+ << std::endl;
+ }
+
+ if (max_frame_sizes.recv_frame_size < eth_data_rec_frame_size) {
+ UHD_MSG(warning)
+ << boost::format("For this connection, UHD recommends a receive frame size of at least %lu for best\nperformance, but your system's MTU will only allow %lu.")
+ % eth_data_rec_frame_size
+ % max_frame_sizes.recv_frame_size
+ << std::endl
+ << "This will negatively impact your maximum achievable sample rate."
+ << std::endl;
+ }
+
+ // Account for headers
+ size_t system_max_send_frame_size = (size_t) max_frame_sizes.send_frame_size - 64;
+ size_t system_max_recv_frame_size = (size_t) max_frame_sizes.recv_frame_size - 64;
+
+ // Make sure frame sizes do not exceed the max available value supported by UHD
default_buff_args.send_frame_size =
- (prefix == X300_RADIO_DEST_PREFIX_TX) ? X300_ETH_DATA_FRAME_SIZE : X300_ETH_MSG_FRAME_SIZE;
+ (prefix == X300_RADIO_DEST_PREFIX_TX)
+ ? std::min(system_max_send_frame_size, X300_10GE_DATA_FRAME_MAX_SIZE)
+ : std::min(system_max_send_frame_size, X300_ETH_MSG_FRAME_SIZE);
+
default_buff_args.recv_frame_size =
- (prefix == X300_RADIO_DEST_PREFIX_RX) ? X300_ETH_DATA_FRAME_SIZE : X300_ETH_MSG_FRAME_SIZE;
+ (prefix == X300_RADIO_DEST_PREFIX_RX)
+ ? std::min(system_max_recv_frame_size, X300_10GE_DATA_FRAME_MAX_SIZE)
+ : std::min(system_max_recv_frame_size, X300_ETH_MSG_FRAME_SIZE);
+
default_buff_args.num_send_frames =
- (prefix == X300_RADIO_DEST_PREFIX_TX) ? X300_ETH_DATA_NUM_FRAMES : X300_ETH_MSG_NUM_FRAMES;
+ (prefix == X300_RADIO_DEST_PREFIX_TX)
+ ? X300_ETH_DATA_NUM_FRAMES
+ : X300_ETH_MSG_NUM_FRAMES;
+
default_buff_args.num_recv_frames =
- (prefix == X300_RADIO_DEST_PREFIX_RX) ? X300_ETH_DATA_NUM_FRAMES : X300_ETH_MSG_NUM_FRAMES;
+ (prefix == X300_RADIO_DEST_PREFIX_RX)
+ ? X300_ETH_DATA_NUM_FRAMES
+ : X300_ETH_MSG_NUM_FRAMES;
//make a new transport - fpga has no idea how to talk to use on this yet
udp_zero_copy::buff_params buff_params;
- xports.recv = udp_zero_copy::make(addr, BOOST_STRINGIZE(X300_VITA_UDP_PORT), default_buff_args, buff_params, xport_args);
+ xports.recv = udp_zero_copy::make(mb.addr,
+ BOOST_STRINGIZE(X300_VITA_UDP_PORT),
+ default_buff_args,
+ buff_params,
+ xport_args);
+
xports.send = xports.recv;
- //For the UDP transport the buffer size if the size of the socket buffer in the kernel
+ //For the UDP transport the buffer size if the size of the socket buffer
+ //in the kernel
xports.recv_buff_size = buff_params.recv_buff_size;
xports.send_buff_size = buff_params.send_buff_size;
- }
- //always program the framer if this is a socket, even its caching was used
- if (xport_path != "nirio")
- {
//clear the ethernet dispatcher's udp port
//NOT clearing this, the dispatcher is now intelligent
//_zpu_ctrl->poke32(SR_ADDR(SET0_BASE, (ZPU_SR_ETHINT0+8+3)), 0);
@@ -1095,7 +1187,7 @@ x300_impl::both_xports_t x300_impl::make_transport(
//send a mini packet with SID into the ZPU
//ZPU will reprogram the ethernet framer
UHD_LOG << "programming packet for new xport on "
- << addr << std::hex << "sid 0x" << sid << std::dec << std::endl;
+ << mb.addr << std::hex << "sid 0x" << sid << std::dec << std::endl;
//YES, get a __send__ buffer from the __recv__ socket
//-- this is the only way to program the framer for recv:
managed_send_buffer::sptr buff = xports.recv->get_send_buff();
@@ -1113,6 +1205,7 @@ x300_impl::both_xports_t x300_impl::make_transport(
//ethernet framer has been programmed before we return.
mb.zpu_ctrl->peek32(0);
}
+
return xports;
}
@@ -1299,13 +1392,15 @@ bool x300_impl::is_claimed(wb_iface::sptr iface)
}
/***********************************************************************
- * MTU detection
+ * Frame size detection
**********************************************************************/
-x300_impl::mtu_result_t x300_impl::determine_mtu(const std::string &addr, const mtu_result_t &user_mtu)
+x300_impl::frame_size_t x300_impl::determine_max_frame_size(const std::string &addr,
+ const frame_size_t &user_frame_size)
{
- udp_simple::sptr udp = udp_simple::make_connected(addr, BOOST_STRINGIZE(X300_MTU_DETECT_UDP_PORT));
+ udp_simple::sptr udp = udp_simple::make_connected(addr,
+ BOOST_STRINGIZE(X300_MTU_DETECT_UDP_PORT));
- std::vector<boost::uint8_t> buffer(std::max(user_mtu.recv_mtu, user_mtu.send_mtu));
+ std::vector<boost::uint8_t> buffer(std::max(user_frame_size.recv_frame_size, user_frame_size.send_frame_size));
x300_mtu_t *request = reinterpret_cast<x300_mtu_t *>(&buffer.front());
static const double echo_timeout = 0.020; //20 ms
@@ -1317,54 +1412,62 @@ x300_impl::mtu_result_t x300_impl::determine_mtu(const std::string &addr, const
if (!(uhd::ntohx<boost::uint32_t>(request->flags) & X300_MTU_DETECT_ECHO_REPLY))
throw uhd::not_implemented_error("Holler protocol not implemented");
- size_t min_recv_mtu = sizeof(x300_mtu_t);
- size_t max_recv_mtu = user_mtu.recv_mtu;
- size_t min_send_mtu = sizeof(x300_mtu_t);
- size_t max_send_mtu = user_mtu.send_mtu;
+ size_t min_recv_frame_size = sizeof(x300_mtu_t);
+ size_t max_recv_frame_size = user_frame_size.recv_frame_size;
+ size_t min_send_frame_size = sizeof(x300_mtu_t);
+ size_t max_send_frame_size = user_frame_size.send_frame_size;
- UHD_MSG(status) << "Determining receive MTU ... ";
- while (min_recv_mtu < max_recv_mtu)
+ UHD_MSG(status) << "Determining maximum frame size... ";
+ while (min_recv_frame_size < max_recv_frame_size)
{
- size_t test_mtu = (max_recv_mtu/2 + min_recv_mtu/2 + 3) & ~3;
+ size_t test_frame_size = (max_recv_frame_size/2 + min_recv_frame_size/2 + 3) & ~3;
request->flags = uhd::htonx<boost::uint32_t>(X300_MTU_DETECT_ECHO_REQUEST);
- request->size = uhd::htonx<boost::uint32_t>(test_mtu);
+ request->size = uhd::htonx<boost::uint32_t>(test_frame_size);
udp->send(boost::asio::buffer(buffer, sizeof(x300_mtu_t)));
size_t len = udp->recv(boost::asio::buffer(buffer), echo_timeout);
- if (len >= test_mtu)
- min_recv_mtu = test_mtu;
+ if (len >= test_frame_size)
+ min_recv_frame_size = test_frame_size;
else
- max_recv_mtu = test_mtu - 4;
+ max_recv_frame_size = test_frame_size - 4;
+ }
+ if(min_recv_frame_size < IP_PROTOCOL_MIN_MTU_SIZE-IP_PROTOCOL_UDP_PLUS_IP_HEADER) {
+ throw uhd::runtime_error("System receive MTU size is less than the minimum required by the IP protocol.");
}
- UHD_MSG(status) << min_recv_mtu << std::endl;
- UHD_MSG(status) << "Determining send MTU ... ";
- while (min_send_mtu < max_send_mtu)
+ while (min_send_frame_size < max_send_frame_size)
{
- size_t test_mtu = (max_send_mtu/2 + min_send_mtu/2 + 3) & ~3;
+ size_t test_frame_size = (max_send_frame_size/2 + min_send_frame_size/2 + 3) & ~3;
request->flags = uhd::htonx<boost::uint32_t>(X300_MTU_DETECT_ECHO_REQUEST);
request->size = uhd::htonx<boost::uint32_t>(sizeof(x300_mtu_t));
- udp->send(boost::asio::buffer(buffer, test_mtu));
+ udp->send(boost::asio::buffer(buffer, test_frame_size));
size_t len = udp->recv(boost::asio::buffer(buffer), echo_timeout);
if (len >= sizeof(x300_mtu_t))
len = uhd::ntohx<boost::uint32_t>(request->size);
- if (len >= test_mtu)
- min_send_mtu = test_mtu;
+ if (len >= test_frame_size)
+ min_send_frame_size = test_frame_size;
else
- max_send_mtu = test_mtu - 4;
+ max_send_frame_size = test_frame_size - 4;
+ }
+
+ if(min_send_frame_size < IP_PROTOCOL_MIN_MTU_SIZE-IP_PROTOCOL_UDP_PLUS_IP_HEADER) {
+ throw uhd::runtime_error("System send MTU size is less than the minimum required by the IP protocol.");
}
- UHD_MSG(status) << min_send_mtu << std::endl;
- mtu_result_t mtu;
- mtu.recv_mtu = min_recv_mtu;
- mtu.send_mtu = min_send_mtu;
- return mtu;
+ frame_size_t frame_size;
+ // There are cases when NICs accept oversized packets, in which case we'd falsely
+ // detect a larger-than-possible frame size. A safe and sensible value is the minimum
+ // of the recv and send frame sizes.
+ frame_size.recv_frame_size = std::min(min_recv_frame_size, min_send_frame_size);
+ frame_size.send_frame_size = std::min(min_recv_frame_size, min_send_frame_size);
+ UHD_MSG(status) << frame_size.send_frame_size << " bytes." << std::endl;
+ return frame_size;
}
/***********************************************************************
diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp
index 37f8cc468..1fb3676a0 100644
--- a/host/lib/usrp/x300/x300_impl.hpp
+++ b/host/lib/usrp/x300/x300_impl.hpp
@@ -58,21 +58,23 @@ static const double X300_BUS_CLOCK_RATE = 175e6; //Hz
static const size_t X300_TX_HW_BUFF_SIZE = 0x90000; //576KiB
static const size_t X300_TX_FC_RESPONSE_FREQ = 8; //per flow-control window
-static const size_t X300_RX_SW_BUFF_SIZE_ETH = 0x2000000; //32MiB For an ~8k MTU any size >32MiB is just wasted buffer space
-static const size_t X300_RX_SW_BUFF_SIZE_ETH_MACOS = 0x100000; //1Mib
-static const double X300_RX_SW_BUFF_FULL_FACTOR = 0.90; //Buffer should ideally be 90% full.
-static const size_t X300_RX_FC_REQUEST_FREQ = 32; //per flow-control window
-
-static const size_t X300_PCIE_DATA_FRAME_SIZE = 8192; //bytes
-static const size_t X300_PCIE_DATA_NUM_FRAMES = 2048;
-static const size_t X300_PCIE_MSG_FRAME_SIZE = 256; //bytes
-static const size_t X300_PCIE_MSG_NUM_FRAMES = 32;
-
-static const size_t X300_ETH_DATA_FRAME_SIZE = 8000; //bytes
-static const size_t X300_ETH_DATA_NUM_FRAMES = 32;
-static const size_t X300_ETH_MSG_FRAME_SIZE = uhd::transport::udp_simple::mtu; //bytes
-static const size_t X300_ETH_MSG_NUM_FRAMES = 32;
-static const double X300_DEFAULT_SYSREF_RATE = 10e6;
+static const size_t X300_RX_SW_BUFF_SIZE_ETH = 0x2000000;//32MiB For an ~8k frame size any size >32MiB is just wasted buffer space
+static const size_t X300_RX_SW_BUFF_SIZE_ETH_MACOS = 0x100000; //1Mib
+static const double X300_RX_SW_BUFF_FULL_FACTOR = 0.90; //Buffer should ideally be 90% full.
+static const size_t X300_RX_FC_REQUEST_FREQ = 32; //per flow-control window
+
+static const size_t X300_PCIE_DATA_FRAME_SIZE = 8192; //bytes
+static const size_t X300_PCIE_DATA_NUM_FRAMES = 2048;
+static const size_t X300_PCIE_MSG_FRAME_SIZE = 256; //bytes
+static const size_t X300_PCIE_MSG_NUM_FRAMES = 32;
+
+static const size_t X300_10GE_DATA_FRAME_MAX_SIZE = 8000; //bytes
+static const size_t X300_1GE_DATA_FRAME_MAX_SIZE = 1472; //bytes
+static const size_t X300_ETH_MSG_FRAME_SIZE = uhd::transport::udp_simple::mtu; //bytes
+
+static const size_t X300_ETH_MSG_NUM_FRAMES = 32;
+static const size_t X300_ETH_DATA_NUM_FRAMES = 32;
+static const double X300_DEFAULT_SYSREF_RATE = 10e6;
#define X300_RADIO_DEST_PREFIX_TX 0
#define X300_RADIO_DEST_PREFIX_CTRL 1
@@ -207,6 +209,9 @@ private:
int clock_control_regs__pps_out_enb;
int clock_control_regs__tcxo_enb;
int clock_control_regs__gpsdo_pwr;
+
+ //which FPGA image is loaded
+ std::string loaded_fpga_image;
};
std::vector<mboard_members_t> _mb;
@@ -243,13 +248,19 @@ private:
const uhd::device_addr_t& args,
boost::uint32_t& sid);
- struct mtu_result_t
+ struct frame_size_t
{
- size_t recv_mtu;
- size_t send_mtu;
+ size_t recv_frame_size;
+ size_t send_frame_size;
};
-
- mtu_result_t determine_mtu(const std::string &addr, const mtu_result_t &user_mtu);
+ frame_size_t max_frame_sizes;
+
+ /*!
+ * Automatically determine the maximum frame size available by sending a UDP packet
+ * to the device and see which packet sizes actually work. This way, we can take
+ * switches etc. into account which might live between the device and the host.
+ */
+ frame_size_t determine_max_frame_size(const std::string &addr, const frame_size_t &user_mtu);
////////////////////////////////////////////////////////////////////
//