aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/lib/usrp/usrp2/codec_ctrl.cpp5
-rw-r--r--host/lib/usrp/usrp2/codec_ctrl.hpp7
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp80
3 files changed, 85 insertions, 7 deletions
diff --git a/host/lib/usrp/usrp2/codec_ctrl.cpp b/host/lib/usrp/usrp2/codec_ctrl.cpp
index c3e7b332f..5c1c006fb 100644
--- a/host/lib/usrp/usrp2/codec_ctrl.cpp
+++ b/host/lib/usrp/usrp2/codec_ctrl.cpp
@@ -179,6 +179,11 @@ public:
}
}
+ size_t get_tx_interpolation() const
+ {
+ return 4;
+ }
+
private:
ad9777_regs_t _ad9777_regs;
ads62p44_regs_t _ads62p44_regs;
diff --git a/host/lib/usrp/usrp2/codec_ctrl.hpp b/host/lib/usrp/usrp2/codec_ctrl.hpp
index e32b508e9..ac808e357 100644
--- a/host/lib/usrp/usrp2/codec_ctrl.hpp
+++ b/host/lib/usrp/usrp2/codec_ctrl.hpp
@@ -56,6 +56,13 @@ public:
virtual void set_rx_digital_fine_gain(double gain) = 0;
+ /*! Return the internal interpolation on the TX side. This is the factor
+ * between the rate of incoming samples and rate at which the DAC is
+ * actually clocked. Values > 1 will enable features, such as internal
+ * modulation.
+ */
+ virtual size_t get_tx_interpolation() const = 0;
+
};
#endif /* INCLUDED_CODEC_CTRL_HPP */
diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp
index 88591333a..d6ab11969 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.cpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.cpp
@@ -622,21 +622,44 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr) :
// create tx dsp control objects
////////////////////////////////////////////////////////////////
_mbc[mb].tx_dsp = tx_dsp_core_200::make(
- _mbc[mb].wbiface, U2_REG_SR_ADDR(SR_TX_DSP), U2_REG_SR_ADDR(SR_TX_CTRL), USRP2_TX_ASYNC_SID
+ _mbc[mb].wbiface,
+ U2_REG_SR_ADDR(SR_TX_DSP),
+ U2_REG_SR_ADDR(SR_TX_CTRL),
+ USRP2_TX_ASYNC_SID
);
_mbc[mb].tx_dsp->set_link_rate(USRP2_LINK_RATE_BPS);
+ { // This scope can be removed once we're able to do named captures
+ auto this_tx_dsp = _mbc[mb].tx_dsp; // This can then also go away
_tree->access<double>(mb_path / "tick_rate")
- .add_coerced_subscriber(boost::bind(&tx_dsp_core_200::set_tick_rate, _mbc[mb].tx_dsp, _1));
+ .add_coerced_subscriber([this_tx_dsp](const double rate){
+ this_tx_dsp->set_tick_rate(rate);
+ })
+ ;
_tree->create<meta_range_t>(mb_path / "tx_dsps/0/rate/range")
- .set_publisher(boost::bind(&tx_dsp_core_200::get_host_rates, _mbc[mb].tx_dsp));
+ .set_publisher([this_tx_dsp](){
+ return this_tx_dsp->get_host_rates();
+ })
+ ;
_tree->create<double>(mb_path / "tx_dsps/0/rate/value")
.set(1e6) //some default
- .set_coercer(boost::bind(&tx_dsp_core_200::set_host_rate, _mbc[mb].tx_dsp, _1))
- .add_coerced_subscriber(boost::bind(&usrp2_impl::update_tx_samp_rate, this, mb, 0, _1));
+ .set_coercer([this_tx_dsp](const double rate){
+ return this_tx_dsp->set_host_rate(rate);
+ })
+ .add_coerced_subscriber([this, mb](const double rate){
+ this->update_tx_samp_rate(mb, 0, rate);
+ })
+ ;
+ } // End of non-C++14 scope (to release reference to this_tx_dsp)
_tree->create<double>(mb_path / "tx_dsps/0/freq/value")
- .set_coercer(boost::bind(&tx_dsp_core_200::set_freq, _mbc[mb].tx_dsp, _1));
+ .set_coercer([this, mb](const double rate){
+ return this->set_tx_dsp_freq(mb, rate);
+ })
+ ;
_tree->create<meta_range_t>(mb_path / "tx_dsps/0/freq/range")
- .set_publisher(boost::bind(&tx_dsp_core_200::get_freq_range, _mbc[mb].tx_dsp));
+ .set_publisher([this, mb](){
+ return this->get_tx_dsp_freq_range(mb);
+ })
+ ;
//setup dsp flow control
const double ups_per_sec = device_args_i.cast<double>("ups_per_sec", 20);
@@ -810,6 +833,49 @@ void usrp2_impl::set_tx_fe_corrections(const std::string &mb, const double lo_fr
}
}
+double usrp2_impl::set_tx_dsp_freq(
+ const std::string &mb,
+ const double freq_
+) {
+ double new_freq = freq_;
+ const double tick_rate =
+ _tree->access<double>("/mboards/"+mb+"/tick_rate").get();
+
+ //calculate the DAC shift (multiples of rate)
+ const int sign = boost::math::sign(new_freq);
+ const int zone = std::min(boost::math::iround(new_freq/tick_rate), 2);
+ const double dac_shift = sign*zone*tick_rate;
+ new_freq -= dac_shift; //update FPGA DSP target freq
+ UHD_LOG_TRACE("USRP2",
+ "DSP Tuning: Requested " + std::to_string(freq_/1e6) + " MHz, Using "
+ "Nyquist zone " + std::to_string(sign*zone) + ", leftover DSP tuning: "
+ + std::to_string(new_freq/1e6) + " MHz.");
+
+ //set the DAC shift (modulation mode)
+ if (zone == 0) {
+ _mbc[mb].codec->set_tx_mod_mode(0); //no shift
+ } else {
+ _mbc[mb].codec->set_tx_mod_mode(sign*4/zone); //DAC interp = 4
+ }
+
+ return _mbc[mb].tx_dsp->set_freq(new_freq) + dac_shift; //actual freq
+}
+
+meta_range_t usrp2_impl::get_tx_dsp_freq_range(const std::string &mb)
+{
+ const double dac_rate =
+ _tree->access<double>("/mboards/" + mb + "/tick_rate").get()
+ * _mbc[mb].codec->get_tx_interpolation();
+ const auto dsp_range_step = _mbc[mb].tx_dsp->get_freq_range().step();
+ // The DSP tuning rate is the entire range of the DAC clock rate. The step
+ // size is determined by the FPGA IP, however.
+ return meta_range_t(
+ -dac_rate / 2,
+ +dac_rate / 2,
+ dsp_range_step
+ );
+}
+
#include <boost/math/special_functions/round.hpp>
#include <boost/math/special_functions/sign.hpp>