diff options
-rw-r--r-- | host/docs/coding.rst | 4 | ||||
-rw-r--r-- | host/docs/gpsdo.rst | 18 | ||||
-rw-r--r-- | host/docs/index.rst | 1 | ||||
-rw-r--r-- | host/docs/sync.rst | 13 | ||||
-rw-r--r-- | host/docs/usrp2.rst | 8 | ||||
-rw-r--r-- | host/examples/tx_timed_samples.cpp | 4 | ||||
-rw-r--r-- | host/lib/types/time_spec.cpp | 47 | ||||
-rw-r--r-- | host/lib/usrp/b100/b100_impl.cpp | 51 | ||||
-rw-r--r-- | host/lib/usrp/b100/io_impl.cpp | 5 | ||||
-rw-r--r-- | host/tests/time_spec_test.cpp | 25 |
10 files changed, 121 insertions, 55 deletions
diff --git a/host/docs/coding.rst b/host/docs/coding.rst index d5304c1c5..7400e0b4b 100644 --- a/host/docs/coding.rst +++ b/host/docs/coding.rst @@ -14,8 +14,8 @@ A device is an abstraction for hardware that is connected to the host system. For a USRP, this means that the motherboard and everything on it would be considered to be a "device". The device API provides ways to: -* Discover devices that are physical connected to the host system. -* Create a device object for a particular physical device identified by address. +* Discover devices that are physically connected to the host system. +* Create a device object for a particular device identified by address. * Register a device driver into the discovery and factory sub-system. * Streaming samples with metadata into and out of the device. * Set and get properties on the device object. diff --git a/host/docs/gpsdo.rst b/host/docs/gpsdo.rst index a0f2d67da..5680e0699 100644 --- a/host/docs/gpsdo.rst +++ b/host/docs/gpsdo.rst @@ -11,11 +11,17 @@ to the Jackson Labs Firefly-1A device unless noted otherwise. ------------------------------------------------------------------------ Specifications ------------------------------------------------------------------------ -Receiver type: 50 channel with WAAS, EGNOS, MSAS -10MHz ADEV: 1e-11 over >24h -1PPS RMS jitter: <50ns 1-sigma -Holdover: <11us over 3h -Phase noise: 1Hz: -80dBc/Hz, 10Hz: -110dBc/Hz, 100Hz: -135dBc/Hz, 1kHz: -145dBc/Hz, 10kHz: <-145dBc/Hz +* Receiver type: 50 channel with WAAS, EGNOS, MSAS +* 10MHz ADEV: 1e-11 over >24h +* 1PPS RMS jitter: <50ns 1-sigma +* Holdover: <11us over 3h +* Phase noise: + + * **1Hz:** -80dBc/Hz + * **10Hz:** -110dBc/Hz + * **100Hz:** -135dBc/Hz + * **1kHz:** -145dBc/Hz + * **10kHz:** <-145dBc/Hz ------------------------------------------------------------------------ Installation @@ -35,6 +41,7 @@ To configure the USRP to communicate with the GPSDO, use the usrp_burn_mb_eeprom utility: :: + $ cd <install-path>/share/uhd/utils $ ./usrp_burn_mb_eeprom --key=gpsdo --val=internal @@ -53,6 +60,7 @@ GPS data is obtained through the mboard_sensors interface. To retrieve the current GPS time, use the "gps_time" sensor: :: + usrp->get_mboard_sensor("gps_time"); The returned value will be the current epoch time, in seconds since diff --git a/host/docs/index.rst b/host/docs/index.rst index b4ebdad6c..f2dca50bf 100644 --- a/host/docs/index.rst +++ b/host/docs/index.rst @@ -29,6 +29,7 @@ Application Notes * `Daughterboard Application Notes <./dboards.html>`_ * `Transport Application Notes <./transport.html>`_ * `Synchronization Application Notes <./sync.html>`_ +* `Internal GPSDO Application Notes <./gpsdo.html>`_ ^^^^^^^^^^^^^^^^^^^^^ API Documentation diff --git a/host/docs/sync.rst b/host/docs/sync.rst index fe37a66dd..fb9f7a1df 100644 --- a/host/docs/sync.rst +++ b/host/docs/sync.rst @@ -105,8 +105,17 @@ and the user can also parse this string to determine GPS time: Method 3 - internal GPSDO ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ USRPs with internal GPSDOs properly configured will automatically -configure themselves to set the VITA time to current UTC time. See the -GPSDO application note for more details. +configure themselves to set the VITA time to current UTC time. +See the `GPSDO Application Notes <./gpsdo.html>`_ for more details. + +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Method 4 - MIMO cable +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +A USRP can synchronize its time to another USRP via the MIMO cable. +Unlike the other methods, this does not use a real "pulse per second". +Rather, the USRP sends an encoded time message over the MIMO cable. +The slave device will automatically synchronize to the time on the master device. +See the `MIMO Cable Application Notes <./usrp2.html#using-the-mimo-cable>`_ for more detail. ------------------------------------------------------------------------ Synchronizing channel phase diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst index 025cdd198..b3238d801 100644 --- a/host/docs/usrp2.rst +++ b/host/docs/usrp2.rst @@ -44,7 +44,6 @@ Use the card burner tool (windows) <path_to_python.exe> <install-path>/share/uhd/utils/usrp2_card_burner_gui.py - ------------------------------------------------------------------------ Load the images onto the on-board flash (USRP-N Series only) ------------------------------------------------------------------------ @@ -53,12 +52,17 @@ to update or change the firmware and FPGA images. When updating images, always burn both the FPGA and firmware images before power cycling. This ensures that when the device reboots, it has a compatible set of images to boot into. +**Note:** +Different hardware revisions require different FPGA images. +Determine the revision number from the sticker on the rear of the chassis. +Use this number to select the correct FPGA image for your device. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use the net burner tool (unix) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: - sudo <install-path>/share/uhd/utils/usrp_n2xx_net_burner_gui.py + <install-path>/share/uhd/utils/usrp_n2xx_net_burner_gui.py -- OR -- diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp index 858de83d2..1c222d414 100644 --- a/host/examples/tx_timed_samples.cpp +++ b/host/examples/tx_timed_samples.cpp @@ -84,7 +84,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ md.time_spec = uhd::time_spec_t(seconds_in_future); //the first call to send() will block this many seconds before sending: - double timeout = seconds_in_future + 0.1; //timeout (delay before transmit + padding) + const double timeout = seconds_in_future + 0.1; //timeout (delay before transmit + padding) size_t num_acc_samps = 0; //number of accumulated samples while(num_acc_samps < total_num_samps){ @@ -117,7 +117,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ uhd::async_metadata_t async_md; bool got_async_burst_ack = false; //loop through all messages for the ACK packet (may have underflow messages in queue) - while (not got_async_burst_ack and usrp->get_device()->recv_async_msg(async_md, seconds_in_future)){ + while (not got_async_burst_ack and usrp->get_device()->recv_async_msg(async_md, timeout)){ got_async_burst_ack = (async_md.event_code == uhd::async_metadata_t::EVENT_CODE_BURST_ACK); } std::cout << (got_async_burst_ack? "success" : "fail") << std::endl; diff --git a/host/lib/types/time_spec.cpp b/host/lib/types/time_spec.cpp index a785332c2..e019f1ccd 100644 --- a/host/lib/types/time_spec.cpp +++ b/host/lib/types/time_spec.cpp @@ -83,25 +83,26 @@ time_spec_t time_spec_t::get_system_time(void){ /*********************************************************************** * Time spec constructors **********************************************************************/ -time_spec_t::time_spec_t(double secs): - _full_secs(0), - _frac_secs(secs) -{ - /* NOP */ +#define time_spec_init(full, frac) { \ + _full_secs = full + time_t(frac); \ + _frac_secs = frac - time_t(frac); \ + if (_frac_secs < 0) {\ + _full_secs -= 1; \ + _frac_secs += 1; \ + } \ } -time_spec_t::time_spec_t(time_t full_secs, double frac_secs): - _full_secs(full_secs), - _frac_secs(frac_secs) -{ - /* NOP */ +time_spec_t::time_spec_t(double secs){ + time_spec_init(0, secs); } -time_spec_t::time_spec_t(time_t full_secs, long tick_count, double tick_rate): - _full_secs(full_secs), - _frac_secs(tick_count/tick_rate) -{ - /* NOP */ +time_spec_t::time_spec_t(time_t full_secs, double frac_secs){ + time_spec_init(full_secs, frac_secs); +} + +time_spec_t::time_spec_t(time_t full_secs, long tick_count, double tick_rate){ + const double frac_secs = tick_count/tick_rate; + time_spec_init(full_secs, frac_secs); } /*********************************************************************** @@ -116,25 +117,29 @@ double time_spec_t::get_real_secs(void) const{ } time_t time_spec_t::get_full_secs(void) const{ - return this->_full_secs + time_t(this->_frac_secs); + return this->_full_secs; } double time_spec_t::get_frac_secs(void) const{ - return this->_frac_secs - time_t(this->_frac_secs); + return this->_frac_secs; } /*********************************************************************** * Time spec math overloads **********************************************************************/ time_spec_t &time_spec_t::operator+=(const time_spec_t &rhs){ - this->_full_secs += rhs.get_full_secs(); - this->_frac_secs += rhs.get_frac_secs(); + time_spec_init( + this->_full_secs + rhs.get_full_secs(), + this->_frac_secs + rhs.get_frac_secs() + ); return *this; } time_spec_t &time_spec_t::operator-=(const time_spec_t &rhs){ - this->_full_secs -= rhs.get_full_secs(); - this->_frac_secs -= rhs.get_frac_secs(); + time_spec_init( + this->_full_secs - rhs.get_full_secs(), + this->_frac_secs - rhs.get_frac_secs() + ); return *this; } diff --git a/host/lib/usrp/b100/b100_impl.cpp b/host/lib/usrp/b100/b100_impl.cpp index ea9c91c50..04be45b5d 100644 --- a/host/lib/usrp/b100/b100_impl.cpp +++ b/host/lib/usrp/b100/b100_impl.cpp @@ -158,7 +158,7 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ } UHD_ASSERT_THROW(handle.get() != NULL); //better be found - //create control objects and a data transport + //create control objects usb_control::sptr fx2_transport = usb_control::make(handle); _fx2_ctrl = fx2_ctrl::make(fx2_transport); this->check_fw_compat(); //check after making fx2 @@ -166,21 +166,6 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ _clock_ctrl = b100_clock_ctrl::make(_fx2_ctrl, device_addr.cast<double>("master_clock_rate", B100_DEFAULT_TICK_RATE)); _fx2_ctrl->usrp_load_fpga(b100_fpga_image); - device_addr_t data_xport_args; - data_xport_args["recv_frame_size"] = device_addr.get("recv_frame_size", "16384"); - data_xport_args["num_recv_frames"] = device_addr.get("num_recv_frames", "16"); - data_xport_args["send_frame_size"] = device_addr.get("send_frame_size", "16384"); - data_xport_args["num_send_frames"] = device_addr.get("num_send_frames", "16"); - - _data_transport = usb_zero_copy::make_wrapper( - usb_zero_copy::make( - handle, // identifier - 6, // IN endpoint - 2, // OUT endpoint - data_xport_args // param hints - ) - ); - //create the control transport device_addr_t ctrl_xport_args; ctrl_xport_args["recv_frame_size"] = boost::lexical_cast<std::string>(CTRL_PACKET_LENGTH); @@ -201,10 +186,44 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ _fpga_ctrl = b100_ctrl::make(_ctrl_transport); this->enable_gpif(true); //TODO best place to put this? this->check_fpga_compat(); //check after making control + + //////////////////////////////////////////////////////////////////// + // Reset buffers in data path + //////////////////////////////////////////////////////////////////// + _fpga_ctrl->poke32(B100_REG_GLOBAL_RESET, 0); + _fpga_ctrl->poke32(B100_REG_CLEAR_RX, 0); + _fpga_ctrl->poke32(B100_REG_CLEAR_TX, 0); + this->reset_gpif(6); + this->reset_gpif(2); + + //////////////////////////////////////////////////////////////////// + // Initialize peripherals after reset + //////////////////////////////////////////////////////////////////// _fpga_i2c_ctrl = i2c_core_100::make(_fpga_ctrl, B100_REG_SLAVE(3)); _fpga_spi_ctrl = spi_core_100::make(_fpga_ctrl, B100_REG_SLAVE(2)); //////////////////////////////////////////////////////////////////// + // Create data transport + // This happens after FPGA ctrl instantiated so any junk that might + // be in the FPGAs buffers doesn't get pulled into the transport + // before being cleared. + //////////////////////////////////////////////////////////////////// + device_addr_t data_xport_args; + data_xport_args["recv_frame_size"] = device_addr.get("recv_frame_size", "16384"); + data_xport_args["num_recv_frames"] = device_addr.get("num_recv_frames", "16"); + data_xport_args["send_frame_size"] = device_addr.get("send_frame_size", "16384"); + data_xport_args["num_send_frames"] = device_addr.get("num_send_frames", "16"); + + _data_transport = usb_zero_copy::make_wrapper( + usb_zero_copy::make( + handle, // identifier + 6, // IN endpoint + 2, // OUT endpoint + data_xport_args // param hints + ) + ); + + //////////////////////////////////////////////////////////////////// // Initialize the properties tree //////////////////////////////////////////////////////////////////// _tree = property_tree::make(); diff --git a/host/lib/usrp/b100/io_impl.cpp b/host/lib/usrp/b100/io_impl.cpp index 34535217a..d2eee4f7c 100644 --- a/host/lib/usrp/b100/io_impl.cpp +++ b/host/lib/usrp/b100/io_impl.cpp @@ -65,8 +65,9 @@ void b100_impl::io_init(void){ _tx_otw_type.shift = 0; _tx_otw_type.byteorder = uhd::otw_type_t::BO_LITTLE_ENDIAN; - //TODO best place to put this? - this->reset_gpif(6); + //clear state machines + _fpga_ctrl->poke32(B100_REG_CLEAR_RX, 0); + _fpga_ctrl->poke32(B100_REG_CLEAR_TX, 0); //set the expected packet size in USB frames _fpga_ctrl->poke32(B100_REG_MISC_RX_LEN, 4); diff --git a/host/tests/time_spec_test.cpp b/host/tests/time_spec_test.cpp index e57bbced1..467da5c18 100644 --- a/host/tests/time_spec_test.cpp +++ b/host/tests/time_spec_test.cpp @@ -56,9 +56,9 @@ BOOST_AUTO_TEST_CASE(test_time_spec_parts){ BOOST_CHECK_CLOSE(uhd::time_spec_t(1.1).get_frac_secs(), 0.1, 0.001); BOOST_CHECK_EQUAL(uhd::time_spec_t(1.1).get_tick_count(100), 10); - BOOST_CHECK_EQUAL(uhd::time_spec_t(-1.1).get_full_secs(), -1); - BOOST_CHECK_CLOSE(uhd::time_spec_t(-1.1).get_frac_secs(), -0.1, 0.001); - BOOST_CHECK_EQUAL(uhd::time_spec_t(-1.1).get_tick_count(100), -10); + BOOST_CHECK_EQUAL(uhd::time_spec_t(-1.1).get_full_secs(), -2); + BOOST_CHECK_CLOSE(uhd::time_spec_t(-1.1).get_frac_secs(), 0.9, 0.001); + BOOST_CHECK_EQUAL(uhd::time_spec_t(-1.1).get_tick_count(100), 90); } BOOST_AUTO_TEST_CASE(test_time_spec_get_system_time){ @@ -78,3 +78,22 @@ BOOST_AUTO_TEST_CASE(test_time_spec_get_system_time){ BOOST_CHECK(diff.get_real_secs() > 0); //assert positive BOOST_CHECK(diff.get_real_secs() < 1.0); //assert under 1s } + +BOOST_AUTO_TEST_CASE(test_time_spec_neg_values){ + uhd::time_spec_t ts1(0.3); + uhd::time_spec_t ts2(1, -0.9); + std::cout << "ts1 " << ts1.get_real_secs() << std::endl; + std::cout << "ts2 " << ts2.get_real_secs() << std::endl; + BOOST_CHECK(ts1 > ts2); + + uhd::time_spec_t tsa(430.001083); + uhd::time_spec_t tsb(429.999818); + uhd::time_spec_t tsc(0.3); + uhd::time_spec_t tsd = tsa - tsb; + std::cout << "tsa " << tsa.get_real_secs() << std::endl; + std::cout << "tsb " << tsb.get_real_secs() << std::endl; + std::cout << "tsc " << tsc.get_real_secs() << std::endl; + std::cout << "tsd " << tsd.get_real_secs() << std::endl; + BOOST_CHECK(tsa > tsb); + BOOST_CHECK(tsc > tsd); +} |