diff options
Diffstat (limited to 'host/lib')
| -rw-r--r-- | host/lib/usrp/dboard/db_ubx.cpp | 18 | ||||
| -rw-r--r-- | host/lib/usrp/dboard/db_ubx.hpp | 57 | ||||
| -rw-r--r-- | host/lib/usrp/dboard/twinrx/twinrx_ctrl.cpp | 51 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_device_args.hpp | 7 | ||||
| -rw-r--r-- | host/lib/usrp/x300/x300_impl.cpp | 62 | 
5 files changed, 153 insertions, 42 deletions
diff --git a/host/lib/usrp/dboard/db_ubx.cpp b/host/lib/usrp/dboard/db_ubx.cpp index 8ac96a2fe..733a4b8e2 100644 --- a/host/lib/usrp/dboard/db_ubx.cpp +++ b/host/lib/usrp/dboard/db_ubx.cpp @@ -7,6 +7,7 @@  /***********************************************************************   * Included Files and Libraries   **********************************************************************/ +#include "db_ubx.hpp"  #include <uhd/types/device_addr.hpp>  #include <uhd/types/dict.hpp>  #include <uhd/types/direction.hpp> @@ -30,6 +31,7 @@  using namespace uhd;  using namespace uhd::usrp; +using namespace uhd::usrp::dboard::ubx;  /***********************************************************************   * UBX Data Structures @@ -134,22 +136,6 @@ enum spi_dest_t {   * UBX Constants   **********************************************************************/  #define fMHz (1000000.0) -static const dboard_id_t UBX_PROTO_V3_TX_ID(0x73); -static const dboard_id_t UBX_PROTO_V3_RX_ID(0x74); -static const dboard_id_t UBX_PROTO_V4_TX_ID(0x75); -static const dboard_id_t UBX_PROTO_V4_RX_ID(0x76); -static const dboard_id_t UBX_V1_40MHZ_TX_ID(0x77); -static const dboard_id_t UBX_V1_40MHZ_RX_ID(0x78); -static const dboard_id_t UBX_V1_160MHZ_TX_ID(0x79); -static const dboard_id_t UBX_V1_160MHZ_RX_ID(0x7A); -static const dboard_id_t UBX_V2_40MHZ_TX_ID(0x7B); -static const dboard_id_t UBX_V2_40MHZ_RX_ID(0x7C); -static const dboard_id_t UBX_V2_160MHZ_TX_ID(0x7D); -static const dboard_id_t UBX_V2_160MHZ_RX_ID(0x7E); -static const dboard_id_t UBX_LP_160MHZ_TX_ID(0x0200); -static const dboard_id_t UBX_LP_160MHZ_RX_ID(0x0201); -static const dboard_id_t UBX_TDD_160MHZ_TX_ID(0x0202); -static const dboard_id_t UBX_TDD_160MHZ_RX_ID(0x0203);  static const freq_range_t ubx_freq_range(10e6, 6.0e9);  static const gain_range_t ubx_tx_gain_range(0, 31.5, double(0.5));  static const gain_range_t ubx_rx_gain_range(0, 31.5, double(0.5)); diff --git a/host/lib/usrp/dboard/db_ubx.hpp b/host/lib/usrp/dboard/db_ubx.hpp new file mode 100644 index 000000000..246a89eb0 --- /dev/null +++ b/host/lib/usrp/dboard/db_ubx.hpp @@ -0,0 +1,57 @@ +// +// Copyright 2020 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#pragma once + +#include <uhd/usrp/dboard_base.hpp> + +using namespace uhd; +using namespace uhd::usrp; + +namespace uhd { namespace usrp { namespace dboard { namespace ubx { + +static const dboard_id_t UBX_PROTO_V3_TX_ID(0x73); +static const dboard_id_t UBX_PROTO_V3_RX_ID(0x74); +static const dboard_id_t UBX_PROTO_V4_TX_ID(0x75); +static const dboard_id_t UBX_PROTO_V4_RX_ID(0x76); +static const dboard_id_t UBX_V1_40MHZ_TX_ID(0x77); +static const dboard_id_t UBX_V1_40MHZ_RX_ID(0x78); +static const dboard_id_t UBX_V1_160MHZ_TX_ID(0x79); +static const dboard_id_t UBX_V1_160MHZ_RX_ID(0x7A); +static const dboard_id_t UBX_V2_40MHZ_TX_ID(0x7B); +static const dboard_id_t UBX_V2_40MHZ_RX_ID(0x7C); +static const dboard_id_t UBX_V2_160MHZ_TX_ID(0x7D); +static const dboard_id_t UBX_V2_160MHZ_RX_ID(0x7E); +static const dboard_id_t UBX_LP_160MHZ_TX_ID(0x0200); +static const dboard_id_t UBX_LP_160MHZ_RX_ID(0x0201); +static const dboard_id_t UBX_TDD_160MHZ_TX_ID(0x0202); +static const dboard_id_t UBX_TDD_160MHZ_RX_ID(0x0203); +static const std::vector<dboard_id_t> ubx_ids{UBX_PROTO_V3_TX_ID, +    UBX_PROTO_V4_TX_ID, +    UBX_V1_40MHZ_TX_ID, +    UBX_V1_160MHZ_TX_ID, +    UBX_V2_40MHZ_TX_ID, +    UBX_V2_160MHZ_TX_ID, +    UBX_LP_160MHZ_TX_ID, +    UBX_TDD_160MHZ_TX_ID, +    UBX_PROTO_V3_RX_ID, +    UBX_PROTO_V4_RX_ID, +    UBX_V1_40MHZ_RX_ID, +    UBX_V1_160MHZ_RX_ID, +    UBX_V2_40MHZ_RX_ID, +    UBX_V2_160MHZ_RX_ID, +    UBX_LP_160MHZ_RX_ID, +    UBX_TDD_160MHZ_RX_ID}; + +static UHD_INLINE double get_max_pfd_freq(dboard_id_t dboard_id) +{ +    if ((dboard_id == UBX_PROTO_V3_TX_ID) || (dboard_id == UBX_PROTO_V3_RX_ID)) { +        return 25e6; +    } +    return 50e6; +} + +}}}}; // namespace uhd::usrp::dboard::ubx diff --git a/host/lib/usrp/dboard/twinrx/twinrx_ctrl.cpp b/host/lib/usrp/dboard/twinrx/twinrx_ctrl.cpp index 3752a2e70..3686f4348 100644 --- a/host/lib/usrp/dboard/twinrx/twinrx_ctrl.cpp +++ b/host/lib/usrp/dboard/twinrx/twinrx_ctrl.cpp @@ -13,6 +13,7 @@  #include <uhdlib/usrp/common/adf535x.hpp>  #include <uhdlib/utils/narrow.hpp>  #include <chrono> +#include <cmath>  #include <thread>  using namespace uhd; @@ -29,10 +30,9 @@ inline uint32_t bool2bin(bool x)      return x ? 1 : 0;  } -const double TWINRX_DESIRED_REFERENCE_FREQ = 50e6; -const double TWINRX_REV_AB_PFD_FREQ        = 6.25e6; -const double TWINRX_REV_C_PFD_FREQ         = 12.5e6; -const double TWINRX_SPI_CLOCK_FREQ         = 3e6; +const double TWINRX_REV_AB_PFD_FREQ = 6.25e6; +const double TWINRX_REV_C_PFD_FREQ  = 12.5e6; +const double TWINRX_SPI_CLOCK_FREQ  = 3e6;  } // namespace  class twinrx_ctrl_impl : public twinrx_ctrl @@ -49,22 +49,29 @@ public:          _spi_config.divider            = uhd::narrow_cast<size_t>(std::ceil(              _db_iface->get_codec_rate(dboard_iface::UNIT_TX) / TWINRX_SPI_CLOCK_FREQ)); -        // Initialize dboard clocks -        bool found_rate = false; -        for (double rate : _db_iface->get_clock_rates(dboard_iface::UNIT_TX)) { -            found_rate |= -                uhd::math::frequencies_are_equal(rate, TWINRX_DESIRED_REFERENCE_FREQ); -        } -        for (double rate : _db_iface->get_clock_rates(dboard_iface::UNIT_RX)) { -            found_rate |= -                uhd::math::frequencies_are_equal(rate, TWINRX_DESIRED_REFERENCE_FREQ); -        } -        if (not found_rate) { -            throw uhd::runtime_error("TwinRX not supported on this motherboard"); +        // Daughterboard clock rates must be a multiple of the pfd frequency +        if (rx_id == twinrx::TWINRX_REV_C_ID) { +            if (fmod(_db_iface->get_clock_rate(dboard_iface::UNIT_RX), +                    TWINRX_REV_C_PFD_FREQ) +                != 0) { +                throw uhd::value_error( +                    str(boost::format( +                            "TwinRX clock rate %f is not a multiple of the pfd freq %f.") +                        % _db_iface->get_clock_rate(dboard_iface::UNIT_RX) +                        % TWINRX_REV_C_PFD_FREQ)); +            } +        } else { +            if (fmod(_db_iface->get_clock_rate(dboard_iface::UNIT_RX), +                    TWINRX_REV_AB_PFD_FREQ) +                != 0) { +                throw uhd::value_error( +                    str(boost::format( +                            "TwinRX clock rate %f is not a multiple of the pfd freq %f.") +                        % _db_iface->get_clock_rate(dboard_iface::UNIT_RX) +                        % TWINRX_REV_AB_PFD_FREQ)); +            }          } -        _db_iface->set_clock_rate(dboard_iface::UNIT_TX, TWINRX_DESIRED_REFERENCE_FREQ); -        _db_iface->set_clock_rate(dboard_iface::UNIT_RX, TWINRX_DESIRED_REFERENCE_FREQ); - +        // Initialize dboard clocks          _db_iface->set_clock_enabled(dboard_iface::UNIT_TX, true);          _db_iface->set_clock_enabled(dboard_iface::UNIT_RX, true); @@ -126,7 +133,8 @@ public:                  _lo1_iface[i]->set_pfd_freq(TWINRX_REV_AB_PFD_FREQ);              }              _lo1_iface[i]->set_output_power(adf535x_iface::OUTPUT_POWER_5DBM); -            _lo1_iface[i]->set_reference_freq(TWINRX_DESIRED_REFERENCE_FREQ); +            _lo1_iface[i]->set_reference_freq( +                _db_iface->get_clock_rate(dboard_iface::UNIT_TX));              _lo1_iface[i]->set_muxout_mode(adf535x_iface::MUXOUT_DLD);              _lo1_iface[i]->set_frequency(3e9, 1.0e3); @@ -137,7 +145,8 @@ public:                  });              _lo2_iface[i]->set_feedback_select(adf435x_iface::FB_SEL_DIVIDED);              _lo2_iface[i]->set_output_power(adf435x_iface::OUTPUT_POWER_5DBM); -            _lo2_iface[i]->set_reference_freq(TWINRX_DESIRED_REFERENCE_FREQ); +            _lo2_iface[i]->set_reference_freq( +                _db_iface->get_clock_rate(dboard_iface::UNIT_RX));              _lo2_iface[i]->set_muxout_mode(adf435x_iface::MUXOUT_DLD);              _lo2_iface[i]->set_tuning_mode(adf435x_iface::TUNING_MODE_LOW_SPUR);              _lo2_iface[i]->set_prescaler(adf435x_iface::PRESCALER_8_9); diff --git a/host/lib/usrp/x300/x300_device_args.hpp b/host/lib/usrp/x300/x300_device_args.hpp index 6c6680c4f..7e17c36ce 100644 --- a/host/lib/usrp/x300/x300_device_args.hpp +++ b/host/lib/usrp/x300/x300_device_args.hpp @@ -197,12 +197,11 @@ private:          if (dev_args.has_key(_dboard_clock_rate.key())) {              _dboard_clock_rate.parse(dev_args[_dboard_clock_rate.key()]);          } else { -            // Some daughterboards may require other rates, but this default -            // works best for all newer daughterboards (i.e. CBX, WBX, SBX, -            // UBX, and TwinRX). +            // This default clock rate works best for most daughterboards (i.e. DBSRX2, +            // WBX, SBX, CBX, and TwinRX).              if (_master_clock_rate.get() >= MIN_TICK_RATE                  && _master_clock_rate.get() <= MAX_TICK_RATE) { -                _dboard_clock_rate.set(_master_clock_rate.get() / 4); +                _dboard_clock_rate.set(_master_clock_rate.get() / 2);              } else {                  throw uhd::value_error("Can't infer daughterboard clock rate. Specify "                                         "dboard_clk_rate in the device args."); diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index a414fd0f1..fa8425fac 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -7,6 +7,7 @@  //  #include "x300_impl.hpp" +#include "../dboard/db_ubx.hpp"  #include "x300_claim.hpp"  #include "x300_eth_mgr.hpp"  #include "x300_mb_controller.hpp" @@ -15,6 +16,8 @@  #include "x300_mboard_type.hpp"  #include "x300_pcie_mgr.hpp"  #include <uhd/transport/if_addrs.hpp> +#include <uhd/usrp/dboard_eeprom.hpp> +#include <uhd/usrp/dboard_id.hpp>  #include <uhd/utils/log.hpp>  #include <uhd/utils/paths.hpp>  #include <uhd/utils/safe_call.hpp> @@ -141,6 +144,31 @@ device_addrs_t x300_find(const device_addr_t& hint_)  }  /*********************************************************************** + * Daughterboard detection before initialization in software + **********************************************************************/ +static std::vector<dboard_id_t> get_dboard_ids(uhd::i2c_iface& zpu_i2c) +{ +    std::vector<dboard_id_t> dboard_ids; +    // Read dboard ids from the EEPROM +    constexpr size_t BASE_ADDR      = 0x50; +    constexpr size_t RX_EEPROM_ADDR = 0x5; +    constexpr size_t TX_EEPROM_ADDR = 0x4; +    static const std::vector<size_t> DB_OFFSETS{0x0, 0x2}; +    static const std::vector<size_t> EEPROM_ADDRS{RX_EEPROM_ADDR, TX_EEPROM_ADDR}; +    for (size_t eeprom_addr : EEPROM_ADDRS) { +        for (size_t db_offset : DB_OFFSETS) { +            const size_t addr = eeprom_addr + db_offset; +            // Load EEPROM +            std::unordered_map<size_t, usrp::dboard_eeprom_t> db_eeproms; +            db_eeproms[addr].load(zpu_i2c, BASE_ADDR | addr); +            uint16_t dboard_id = db_eeproms[addr].id.to_uint16(); +            dboard_ids.push_back(static_cast<dboard_id_t>(dboard_id)); +        } +    } +    return dboard_ids; +} + +/***********************************************************************   * Make   **********************************************************************/  static device::sptr x300_make(const device_addr_t& device_addr) @@ -331,13 +359,45 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t& dev_addr)      // create clock control objects      ////////////////////////////////////////////////////////////////////      UHD_LOGGER_DEBUG("X300") << "Setting up RF frontend clocking..."; + +    // The default daughterboard clock rate may have to be overridden. This is due to the +    // limitation on X300 devices where both daughterboards must use the same clock rate. +    // The daughterboards that require specific clock rates are UBX and TwinRX. TwinRX +    // requires a clock rate of 100 MHz for the best RF performance. UBX daughterboards +    // require a clock rate of no more than the max pfd frequency to maintain phase +    // synchronization. If there is no UBX, the default daughterboard clock rate is half +    // of the master clock rate for X300. +    const double x300_dboard_clock_rate = [this, dev_addr, mb]() -> double { +        // Do not override use-specified dboard clock rates +        if (dev_addr.has_key("dboard_clock_rate")) { +            return mb.args.get_dboard_clock_rate(); +        } +        const double mcr         = mb.args.get_master_clock_rate(); +        double dboard_clock_rate = mb.args.get_dboard_clock_rate(); +        // Check for UBX daughterboards +        std::vector<dboard_id_t> dboard_ids = get_dboard_ids(*mb.zpu_i2c); +        for (dboard_id_t dboard_id : dboard_ids) { +            if (std::find( +                    dboard::ubx::ubx_ids.begin(), dboard::ubx::ubx_ids.end(), dboard_id) +                != dboard::ubx::ubx_ids.end()) { +                double ubx_clock_rate = mcr; +                for (int i = 2; ubx_clock_rate > dboard::ubx::get_max_pfd_freq(dboard_id); +                     i++) { +                    ubx_clock_rate = mcr / i; +                } +                dboard_clock_rate = std::min(dboard_clock_rate, ubx_clock_rate); +            } +        } +        return dboard_clock_rate; +    }(); +      // Initialize clock control registers.      // NOTE: This does not configure the LMK yet.      mb.clock = x300_clock_ctrl::make(mb.zpu_spi,          1 /*slaveno*/,          mb.hw_rev,          mb.args.get_master_clock_rate(), -        mb.args.get_dboard_clock_rate(), +        x300_dboard_clock_rate,          mb.args.get_system_ref_rate());      ////////////////////////////////////////////////////////////////////  | 
