diff options
author | Ashish Chaudhari <ashish@ettus.com> | 2016-03-13 18:30:21 -0700 |
---|---|---|
committer | Ashish Chaudhari <ashish@ettus.com> | 2016-03-21 17:46:23 -0700 |
commit | 7fad896c07fbdda4cf112e9e4999a5ab8f5484a5 (patch) | |
tree | 1090e59026bb9ca1958ad48b72722d3960e79d54 | |
parent | 9d6c0b7f875ac24c284e355ef54f52ed41f8137e (diff) | |
download | uhd-7fad896c07fbdda4cf112e9e4999a5ab8f5484a5.tar.gz uhd-7fad896c07fbdda4cf112e9e4999a5ab8f5484a5.tar.bz2 uhd-7fad896c07fbdda4cf112e9e4999a5ab8f5484a5.zip |
usrp3: Added RX DSP support for heterodyne sampling
- rx_dsp_core: set_mux takes in a fe_connection obj
to determine IQ mapping and sampling mode parameters
- rx_dsp_core: Support a non-zero IF for downconversion
The current strategy applies a software DSP freq offset
which eats into the range of the CORDIC which is OK
because heterodyne assumes real-mode sampling
-rw-r--r-- | host/lib/usrp/b200/b200_impl.cpp | 2 | ||||
-rw-r--r-- | host/lib/usrp/cores/rx_dsp_core_3000.cpp | 54 | ||||
-rw-r--r-- | host/lib/usrp/cores/rx_dsp_core_3000.hpp | 3 | ||||
-rw-r--r-- | host/lib/usrp/e300/e300_io_impl.cpp | 2 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_io_impl.cpp | 2 |
5 files changed, 46 insertions, 17 deletions
diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index 565ce681a..bfb32b2c8 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -765,7 +765,7 @@ void b200_impl::setup_radio(const size_t dspno) perif.framer = rx_vita_core_3000::make(perif.ctrl, TOREG(SR_RX_CTRL)); perif.ddc = rx_dsp_core_3000::make(perif.ctrl, TOREG(SR_RX_DSP), true /*is_b200?*/); perif.ddc->set_link_rate(10e9/8); //whatever - perif.ddc->set_mux("IQ", false, dspno == 1 ? true : false, dspno == 1 ? true : false); + perif.ddc->set_mux(usrp::fe_connection_t(dspno == 1 ? "IbQb" : "IQ")); perif.ddc->set_freq(rx_dsp_core_3000::DEFAULT_CORDIC_FREQ); perif.deframer = tx_vita_core_3000::make_no_radio_buff(perif.ctrl, TOREG(SR_TX_CTRL)); perif.duc = tx_dsp_core_3000::make(perif.ctrl, TOREG(SR_TX_DSP)); diff --git a/host/lib/usrp/cores/rx_dsp_core_3000.cpp b/host/lib/usrp/cores/rx_dsp_core_3000.cpp index 0c11c5a12..eedbbef95 100644 --- a/host/lib/usrp/cores/rx_dsp_core_3000.cpp +++ b/host/lib/usrp/cores/rx_dsp_core_3000.cpp @@ -69,6 +69,7 @@ public: _scaling_adjustment = 1.0; _dsp_extra_scaling = 1.0; _tick_rate = 1.0; + _dsp_freq_offset = 0.0; } ~rx_dsp_core_3000_impl(void) @@ -79,17 +80,41 @@ public: ) } - void set_mux(const std::string &mode, const bool fe_swapped, const bool invert_i, const bool invert_q){ - static const uhd::dict<std::string, boost::uint32_t> mode_to_mux = boost::assign::map_list_of - ("IQ", 0) - ("QI", FLAG_DSP_RX_MUX_SWAP_IQ) - ("I", FLAG_DSP_RX_MUX_REAL_MODE) - ("Q", FLAG_DSP_RX_MUX_SWAP_IQ | FLAG_DSP_RX_MUX_REAL_MODE) - ; - _iface->poke32(REG_DSP_RX_MUX, mode_to_mux[mode] - | (fe_swapped ? FLAG_DSP_RX_MUX_SWAP_IQ : 0) - | (invert_i ? FLAG_DSP_RX_MUX_INVERT_I : 0) - | (invert_q ? FLAG_DSP_RX_MUX_INVERT_Q : 0)); + void set_mux(const uhd::usrp::fe_connection_t& fe_conn){ + boost::uint32_t reg_val = 0; + switch (fe_conn.get_sampling_mode()) { + case uhd::usrp::fe_connection_t::REAL: + case uhd::usrp::fe_connection_t::HETERODYNE: + reg_val = FLAG_DSP_RX_MUX_REAL_MODE; + break; + default: + reg_val = 0; + break; + } + + if (fe_conn.is_iq_swapped()) reg_val |= FLAG_DSP_RX_MUX_SWAP_IQ; + if (fe_conn.is_i_inverted()) reg_val |= FLAG_DSP_RX_MUX_INVERT_I; + if (fe_conn.is_q_inverted()) reg_val |= FLAG_DSP_RX_MUX_INVERT_Q; + + _iface->poke32(REG_DSP_RX_MUX, reg_val); + + if (fe_conn.get_sampling_mode() == uhd::usrp::fe_connection_t::HETERODYNE) { + //1. Remember the sign of the IF frequency. + // It will be discarded in the next step + int if_freq_sign = boost::math::sign(fe_conn.get_if_freq()); + //2. Map IF frequency to the range [0, _tick_rate) + double if_freq = std::abs(std::fmod(fe_conn.get_if_freq(), _tick_rate)); + //3. Map IF frequency to the range [-_tick_rate/2, _tick_rate/2) + // This is the aliased frequency + if (if_freq > (_tick_rate / 2.0)) { + if_freq -= _tick_rate; + } + //4. Set DSP offset to spin the signal in the opposite + // direction as the aliased frequency + _dsp_freq_offset = if_freq * (-if_freq_sign); + } else { + _dsp_freq_offset = 0.0; + } } void set_tick_rate(const double rate){ @@ -212,13 +237,15 @@ public: double set_freq(const double requested_freq){ double actual_freq; int32_t freq_word; - get_freq_and_freq_word(requested_freq, _tick_rate, actual_freq, freq_word); + get_freq_and_freq_word(requested_freq + _dsp_freq_offset, _tick_rate, actual_freq, freq_word); _iface->poke32(REG_DSP_RX_FREQ, boost::uint32_t(freq_word)); return actual_freq; } uhd::meta_range_t get_freq_range(void){ - return uhd::meta_range_t(-_tick_rate/2, +_tick_rate/2, _tick_rate/std::pow(2.0, 32)); + //Too keep the DSP range symmetric about 0, we use abs(_dsp_freq_offset) + const double offset = std::abs<double>(_dsp_freq_offset); + return uhd::meta_range_t(-(_tick_rate-offset)/2, +(_tick_rate-offset)/2, _tick_rate/std::pow(2.0, 32)); } void setup(const uhd::stream_args_t &stream_args){ @@ -274,6 +301,7 @@ private: const bool _is_b200; //TODO: Obsolete this when we switch to the new DDC on the B200 double _tick_rate, _link_rate; double _scaling_adjustment, _dsp_extra_scaling, _host_extra_scaling, _fxpt_scalar_correction; + double _dsp_freq_offset; }; rx_dsp_core_3000::sptr rx_dsp_core_3000::make(wb_iface::sptr iface, const size_t dsp_base, const bool is_b200 /* = false */) diff --git a/host/lib/usrp/cores/rx_dsp_core_3000.hpp b/host/lib/usrp/cores/rx_dsp_core_3000.hpp index 65801de1d..41b328357 100644 --- a/host/lib/usrp/cores/rx_dsp_core_3000.hpp +++ b/host/lib/usrp/cores/rx_dsp_core_3000.hpp @@ -24,6 +24,7 @@ #include <uhd/types/stream_cmd.hpp> #include <uhd/types/wb_iface.hpp> #include <uhd/property_tree.hpp> +#include <uhd/usrp/fe_connection.hpp> #include <boost/utility.hpp> #include <boost/shared_ptr.hpp> #include <string> @@ -43,7 +44,7 @@ public: const bool is_b200 = false //TODO: Obsolete this when we switch to the new DDC on the B200 ); - virtual void set_mux(const std::string &mode, const bool fe_swapped = false, const bool invert_i = false, const bool invert_q = false) = 0; + virtual void set_mux(const uhd::usrp::fe_connection_t& fe_conn) = 0; virtual void set_tick_rate(const double rate) = 0; diff --git a/host/lib/usrp/e300/e300_io_impl.cpp b/host/lib/usrp/e300/e300_io_impl.cpp index f9ca7b0b2..c84042e98 100644 --- a/host/lib/usrp/e300/e300_io_impl.cpp +++ b/host/lib/usrp/e300/e300_io_impl.cpp @@ -157,7 +157,7 @@ void e300_impl::_update_subdev_spec( const std::string conn = _tree->access<std::string>( mb_path / "dboards" / spec[i].db_name / ("rx_frontends") / spec[i].sd_name / "connection").get(); - _radio_perifs[i].ddc->set_mux(conn); + _radio_perifs[i].ddc->set_mux(usrp::fe_connection_t(conn)); _radio_perifs[i].rx_fe->set_mux(false); } } diff --git a/host/lib/usrp/x300/x300_io_impl.cpp b/host/lib/usrp/x300/x300_io_impl.cpp index 01cbc3ca7..a9fb5d830 100644 --- a/host/lib/usrp/x300/x300_io_impl.cpp +++ b/host/lib/usrp/x300/x300_io_impl.cpp @@ -111,7 +111,7 @@ void x300_impl::update_subdev_spec(const std::string &tx_rx, const size_t mb_i, //swap condition _mb[mb_i].radio_perifs[radio_idx].tx_fe->set_mux(conn); } else { - _mb[mb_i].radio_perifs[radio_idx].ddc->set_mux(conn); + _mb[mb_i].radio_perifs[radio_idx].ddc->set_mux(usrp::fe_connection_t(conn)); _mb[mb_i].radio_perifs[radio_idx].rx_fe->set_mux(false); } } |