diff options
author | Ashish Chaudhari <ashish@ettus.com> | 2015-01-22 14:15:34 -0800 |
---|---|---|
committer | Ashish Chaudhari <ashish@ettus.com> | 2015-01-22 14:15:34 -0800 |
commit | 1f44f06abad589d2244eecfcbca1618b4fcb3ffd (patch) | |
tree | ace8223ec045ab7d53a383d5e4805aa5deb00a80 | |
parent | 9c3cdb6ee831f164e5a8734a71ad3cd5543719ac (diff) | |
download | uhd-1f44f06abad589d2244eecfcbca1618b4fcb3ffd.tar.gz uhd-1f44f06abad589d2244eecfcbca1618b4fcb3ffd.tar.bz2 uhd-1f44f06abad589d2244eecfcbca1618b4fcb3ffd.zip |
e300: UHD support for refclk disciplining using PPS.
- Only supported value for clk_source is internal
- time_source automatically changes the disciplining pulse source
- Added ref_locked sensor
-rw-r--r-- | host/docs/usrp_e3x0.dox | 7 | ||||
-rw-r--r-- | host/lib/usrp/e300/e300_impl.cpp | 23 | ||||
-rw-r--r-- | host/lib/usrp/e300/e300_network.cpp | 2 | ||||
-rw-r--r-- | host/lib/usrp/e300/e300_sensor_manager.cpp | 69 | ||||
-rw-r--r-- | host/lib/usrp/e300/e300_sensor_manager.hpp | 6 |
5 files changed, 87 insertions, 20 deletions
diff --git a/host/docs/usrp_e3x0.dox b/host/docs/usrp_e3x0.dox index 7fab73f20..8f94ea64d 100644 --- a/host/docs/usrp_e3x0.dox +++ b/host/docs/usrp_e3x0.dox @@ -7,7 +7,6 @@ - Hardware Capabilities: Integrated RF frontend (70 MHz - 6 GHz) - External PPS reference input - - External 10 MHz reference input - Configurable clock rate - Internal GPIO connector with UHD API control - 2 USB 2.0 Host ports @@ -132,7 +131,7 @@ which should return 'arm-oe-linux-gnueabi'. -# Setup your environment as described in \ref e3x0_sdk_usage -# Type the following in the build directory (assuming a build in host/build): - $ cmake -DCMAKE_TOOLCHAIN_FILE=<youruhdsrc>/host/cmake/Toolchains/oe-sdk_cross.cmake -DENABLE_E300 .. + $ cmake -DCMAKE_TOOLCHAIN_FILE=<youruhdsrc>/host/cmake/Toolchains/oe-sdk_cross.cmake -DENABLE_E300=ON .. $ make \subsubsection e3x0_sdk_usage_gnuradio Building GNU Radio @@ -276,6 +275,8 @@ You may need to change the USRP's IP address for several reasons: \subsection e3x0_hw_pps PPS - Pulse Per Second Using a PPS signal for timestamp synchronization requires a square wave signal with the following a 5Vpp amplitude. +An external PPS can be used to discipline the internal reference clock. This feature is automatically +enabled with the time source is set to "external". To test the PPS input, you can use the following tool from the UHD examples: @@ -288,6 +289,8 @@ To test the PPS input, you can use the following tool from the UHD examples: Your USRP-E Series device comes with an internal GPS. In order to get a lock on a satellite an external GPS antenna is required. +The PPS from the internal GPS can be used to discipline the internal reference clock. This feature is automatically +enabled with the time source is set to "gpsdo". The device provides a 3.3V supply voltage to an external antenna connected to the *GPS* port of your device. Note that this supply voltage is turned off in order to safe power upon destruction of the software object. diff --git a/host/lib/usrp/e300/e300_impl.cpp b/host/lib/usrp/e300/e300_impl.cpp index d04794947..c74ce9412 100644 --- a/host/lib/usrp/e300/e300_impl.cpp +++ b/host/lib/usrp/e300/e300_impl.cpp @@ -381,7 +381,7 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr) } catch (std::exception &e) { UHD_MSG(error) << "An error occured making GPSDO control: " << e.what() << std::endl; } - _sensor_manager = e300_sensor_manager::make_local(_gps); + _sensor_manager = e300_sensor_manager::make_local(_gps, _global_regs); } UHD_MSG(status) << (_sensor_manager->get_gps_found() ? "found" : "not found") << std::endl; @@ -493,14 +493,15 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr) .subscribe(boost::bind(&time_core_3000::set_time_next_pps, _radio_perifs[1].time64, _1)); //setup time source props _tree->create<std::string>(mb_path / "time_source" / "value") - .subscribe(boost::bind(&e300_impl::_update_time_source, this, _1)); - static const std::vector<std::string> time_sources = boost::assign::list_of("none")("external")("gpsdo"); + .subscribe(boost::bind(&e300_impl::_update_time_source, this, _1)) + .set("internal"); + static const std::vector<std::string> time_sources = boost::assign::list_of("none")("internal")("external")("gpsdo"); _tree->create<std::vector<std::string> >(mb_path / "time_source" / "options").set(time_sources); //setup reference source props _tree->create<std::string>(mb_path / "clock_source" / "value") - .subscribe(boost::bind(&e300_impl::_update_clock_source, this, _1)); - static const std::vector<std::string> clock_sources = boost::assign::list_of("internal"); - // not implemented ("external")("gpsdo"); + .subscribe(boost::bind(&e300_impl::_update_clock_source, this, _1)) + .set("internal"); + static const std::vector<std::string> clock_sources = boost::assign::list_of("internal"); //external,gpsdo not supported _tree->create<std::vector<std::string> >(mb_path / "clock_source" / "options").set(clock_sources); //////////////////////////////////////////////////////////////////// @@ -895,14 +896,20 @@ e300_impl::both_xports_t e300_impl::_make_transport( return xports; } -void e300_impl::_update_clock_source(const std::string &) +void e300_impl::_update_clock_source(const std::string &source) { + if (source != "internal") { + throw uhd::value_error(boost::str( + boost::format("Clock source option not supported: %s. The only value supported is \"internal\". " \ + "To discipline the internal oscillator, set the appropriate time source.") % source + )); + } } void e300_impl::_update_antenna_sel(const size_t &which, const std::string &ant) { if (ant != "TX/RX" and ant != "RX2") - throw uhd::value_error("e300: unknown RX antenna option: " + ant); + throw uhd::value_error("Unknown RX antenna option: " + ant); _radio_perifs[which].ant_rx2 = (ant == "RX2"); this->_update_atrs(); } diff --git a/host/lib/usrp/e300/e300_network.cpp b/host/lib/usrp/e300/e300_network.cpp index 6d36d8681..a21c508fe 100644 --- a/host/lib/usrp/e300/e300_network.cpp +++ b/host/lib/usrp/e300/e300_network.cpp @@ -622,7 +622,7 @@ network_server_impl::network_server_impl(const uhd::device_addr_t &device_addr) // This is horrible ... why do I have to sleep here? boost::this_thread::sleep(boost::posix_time::milliseconds(100)); _sensor_manager = e300_sensor_manager::make_local( - gps::ublox::ubx::control::make("/dev/ttyPS1", 9600)); + gps::ublox::ubx::control::make("/dev/ttyPS1", 9600), _global_regs); } }}} // namespace diff --git a/host/lib/usrp/e300/e300_sensor_manager.cpp b/host/lib/usrp/e300/e300_sensor_manager.cpp index 5e65b8fd3..95f31742b 100644 --- a/host/lib/usrp/e300/e300_sensor_manager.cpp +++ b/host/lib/usrp/e300/e300_sensor_manager.cpp @@ -38,7 +38,7 @@ public: std::vector<std::string> get_sensors() { - return boost::assign::list_of("temp")("gps_locked")("gps_time"); + return boost::assign::list_of("temp")("gps_locked")("gps_time")("ref_locked"); } uhd::sensor_value_t get_sensor(const std::string &key) @@ -49,6 +49,8 @@ public: return get_gps_lock(); else if (key == "gps_time") return get_gps_time(); + else if (key == "ref_locked") + return get_ref_lock(); else throw uhd::lookup_error( str(boost::format("Invalid sensor %s requested.") % key)); @@ -194,6 +196,40 @@ public: return sensor_value_t("GPS lock status", static_cast<bool>(uhd::ntohx(transaction.value)), "locked", "unlocked"); } + uhd::sensor_value_t get_ref_lock(void) + { + boost::mutex::scoped_lock(_mutex); + sensor_transaction_t transaction; + transaction.which = uhd::htonx<boost::uint32_t>(REF_LOCK); + { + uhd::transport::managed_send_buffer::sptr buff + = _xport->get_send_buff(1.0); + if (not buff or buff->size() < sizeof(transaction)) { + throw uhd::runtime_error("sensor proxy send timeout"); + } + std::memcpy( + buff->cast<void *>(), + &transaction, + sizeof(transaction)); + buff->commit(sizeof(transaction)); + } + { + uhd::transport::managed_recv_buffer::sptr buff + = _xport->get_recv_buff(1.0); + + if (not buff or buff->size() < sizeof(transaction)) + throw uhd::runtime_error("sensor proxy recv timeout"); + + std::memcpy( + &transaction, + buff->cast<const void *>(), + sizeof(transaction)); + } + UHD_ASSERT_THROW(uhd::ntohx<boost::uint32_t>(transaction.which) == REF_LOCK); + // TODO: Use proper serialization here ... + return sensor_value_t("Ref", static_cast<bool>(uhd::ntohx(transaction.value)), "locked", "unlocked"); + } + private: uhd::transport::zero_copy_if::sptr _xport; boost::mutex _mutex; @@ -219,13 +255,14 @@ static const std::string E300_TEMP_SYSFS = "iio:device0"; class e300_sensor_local : public e300_sensor_manager { public: - e300_sensor_local(uhd::gps_ctrl::sptr gps_ctrl) : _gps_ctrl(gps_ctrl) + e300_sensor_local(uhd::gps_ctrl::sptr gps_ctrl, global_regs::sptr global_regs) : + _gps_ctrl(gps_ctrl), _global_regs(global_regs) { } std::vector<std::string> get_sensors() { - return boost::assign::list_of("temp")("gps_locked")("gps_time"); + return boost::assign::list_of("temp")("gps_locked")("gps_time")("ref_locked"); } uhd::sensor_value_t get_sensor(const std::string &key) @@ -236,6 +273,8 @@ public: return get_gps_lock(); else if (key == "gps_time") return get_gps_time(); + else if (key == "ref_locked") + return get_ref_lock(); else throw uhd::lookup_error( str(boost::format("Invalid sensor %s requested.") % key)); @@ -267,22 +306,38 @@ public: return _gps_ctrl->get_sensor("gps_time"); } + uhd::sensor_value_t get_ref_lock(void) + { + //PPSLOOP_LOCKED_MASK is asserted in the following cases: + //- (Time source = GPS or External) AND (Loop is locked and is in fine adj mode) + //- Time source is Internal + static const boost::uint32_t PPSLOOP_LOCKED_MASK = 0x04; + static const boost::uint32_t REFPLL_LOCKED_MASK = 0x20; + + const boost::uint32_t status = + _global_regs->peek32(global_regs::RB32_CORE_MISC); + bool ref_locked = (status & PPSLOOP_LOCKED_MASK) && (status & REFPLL_LOCKED_MASK); + + return sensor_value_t("Ref", ref_locked, "locked", "unlocked"); + } + private: - gps_ctrl::sptr _gps_ctrl; + gps_ctrl::sptr _gps_ctrl; + global_regs::sptr _global_regs; }; }}} using namespace uhd::usrp::e300; e300_sensor_manager::sptr e300_sensor_manager::make_local( - uhd::gps_ctrl::sptr gps_ctrl) + uhd::gps_ctrl::sptr gps_ctrl, global_regs::sptr global_regs) { - return sptr(new e300_sensor_local(gps_ctrl)); + return sptr(new e300_sensor_local(gps_ctrl, global_regs)); } #else using namespace uhd::usrp::e300; e300_sensor_manager::sptr e300_sensor_manager::make_local( - uhd::gps_ctrl::sptr gps_ctrl) + uhd::gps_ctrl::sptr, global_regs::sptr) { throw uhd::assertion_error("e300_sensor_manager::make_local() !E300_NATIVE"); } diff --git a/host/lib/usrp/e300/e300_sensor_manager.hpp b/host/lib/usrp/e300/e300_sensor_manager.hpp index 503a7bb63..9c060b19a 100644 --- a/host/lib/usrp/e300/e300_sensor_manager.hpp +++ b/host/lib/usrp/e300/e300_sensor_manager.hpp @@ -22,6 +22,7 @@ #include <uhd/types/sensors.hpp> #include <uhd/utils/byteswap.hpp> #include <uhd/usrp/gps_ctrl.hpp> +#include "e300_global_regs.hpp" #ifndef INCLUDED_E300_SENSOR_MANAGER_HPP #define INCLUDED_E300_SENSOR_MANAGER_HPP @@ -39,7 +40,7 @@ struct sensor_transaction_t { enum sensor {ZYNQ_TEMP=0, GPS_FOUND=1, GPS_TIME=2, - GPS_LOCK=3}; + GPS_LOCK=3, REF_LOCK=4}; class e300_sensor_manager : boost::noncopyable { @@ -53,9 +54,10 @@ public: virtual uhd::sensor_value_t get_mb_temp(void) = 0; virtual uhd::sensor_value_t get_gps_lock(void) = 0; virtual uhd::sensor_value_t get_gps_time(void) = 0; + virtual uhd::sensor_value_t get_ref_lock(void) = 0; static sptr make_proxy(uhd::transport::zero_copy_if::sptr xport); - static sptr make_local(uhd::gps_ctrl::sptr gps_ctrl); + static sptr make_local(uhd::gps_ctrl::sptr gps_ctrl, global_regs::sptr global_regs); // Note: This is a hack static boost::uint32_t pack_float_in_uint32_t(const float &v) |