diff options
author | Martin Braun <martin.braun@ettus.com> | 2016-08-01 18:17:41 -0700 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2016-08-09 12:42:52 -0700 |
commit | 3bf4b000f7d9a7f4af82c21753556ede7e8df6e3 (patch) | |
tree | 2228d7eb58c4d83d91192cb9b6a908e4e49f6317 /host/lib/usrp/cores | |
parent | c5b076173e2d866f3ee99c113a37183c5ec20f0b (diff) | |
download | uhd-3bf4b000f7d9a7f4af82c21753556ede7e8df6e3.tar.gz uhd-3bf4b000f7d9a7f4af82c21753556ede7e8df6e3.tar.bz2 uhd-3bf4b000f7d9a7f4af82c21753556ede7e8df6e3.zip |
Merging RFNoC support for X310
Diffstat (limited to 'host/lib/usrp/cores')
-rw-r--r-- | host/lib/usrp/cores/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/lib/usrp/cores/dma_fifo_core_3000.cpp | 4 | ||||
-rw-r--r-- | host/lib/usrp/cores/rx_frontend_core_3000.cpp | 186 | ||||
-rw-r--r-- | host/lib/usrp/cores/rx_frontend_core_3000.hpp | 69 | ||||
-rw-r--r-- | host/lib/usrp/cores/rx_vita_core_3000.cpp | 4 |
5 files changed, 263 insertions, 1 deletions
diff --git a/host/lib/usrp/cores/CMakeLists.txt b/host/lib/usrp/cores/CMakeLists.txt index 404fc6137..1e16dd39e 100644 --- a/host/lib/usrp/cores/CMakeLists.txt +++ b/host/lib/usrp/cores/CMakeLists.txt @@ -30,6 +30,7 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/rx_dsp_core_200.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tx_dsp_core_200.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rx_frontend_core_200.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/rx_frontend_core_3000.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tx_frontend_core_200.cpp ${CMAKE_CURRENT_SOURCE_DIR}/user_settings_core_200.cpp ${CMAKE_CURRENT_SOURCE_DIR}/rx_vita_core_3000.cpp diff --git a/host/lib/usrp/cores/dma_fifo_core_3000.cpp b/host/lib/usrp/cores/dma_fifo_core_3000.cpp index 1a9d5dd5c..5df28f7c2 100644 --- a/host/lib/usrp/cores/dma_fifo_core_3000.cpp +++ b/host/lib/usrp/cores/dma_fifo_core_3000.cpp @@ -240,6 +240,10 @@ public: flush(); } + virtual ~dma_fifo_core_3000_impl() + { + } + virtual void flush() { //Clear the FIFO and hold it in that state _fifo_ctrl_reg.write(fifo_ctrl_reg_t::CLEAR_FIFO, 1); diff --git a/host/lib/usrp/cores/rx_frontend_core_3000.cpp b/host/lib/usrp/cores/rx_frontend_core_3000.cpp new file mode 100644 index 000000000..23197cf5a --- /dev/null +++ b/host/lib/usrp/cores/rx_frontend_core_3000.cpp @@ -0,0 +1,186 @@ +// +// Copyright 2011-2012,2014-2016 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include "rx_frontend_core_3000.hpp" +#include "dsp_core_utils.hpp" +#include <boost/math/special_functions/round.hpp> +#include <boost/assign/list_of.hpp> +#include <boost/bind.hpp> +#include <uhd/types/dict.hpp> + +using namespace uhd; + +#define REG_RX_FE_MAG_CORRECTION (_base + 0 ) //18 bits +#define REG_RX_FE_PHASE_CORRECTION (_base + 4 ) //18 bits +#define REG_RX_FE_OFFSET_I (_base + 8 ) //18 bits +#define REG_RX_FE_OFFSET_Q (_base + 12) //18 bits +#define REG_RX_FE_MAPPING (_base + 16) +#define REG_RX_FE_HET_CORDIC_PHASE (_base + 20) + +#define FLAG_DSP_RX_MAPPING_SWAP_IQ (1 << 0) +#define FLAG_DSP_RX_MAPPING_REAL_MODE (1 << 1) +#define FLAG_DSP_RX_MAPPING_INVERT_Q (1 << 2) +#define FLAG_DSP_RX_MAPPING_INVERT_I (1 << 3) +#define FLAG_DSP_RX_MAPPING_REAL_DECIM (1 << 4) +//#define FLAG_DSP_RX_MAPPING_RESERVED (1 << 5) +//#define FLAG_DSP_RX_MAPPING_RESERVED (1 << 6) +#define FLAG_DSP_RX_MAPPING_BYPASS_ALL (1 << 7) + +#define OFFSET_FIXED (1ul << 31) +#define OFFSET_SET (1ul << 30) +#define FLAG_MASK (OFFSET_FIXED | OFFSET_SET) + +using namespace uhd::usrp; + +static boost::uint32_t fs_to_bits(const double num, const size_t bits){ + return boost::int32_t(boost::math::round(num * (1 << (bits-1)))); +} + +rx_frontend_core_3000::~rx_frontend_core_3000(void){ + /* NOP */ +} + +const std::complex<double> rx_frontend_core_3000::DEFAULT_DC_OFFSET_VALUE = std::complex<double>(0.0, 0.0); +const bool rx_frontend_core_3000::DEFAULT_DC_OFFSET_ENABLE = true; +const std::complex<double> rx_frontend_core_3000::DEFAULT_IQ_BALANCE_VALUE = std::complex<double>(0.0, 0.0); + +class rx_frontend_core_3000_impl : public rx_frontend_core_3000{ +public: + rx_frontend_core_3000_impl(wb_iface::sptr iface, const size_t base): + _i_dc_off(0), _q_dc_off(0), + _adc_rate(0.0), + _fe_conn(fe_connection_t("IQ")), + _iface(iface), _base(base) + { + //NOP + } + + void set_adc_rate(const double rate) { + _adc_rate = rate; + } + + void bypass_all(bool bypass_en) { + if (bypass_en) { + _iface->poke32(REG_RX_FE_MAPPING, FLAG_DSP_RX_MAPPING_BYPASS_ALL); + } else { + set_fe_connection(_fe_conn); + } + } + + void set_fe_connection(const fe_connection_t& fe_conn) { + boost::uint32_t mapping_reg_val = 0; + switch (fe_conn.get_sampling_mode()) { + case fe_connection_t::REAL: + case fe_connection_t::HETERODYNE: + mapping_reg_val = FLAG_DSP_RX_MAPPING_REAL_MODE|FLAG_DSP_RX_MAPPING_REAL_DECIM; + break; + default: + mapping_reg_val = 0; + break; + } + + if (fe_conn.is_iq_swapped()) mapping_reg_val |= FLAG_DSP_RX_MAPPING_SWAP_IQ; + if (fe_conn.is_i_inverted()) mapping_reg_val |= FLAG_DSP_RX_MAPPING_INVERT_I; + if (fe_conn.is_q_inverted()) mapping_reg_val |= FLAG_DSP_RX_MAPPING_INVERT_Q; + + _iface->poke32(REG_RX_FE_MAPPING, mapping_reg_val); + + UHD_ASSERT_THROW(_adc_rate!=0.0) + double cordic_freq = 0.0, actual_cordic_freq = 0.0; + if (fe_conn.get_sampling_mode() == 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, _adc_rate) + double if_freq = std::abs(std::fmod(fe_conn.get_if_freq(), _adc_rate)); + //3. Map IF frequency to the range [-_adc_rate/2, _adc_rate/2) + // This is the aliased frequency + if (if_freq > (_adc_rate / 2.0)) { + if_freq -= _adc_rate; + } + //4. Set DSP offset to spin the signal in the opposite + // direction as the aliased frequency + cordic_freq = if_freq * (-if_freq_sign); + } + int32_t freq_word; + get_freq_and_freq_word(cordic_freq, _adc_rate, actual_cordic_freq, freq_word); + _iface->poke32(REG_RX_FE_HET_CORDIC_PHASE, boost::uint32_t(freq_word)); + + _fe_conn = fe_conn; + } + + void set_dc_offset_auto(const bool enb) { + _set_dc_offset(enb ? 0 : OFFSET_FIXED); + } + + std::complex<double> set_dc_offset(const std::complex<double> &off) { + static const double scaler = double(1ul << 29); + _i_dc_off = boost::math::iround(off.real()*scaler); + _q_dc_off = boost::math::iround(off.imag()*scaler); + + _set_dc_offset(OFFSET_SET | OFFSET_FIXED); + + return std::complex<double>(_i_dc_off/scaler, _q_dc_off/scaler); + } + + void _set_dc_offset(const boost::uint32_t flags) { + _iface->poke32(REG_RX_FE_OFFSET_I, flags | (_i_dc_off & ~FLAG_MASK)); + _iface->poke32(REG_RX_FE_OFFSET_Q, flags | (_q_dc_off & ~FLAG_MASK)); + } + + void set_iq_balance(const std::complex<double> &cor) { + _iface->poke32(REG_RX_FE_MAG_CORRECTION, fs_to_bits(cor.real(), 18)); + _iface->poke32(REG_RX_FE_PHASE_CORRECTION, fs_to_bits(cor.imag(), 18)); + } + + void populate_subtree(uhd::property_tree::sptr subtree) { + subtree->create<std::complex<double> >("dc_offset/value") + .set(DEFAULT_DC_OFFSET_VALUE) + .set_coercer(boost::bind(&rx_frontend_core_3000::set_dc_offset, this, _1)) + ; + subtree->create<bool>("dc_offset/enable") + .set(DEFAULT_DC_OFFSET_ENABLE) + .add_coerced_subscriber(boost::bind(&rx_frontend_core_3000::set_dc_offset_auto, this, _1)) + ; + subtree->create<std::complex<double> >("iq_balance/value") + .set(DEFAULT_IQ_BALANCE_VALUE) + .add_coerced_subscriber(boost::bind(&rx_frontend_core_3000::set_iq_balance, this, _1)) + ; + } + + double get_output_rate() { + switch (_fe_conn.get_sampling_mode()) { + case fe_connection_t::REAL: + case fe_connection_t::HETERODYNE: + return _adc_rate / 2; + default: + return _adc_rate; + } + return _adc_rate; + } + +private: + boost::int32_t _i_dc_off, _q_dc_off; + double _adc_rate; + fe_connection_t _fe_conn; + wb_iface::sptr _iface; + const size_t _base; +}; + +rx_frontend_core_3000::sptr rx_frontend_core_3000::make(wb_iface::sptr iface, const size_t base){ + return sptr(new rx_frontend_core_3000_impl(iface, base)); +} diff --git a/host/lib/usrp/cores/rx_frontend_core_3000.hpp b/host/lib/usrp/cores/rx_frontend_core_3000.hpp new file mode 100644 index 000000000..baa58331e --- /dev/null +++ b/host/lib/usrp/cores/rx_frontend_core_3000.hpp @@ -0,0 +1,69 @@ +// +// Copyright 2011,2014-2016 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_LIBUHD_USRP_TX_FRONTEND_CORE_3000_HPP +#define INCLUDED_LIBUHD_USRP_TX_FRONTEND_CORE_3000_HPP + +#include <uhd/config.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 <complex> +#include <string> + +class rx_frontend_core_3000 : boost::noncopyable{ +public: + static const std::complex<double> DEFAULT_DC_OFFSET_VALUE; + static const bool DEFAULT_DC_OFFSET_ENABLE; + static const std::complex<double> DEFAULT_IQ_BALANCE_VALUE; + + typedef boost::shared_ptr<rx_frontend_core_3000> sptr; + + virtual ~rx_frontend_core_3000(void) = 0; + + static sptr make(uhd::wb_iface::sptr iface, const size_t base); + + /*! Set the input sampling rate (i.e. ADC rate) + */ + virtual void set_adc_rate(const double rate) = 0; + + virtual void bypass_all(bool bypass_en) = 0; + + virtual void set_fe_connection(const uhd::usrp::fe_connection_t& fe_conn) = 0; + + virtual void set_dc_offset_auto(const bool enb) = 0; + + virtual std::complex<double> set_dc_offset(const std::complex<double> &off) = 0; + + virtual void set_iq_balance(const std::complex<double> &cor) = 0; + + virtual void populate_subtree(uhd::property_tree::sptr subtree) = 0; + + /*! Return the sampling rate at the output + * + * In real mode, the frontend core will decimate the sampling rate by a + * factor of 2. + * + * \returns RX sampling rate + */ + virtual double get_output_rate(void) = 0; + +}; + +#endif /* INCLUDED_LIBUHD_USRP_TX_FRONTEND_CORE_3000_HPP */ diff --git a/host/lib/usrp/cores/rx_vita_core_3000.cpp b/host/lib/usrp/cores/rx_vita_core_3000.cpp index 52121837e..54c57c2d5 100644 --- a/host/lib/usrp/cores/rx_vita_core_3000.cpp +++ b/host/lib/usrp/cores/rx_vita_core_3000.cpp @@ -82,7 +82,9 @@ struct rx_vita_core_3000_impl : rx_vita_core_3000 void clear(void) { - this->configure_flow_control(0); //disable fc + // FC should never be disabled, this will actually become + // impossible in the future + //this->configure_flow_control(0); //disable fc } void set_nsamps_per_packet(const size_t nsamps) |