diff options
author | Michael West <michael.west@ettus.com> | 2018-04-10 12:25:29 -0700 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2018-07-17 09:35:31 -0700 |
commit | b75ca6cd9143a730d827c3b5e353a9086a79d210 (patch) | |
tree | 78e9e503184be80722372289d2871c37936a7515 /host | |
parent | 08855405d6511774f65d2b7c7a976202e215bb7d (diff) | |
download | uhd-b75ca6cd9143a730d827c3b5e353a9086a79d210.tar.gz uhd-b75ca6cd9143a730d827c3b5e353a9086a79d210.tar.bz2 uhd-b75ca6cd9143a730d827c3b5e353a9086a79d210.zip |
UBX: Add support for phase synchronization at LTE clock rates
Diffstat (limited to 'host')
-rw-r--r-- | host/lib/usrp/dboard/db_ubx.cpp | 30 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_impl.cpp | 17 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_regs.hpp | 12 |
3 files changed, 46 insertions, 13 deletions
diff --git a/host/lib/usrp/dboard/db_ubx.cpp b/host/lib/usrp/dboard/db_ubx.cpp index c65b5f470..6f2670ec4 100644 --- a/host/lib/usrp/dboard/db_ubx.cpp +++ b/host/lib/usrp/dboard/db_ubx.cpp @@ -488,7 +488,7 @@ public: .set(freq_range_t(bw, bw)); get_tx_subtree()->create<int64_t>("sync_delay") .add_coerced_subscriber(boost::bind(&ubx_xcvr::set_sync_delay, this, true, _1)) - .set(-8); + .set(0); //////////////////////////////////////////////////////////////////// // Register RX properties @@ -524,7 +524,7 @@ public: .set(freq_range_t(bw, bw)); get_rx_subtree()->create<int64_t>("sync_delay") .add_coerced_subscriber(boost::bind(&ubx_xcvr::set_sync_delay, this, false, _1)) - .set(-8); + .set(0); } virtual ~ubx_xcvr(void) @@ -669,20 +669,26 @@ private: // Phase synchronization for MAX2871 requires that the sync signal // is at least 4/(N*PFD_freq) + 2.6ns before the rising edge of the // ref clock and 4/(N*PFD_freq) after the rising edge of the ref clock. - // Since the ref clock, the radio clock, and the VITA time are all - // synchronized to the 10 MHz clock, use the time spec to move - // the rising edge of the sync signal away from the 10 MHz edge, - // which will move it away from the ref clock edge by the same amount. // Since the MAX2871 requires the ref freq and PFD freq be the same // for phase synchronization, the dboard clock rate is used as the PFD - // freq and the worst case value of 20 is used for the N value to - // calculate the offset. - double pfd_freq = _iface->get_clock_rate(dir == TX_DIRECTION ? dboard_iface::UNIT_TX : dboard_iface::UNIT_RX); - double tick_rate = _iface->get_codec_rate(dir == TX_DIRECTION ? dboard_iface::UNIT_TX : dboard_iface::UNIT_RX); + // freq and the sync signal is aligned to the falling edge to meet + // the setup and hold requirements. Since the command time ticks + // at the radio clock rate, this only works if the radio clock is + // an even multiple of the dboard clock, the dboard clock is a + // multiple of the system reference, and the device time has been + // set on a PPS edge sampled by the system reference clock. + + const double pfd_freq = _iface->get_clock_rate(dir == TX_DIRECTION ? dboard_iface::UNIT_TX : dboard_iface::UNIT_RX); + const double tick_rate = _iface->get_codec_rate(dir == TX_DIRECTION ? dboard_iface::UNIT_TX : dboard_iface::UNIT_RX); + const int64_t ticks_per_pfd_cycle = (int64_t)(tick_rate / pfd_freq); + + // Convert time to ticks int64_t ticks = cmd_time.to_ticks(tick_rate); - ticks -= ticks % (int64_t)(tick_rate / 10e6); // align to 10 MHz clock + // Align time to next falling edge of dboard clock + ticks += ticks_per_pfd_cycle - (ticks % ticks_per_pfd_cycle) + (ticks_per_pfd_cycle / 2); + // Add any user specified delay ticks += dir == TX_DIRECTION ? _tx_sync_delay : _rx_sync_delay; - ticks += std::ceil(tick_rate*4/(20*pfd_freq)); // add required offset (using worst case N value of 20) + // Set the command time cmd_time = uhd::time_spec_t::from_ticks(ticks, tick_rate); _iface->set_command_time(cmd_time); diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index 4a8c12e04..051242e0a 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -888,12 +888,27 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr) //Initialize clock control registers. NOTE: This does not configure the LMK yet. const double requested_mcr = dev_addr.cast<double>("master_clock_rate", X300_DEFAULT_TICK_RATE); + //Some daughterboards may require other rates, but these defaults + //work best for all newer daughterboards (i.e. CBX, WBX, SBX, UBX, + //and TwinRX). + double default_dboard_clk_rate = requested_mcr; + if (math::frequencies_are_equal(requested_mcr, 200e6)) { + default_dboard_clk_rate = 50e6; + } else if (math::frequencies_are_equal(requested_mcr, 184.32e6)) { + default_dboard_clk_rate = 46.08e6; + } else if (math::frequencies_are_equal(requested_mcr, 120e6)) { + default_dboard_clk_rate = 40e6; + } mb.clock = x300_clock_ctrl::make(mb.zpu_spi, 1 /*slaveno*/, mb.hw_rev, requested_mcr, - dev_addr.cast<double>("dboard_clock_rate", requested_mcr / 4), + dev_addr.cast<double>("dboard_clock_rate", default_dboard_clk_rate), dev_addr.cast<double>("system_ref_rate", X300_DEFAULT_SYSREF_RATE)); + mb.fw_regmap->ref_freq_reg.write( + fw_regmap_t::ref_freq_reg_t::REF_FREQ, + uint32_t(dev_addr.cast<double>("system_ref_rate", + X300_DEFAULT_SYSREF_RATE))); //Initialize clock source to use internal reference and generate //a valid radio clock. This may change after configuration is done. diff --git a/host/lib/usrp/x300/x300_regs.hpp b/host/lib/usrp/x300/x300_regs.hpp index 68b405dfe..b54c5c2bb 100644 --- a/host/lib/usrp/x300/x300_regs.hpp +++ b/host/lib/usrp/x300/x300_regs.hpp @@ -30,6 +30,7 @@ static const int ZPU_SR_LEDS = 00; static const int ZPU_SR_SW_RST = 01; static const int ZPU_SR_CLOCK_CTRL = 02; static const int ZPU_SR_XB_LOCAL = 03; +static const int ZPU_SR_REF_FREQ = 04; static const int ZPU_SR_SPI = 32; static const int ZPU_SR_ETHINT0 = 40; static const int ZPU_SR_ETHINT1 = 56; @@ -204,9 +205,20 @@ namespace uhd { namespace usrp { namespace x300 { clk_status_reg_t(): uhd::soft_reg32_ro_t(SR_ADDR(SET0_BASE, ZPU_RB_CLK_STATUS)) {} } clock_status_reg; + class ref_freq_reg_t : public uhd::soft_reg32_wo_t { + public: + UHD_DEFINE_SOFT_REG_FIELD(REF_FREQ, /*width*/ 32, /*shift*/ 0); + + ref_freq_reg_t(): uhd::soft_reg32_wo_t(SR_ADDR(SET0_BASE, ZPU_SR_REF_FREQ)) { + //Initial values + set(REF_FREQ, 10000000); + } + } ref_freq_reg; + fw_regmap_t() : soft_regmap_t("fw_regmap") { add_to_map(clock_ctrl_reg, "clock_ctrl_reg", PUBLIC); add_to_map(clock_status_reg, "clock_status_reg", PUBLIC); + add_to_map(ref_freq_reg, "ref_freq_reg", PUBLIC); } }; |