aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/x300
diff options
context:
space:
mode:
authorBen Hilburn <ben.hilburn@ettus.com>2014-03-15 20:43:51 -0700
committerBen Hilburn <ben.hilburn@ettus.com>2014-03-15 20:43:51 -0700
commit4726c0c0958c776bccdf9898384e335013c7e811 (patch)
tree08c179bc422238013574108b56b5a29d73280cd9 /host/lib/usrp/x300
parent4022711d4ffc1b05780e5e4c4bd2bb176fb41c95 (diff)
parent9126069560de0a462f58596055dad15b35693dce (diff)
downloaduhd-4726c0c0958c776bccdf9898384e335013c7e811.tar.gz
uhd-4726c0c0958c776bccdf9898384e335013c7e811.tar.bz2
uhd-4726c0c0958c776bccdf9898384e335013c7e811.zip
Merge clock and PPS fixes.
Diffstat (limited to 'host/lib/usrp/x300')
-rw-r--r--host/lib/usrp/x300/x300_clock_ctrl.cpp4
-rw-r--r--host/lib/usrp/x300/x300_clock_ctrl.hpp6
-rw-r--r--host/lib/usrp/x300/x300_fw_common.h2
-rw-r--r--host/lib/usrp/x300/x300_impl.cpp145
-rw-r--r--host/lib/usrp/x300/x300_impl.hpp12
-rw-r--r--host/lib/usrp/x300/x300_regs.hpp14
6 files changed, 130 insertions, 53 deletions
diff --git a/host/lib/usrp/x300/x300_clock_ctrl.cpp b/host/lib/usrp/x300/x300_clock_ctrl.cpp
index a986928a7..a8b30a0ab 100644
--- a/host/lib/usrp/x300/x300_clock_ctrl.cpp
+++ b/host/lib/usrp/x300/x300_clock_ctrl.cpp
@@ -48,6 +48,10 @@ x300_clock_ctrl_impl(uhd::spi_iface::sptr spiface,
set_master_clock_rate(master_clock_rate);
}
+void reset_clocks() {
+ set_master_clock_rate(_master_clock_rate);
+}
+
void sync_clocks(void) {
//soft sync:
//put the sync IO into output mode - FPGA must be input
diff --git a/host/lib/usrp/x300/x300_clock_ctrl.hpp b/host/lib/usrp/x300/x300_clock_ctrl.hpp
index 0e3caf900..e9904d25c 100644
--- a/host/lib/usrp/x300/x300_clock_ctrl.hpp
+++ b/host/lib/usrp/x300/x300_clock_ctrl.hpp
@@ -78,6 +78,12 @@ public:
* \param true = on, false = off
*/
virtual void set_ref_out(const bool) = 0;
+
+ /*! Reset the clocks.
+ * Should be called if the reference clock changes
+ * to reduce the time required to achieve a lock.
+ */
+ virtual void reset_clocks(void) = 0;
};
#endif /* INCLUDED_X300_CLOCK_CTRL_HPP */
diff --git a/host/lib/usrp/x300/x300_fw_common.h b/host/lib/usrp/x300/x300_fw_common.h
index c470e9bff..632391644 100644
--- a/host/lib/usrp/x300/x300_fw_common.h
+++ b/host/lib/usrp/x300/x300_fw_common.h
@@ -31,7 +31,7 @@ extern "C" {
#define X300_FW_COMPAT_MAJOR 3
#define X300_FW_COMPAT_MINOR 0
-#define X300_FPGA_COMPAT_MAJOR 3
+#define X300_FPGA_COMPAT_MAJOR 4
//shared memory sections - in between the stack and the program space
#define X300_FW_SHMEM_BASE 0x6000
diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp
index 48b9e9bd4..22f607baa 100644
--- a/host/lib/usrp/x300/x300_impl.cpp
+++ b/host/lib/usrp/x300/x300_impl.cpp
@@ -577,16 +577,6 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)
////////////////////////////////////////////////////////////////////
UHD_MSG(status) << "Setup RF frontend clocking..." << std::endl;
- // Init shadow and clock source; the device comes up with it's internal
- // clock source before locking to something else (if requested).
- mb.clock_control_regs__clock_source = 0;
- mb.clock_control_regs__pps_select = 0;
- mb.clock_control_regs__pps_out_enb = 0;
- mb.clock_control_regs__tcxo_enb = 1;
- mb.clock_control_regs__gpsdo_pwr = 1;
- this->update_clock_source(mb, "internal");
- this->update_clock_control(mb);
-
size_t hw_rev = 0;
if(mb_eeprom.has_key("revision") and not mb_eeprom["revision"].empty()) {
try {
@@ -603,12 +593,24 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)
hw_rev = X300_REV("D");
}
+ //Initialize clock control with internal references and GPSDO power on.
+ mb.clock_control_regs_clock_source = ZPU_SR_CLOCK_CTRL_CLK_SRC_INTERNAL;
+ mb.clock_control_regs_pps_select = ZPU_SR_CLOCK_CTRL_PPS_SRC_INTERNAL;
+ mb.clock_control_regs_pps_out_enb = 0;
+ mb.clock_control_regs_tcxo_enb = 1;
+ mb.clock_control_regs_gpsdo_pwr = 1;
+ this->update_clock_control(mb);
+
+ //Create clock control
mb.clock = x300_clock_ctrl::make(mb.zpu_spi,
1 /*slaveno*/,
hw_rev,
dev_addr.cast<double>("master_clock_rate", X300_DEFAULT_TICK_RATE),
dev_addr.cast<double>("system_ref_rate", X300_DEFAULT_SYSREF_RATE));
+ //wait for reference clock to lock
+ wait_for_ref_locked(mb.zpu_ctrl, 1.0);
+
////////////////////////////////////////////////////////////////////
// create clock properties
////////////////////////////////////////////////////////////////////
@@ -768,30 +770,29 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)
_tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(rx_fe_spec);
_tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(tx_fe_spec);
- //GPS installed: use external ref, time, and init time spec
- if (mb.gps and mb.gps->gps_detected())
- {
- UHD_MSG(status) << "Setting references to the internal GPSDO" << std::endl;
- _tree->access<std::string>(mb_path / "time_source" / "value").set("gpsdo");
- _tree->access<std::string>(mb_path / "clock_source" / "value").set("gpsdo");
- UHD_MSG(status) << "Initializing time to the internal GPSDO" << std::endl;
- const time_t tp = time_t(mb.gps->get_sensor("gps_time").to_int()+1);
- _tree->access<time_spec_t>(mb_path / "time" / "pps").set(time_spec_t(tp));
- }
- else
- {
- _tree->access<std::string>(mb_path / "time_source" / "value").set("external");
+ UHD_MSG(status) << "Initializing clock and PPS references..." << std::endl;
+ try {
+ //First, try external source
_tree->access<std::string>(mb_path / "clock_source" / "value").set("external");
- boost::this_thread::sleep(boost::posix_time::milliseconds(100));
- if (this->get_ref_locked(mb.zpu_ctrl).to_bool())
- {
- UHD_MSG(status) << "Setting references to external sources" << std::endl;
- }
- else
+ _tree->access<std::string>(mb_path / "time_source" / "value").set("external");
+ UHD_MSG(status) << "References initialized to external sources" << std::endl;
+ } catch (uhd::exception::runtime_error &e) {
+ //No external source detected - set to the GPSDO if installed
+ if (mb.gps and mb.gps->gps_detected())
{
- UHD_MSG(status) << "Setting references to internal sources" << std::endl;
- _tree->access<std::string>(mb_path / "time_source" / "value").set("internal");
+ _tree->access<std::string>(mb_path / "clock_source" / "value").set("gpsdo");
+ _tree->access<std::string>(mb_path / "time_source" / "value").set("gpsdo");
+ UHD_MSG(status) << "References initialized to GPSDO sources" << std::endl;
+ UHD_MSG(status) << "Initializing time to the GPSDO time" << std::endl;
+ const time_t tp = time_t(mb.gps->get_sensor("gps_time").to_int()+1);
+ _tree->access<time_spec_t>(mb_path / "time" / "pps").set(time_spec_t(tp));
+ //wait for time to be set (timeout after 1 second)
+ for (int i = 0; i < 10 && tp != (_tree->access<time_spec_t>(mb_path / "time" / "pps").get()).get_full_secs(); i++)
+ boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+ } else {
_tree->access<std::string>(mb_path / "clock_source" / "value").set("internal");
+ _tree->access<std::string>(mb_path / "time_source" / "value").set("internal");
+ UHD_MSG(status) << "References initialized to internal sources" << std::endl;
}
}
}
@@ -1290,60 +1291,110 @@ void x300_impl::register_loopback_self_test(wb_iface::sptr iface)
void x300_impl::set_time_source_out(mboard_members_t &mb, const bool enb)
{
- mb.clock_control_regs__pps_out_enb = enb? 1 : 0;
+ mb.clock_control_regs_pps_out_enb = enb? 1 : 0;
this->update_clock_control(mb);
}
void x300_impl::update_clock_control(mboard_members_t &mb)
{
- const size_t reg = mb.clock_control_regs__clock_source
- | (mb.clock_control_regs__pps_select << 2)
- | (mb.clock_control_regs__pps_out_enb << 3)
- | (mb.clock_control_regs__tcxo_enb << 4)
- | (mb.clock_control_regs__gpsdo_pwr << 5)
+ const size_t reg = mb.clock_control_regs_clock_source
+ | (mb.clock_control_regs_pps_select << 2)
+ | (mb.clock_control_regs_pps_out_enb << 4)
+ | (mb.clock_control_regs_tcxo_enb << 5)
+ | (mb.clock_control_regs_gpsdo_pwr << 6)
;
mb.zpu_ctrl->poke32(SR_ADDR(SET0_BASE, ZPU_SR_CLOCK_CTRL), reg);
}
void x300_impl::update_clock_source(mboard_members_t &mb, const std::string &source)
{
- mb.clock_control_regs__clock_source = 0;
+ mb.clock_control_regs_clock_source = 0;
+ mb.clock_control_regs_tcxo_enb = 0;
if (source == "internal") {
- mb.clock_control_regs__clock_source = 0x2;
-
- mb.clock_control_regs__tcxo_enb = (source == "internal")? 1 : 0;
+ mb.clock_control_regs_clock_source = ZPU_SR_CLOCK_CTRL_CLK_SRC_INTERNAL;
+ mb.clock_control_regs_tcxo_enb = 1;
} else if (source == "external") {
- mb.clock_control_regs__clock_source = 0x0;
+ mb.clock_control_regs_clock_source = ZPU_SR_CLOCK_CTRL_CLK_SRC_EXTERNAL;
} else if (source == "gpsdo") {
- mb.clock_control_regs__clock_source = 0x3;
+ mb.clock_control_regs_clock_source = ZPU_SR_CLOCK_CTRL_CLK_SRC_GPSDO;
} else {
throw uhd::key_error("update_clock_source: unknown source: " + source);
}
this->update_clock_control(mb);
+
+ //reset the clock control
+ //without this, the lock time is multiple seconds and the poll below will fail
+ mb.clock->reset_clocks();
+
+ //wait for lock
+ try {
+ wait_for_ref_locked(mb.zpu_ctrl, 1.0);
+ } catch (uhd::runtime_error &e) {
+ //failed to lock on reference
+ throw uhd::runtime_error(
+ (boost::format("Error setting the clock source to %s: %s Please check the clock and try again.")
+ % source % e.what()).str());
+ }
}
void x300_impl::update_time_source(mboard_members_t &mb, const std::string &source)
{
if (source == "internal") {
- // no action needed
+ mb.clock_control_regs_pps_select = ZPU_SR_CLOCK_CTRL_PPS_SRC_INTERNAL;
} else if (source == "external") {
- mb.clock_control_regs__pps_select = (source == "external")? 1 : 0;
+ mb.clock_control_regs_pps_select = ZPU_SR_CLOCK_CTRL_PPS_SRC_EXTERNAL;
} else if (source == "gpsdo") {
- // no action needed
+ mb.clock_control_regs_pps_select = ZPU_SR_CLOCK_CTRL_PPS_SRC_GPSDO;
} else {
throw uhd::key_error("update_time_source: unknown source: " + source);
}
this->update_clock_control(mb);
+
+ //check for valid pps
+ if (!is_pps_present(mb.zpu_ctrl))
+ {
+ throw uhd::runtime_error((boost::format("The %d PPS was not detected. Please check the PPS source and try again.") % source).str());
+ }
+}
+
+void x300_impl::wait_for_ref_locked(wb_iface::sptr ctrl, double timeout)
+{
+ boost::system_time timeout_time = boost::get_system_time() + boost::posix_time::milliseconds(timeout * 1000.0);
+ do
+ {
+ if (get_ref_locked(ctrl).to_bool())
+ return;
+ boost::this_thread::sleep(boost::posix_time::milliseconds(1));
+ } while (boost::get_system_time() < timeout_time);
+
+ //failed to lock on reference
+ throw uhd::runtime_error("The reference clock failed to lock.");
}
sensor_value_t x300_impl::get_ref_locked(wb_iface::sptr ctrl)
{
- const bool lock = (ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_CLK_STATUS)) & (1 << 2)) != 0;
+ uint32_t clk_status = ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_CLK_STATUS));
+ const bool lock = ((clk_status & ZPU_RB_CLK_STATUS_LMK_LOCK) != 0);
return sensor_value_t("Ref", lock, "locked", "unlocked");
}
+bool x300_impl::is_pps_present(wb_iface::sptr ctrl)
+{
+ // The ZPU_RB_CLK_STATUS_PPS_DETECT bit toggles with each rising edge of the PPS.
+ // We monitor it for up to 1.5 seconds looking for it to toggle.
+ uint32_t pps_detect = ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_CLK_STATUS)) & ZPU_RB_CLK_STATUS_PPS_DETECT;
+ for (int i = 0; i < 15; i++)
+ {
+ boost::this_thread::sleep(boost::posix_time::milliseconds(100));
+ uint32_t clk_status = ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_CLK_STATUS));
+ if (pps_detect != (clk_status & ZPU_RB_CLK_STATUS_PPS_DETECT))
+ return true;
+ }
+ return false;
+}
+
void x300_impl::set_db_eeprom(i2c_iface::sptr i2c, const size_t addr, const uhd::usrp::dboard_eeprom_t &db_eeprom)
{
db_eeprom.store(*i2c, addr);
diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp
index 1e159ef38..8f4ae8264 100644
--- a/host/lib/usrp/x300/x300_impl.hpp
+++ b/host/lib/usrp/x300/x300_impl.hpp
@@ -205,11 +205,11 @@ private:
gpio_core_200::sptr fp_gpio;
//clock control register bits
- int clock_control_regs__clock_source;
- int clock_control_regs__pps_select;
- int clock_control_regs__pps_out_enb;
- int clock_control_regs__tcxo_enb;
- int clock_control_regs__gpsdo_pwr;
+ int clock_control_regs_clock_source;
+ int clock_control_regs_pps_select;
+ int clock_control_regs_pps_out_enb;
+ int clock_control_regs_tcxo_enb;
+ int clock_control_regs_gpsdo_pwr;
//which FPGA image is loaded
std::string loaded_fpga_image;
@@ -323,6 +323,8 @@ private:
void update_time_source(mboard_members_t&, const std::string &);
uhd::sensor_value_t get_ref_locked(uhd::wb_iface::sptr);
+ void wait_for_ref_locked(uhd::wb_iface::sptr, double timeout = 0.0);
+ bool is_pps_present(uhd::wb_iface::sptr);
void set_db_eeprom(uhd::i2c_iface::sptr i2c, const size_t, const uhd::usrp::dboard_eeprom_t &);
void set_mb_eeprom(uhd::i2c_iface::sptr i2c, const uhd::usrp::mboard_eeprom_t &);
diff --git a/host/lib/usrp/x300/x300_regs.hpp b/host/lib/usrp/x300/x300_regs.hpp
index e4ae76a38..fb1786deb 100644
--- a/host/lib/usrp/x300/x300_regs.hpp
+++ b/host/lib/usrp/x300/x300_regs.hpp
@@ -68,12 +68,26 @@ localparam ZPU_SR_SPI = 32;
localparam ZPU_SR_ETHINT0 = 40;
localparam ZPU_SR_ETHINT1 = 56;
+//clock controls
+#define ZPU_SR_CLOCK_CTRL_CLK_SRC_EXTERNAL 0x00
+#define ZPU_SR_CLOCK_CTRL_CLK_SRC_INTERNAL 0x02
+#define ZPU_SR_CLOCK_CTRL_CLK_SRC_GPSDO 0x03
+#define ZPU_SR_CLOCK_CTRL_PPS_SRC_EXTERNAL 0x00
+#define ZPU_SR_CLOCK_CTRL_PPS_SRC_INTERNAL 0x02
+#define ZPU_SR_CLOCK_CTRL_PPS_SRC_GPSDO 0x03
+
localparam ZPU_RB_SPI = 2;
localparam ZPU_RB_CLK_STATUS = 3;
localparam ZPU_RB_COMPAT_NUM = 6;
localparam ZPU_RB_ETH_TYPE0 = 4;
localparam ZPU_RB_ETH_TYPE1 = 5;
+//clock status
+#define ZPU_RB_CLK_STATUS_LMK_STATUS (0x3 << 0)
+#define ZPU_RB_CLK_STATUS_LMK_LOCK (0x1 << 2)
+#define ZPU_RB_CLK_STATUS_LMK_HOLDOVER (0x1 << 3)
+#define ZPU_RB_CLK_STATUS_PPS_DETECT (0x1 << 4)
+
//spi slaves on radio
#define DB_DAC_SEN (1 << 7)
#define DB_ADC_SEN (1 << 6)