diff options
Diffstat (limited to 'host/lib')
-rw-r--r-- | host/lib/usrp/usrp2/CMakeLists.txt | 2 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/clock_ctrl.cpp | 57 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/clock_ctrl.hpp | 12 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/fw_common.h | 4 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/mboard_impl.cpp | 60 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/serdes_ctrl.cpp | 46 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/serdes_ctrl.hpp | 40 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.cpp | 14 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.hpp | 9 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_regs.cpp | 2 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_regs.hpp | 10 |
11 files changed, 138 insertions, 118 deletions
diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt index 527669852..d83c82063 100644 --- a/host/lib/usrp/usrp2/CMakeLists.txt +++ b/host/lib/usrp/usrp2/CMakeLists.txt @@ -38,8 +38,6 @@ IF(ENABLE_USRP2) ${CMAKE_CURRENT_SOURCE_DIR}/gps_ctrl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/mboard_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/serdes_ctrl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/serdes_ctrl.hpp ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.cpp ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.hpp ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_impl.cpp diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp index 428d5539b..27ccefb2b 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.cpp +++ b/host/lib/usrp/usrp2/clock_ctrl.cpp @@ -22,10 +22,13 @@ #include <uhd/utils/assert.hpp> #include <boost/cstdint.hpp> #include <boost/lexical_cast.hpp> +#include <boost/math/special_functions/round.hpp> #include <iostream> using namespace uhd; +static const bool enb_test_clk = false; + /*! * A usrp2 clock control specific to the ad9510 ic. */ @@ -66,13 +69,12 @@ public: this->enable_external_ref(false); this->enable_rx_dboard_clock(false); this->enable_tx_dboard_clock(false); + this->enable_mimo_clock_out(false); /* private clock enables, must be set here */ this->enable_dac_clock(true); this->enable_adc_clock(true); - - /* always driving the mimo reference */ - this->enable_mimo_clock_out(true); + this->enable_test_clock(enb_test_clk); } ~usrp2_clock_ctrl_impl(void){ @@ -83,6 +85,7 @@ public: this->enable_dac_clock(false); this->enable_adc_clock(false); this->enable_mimo_clock_out(false); + this->enable_test_clock(false); } void enable_mimo_clock_out(bool enb){ @@ -246,6 +249,54 @@ public: double get_master_clock_rate(void){ return 100e6; } + + void set_mimo_clock_delay(double delay) { + //delay_val is a 5-bit value (0-31) for fine control + //the equations below determine delay for a given ramp current, # of caps and fine delay register + //delay range: + //range_ns = 200*((caps+3)/i_ramp_ua)*1.3286 + //offset (zero delay): + //offset_ns = 0.34 + (1600 - i_ramp_ua)*1e-4 + ((caps-1)/ramp)*6 + //delay_ns = offset_ns + range_ns * delay / 31 + + int delay_val = boost::math::iround(delay/9.744e-9*31); + + if(delay_val == 0) { + switch(clk_regs.exp) { + case 5: + _ad9510_regs.delay_control_out5 = 1; + break; + case 6: + _ad9510_regs.delay_control_out6 = 1; + break; + default: + break; //delay not supported on U2 rev 3 + } + } else { + switch(clk_regs.exp) { + case 5: + _ad9510_regs.delay_control_out5 = 0; + _ad9510_regs.ramp_current_out5 = ad9510_regs_t::RAMP_CURRENT_OUT5_200UA; + _ad9510_regs.ramp_capacitor_out5 = ad9510_regs_t::RAMP_CAPACITOR_OUT5_4CAPS; + _ad9510_regs.delay_fine_adjust_out5 = delay_val; + this->write_reg(0x34); + this->write_reg(0x35); + this->write_reg(0x36); + break; + case 6: + _ad9510_regs.delay_control_out6 = 0; + _ad9510_regs.ramp_current_out6 = ad9510_regs_t::RAMP_CURRENT_OUT6_200UA; + _ad9510_regs.ramp_capacitor_out6 = ad9510_regs_t::RAMP_CAPACITOR_OUT6_4CAPS; + _ad9510_regs.delay_fine_adjust_out6 = delay_val; + this->write_reg(0x38); + this->write_reg(0x39); + this->write_reg(0x3A); + break; + default: + break; + } + } + } private: /*! diff --git a/host/lib/usrp/usrp2/clock_ctrl.hpp b/host/lib/usrp/usrp2/clock_ctrl.hpp index db6c52c83..9ccbc959e 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.hpp +++ b/host/lib/usrp/usrp2/clock_ctrl.hpp @@ -91,8 +91,18 @@ public: virtual void enable_test_clock(bool enb) = 0; /*! - * TODO other clock control api here.... + * Enable/disable the ref clock output over the serdes cable. + * \param enb true to enable + */ + virtual void enable_mimo_clock_out(bool enb) = 0; + + /*! + * Set the output delay of the mimo clock + * Used to synchronise daisy-chained USRPs over the MIMO cable + * Can also be used to adjust delay for uneven reference cable lengths + * \param delay the clock delay in seconds */ + virtual void set_mimo_clock_delay(double delay) = 0; }; diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index a9c39e650..efbb4b954 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -33,8 +33,8 @@ extern "C" { #endif //fpga and firmware compatibility numbers -#define USRP2_FPGA_COMPAT_NUM 3 -#define USRP2_FW_COMPAT_NUM 7 +#define USRP2_FPGA_COMPAT_NUM 4 +#define USRP2_FW_COMPAT_NUM 8 //used to differentiate control packets over data port #define USRP2_INVALID_VRT_HEADER 0 diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 766ea993c..b8ebd6030 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -27,6 +27,10 @@ #include <iostream> #include <boost/date_time/posix_time/posix_time.hpp> +static const double mimo_clock_delay_usrp2_rev4 = 4.18e-9; +static const double mimo_clock_delay_usrp_n2xx = 0; //TODO +static const int mimo_clock_sync_delay_cycles = 134; + using namespace uhd; using namespace uhd::usrp; using namespace boost::posix_time; @@ -38,8 +42,8 @@ usrp2_mboard_impl::usrp2_mboard_impl( size_t index, transport::udp_simple::sptr ctrl_transport, transport::zero_copy_if::sptr data_transport, - size_t recv_samps_per_packet, - const device_addr_t &flow_control_hints + const device_addr_t &device_args, + size_t recv_samps_per_packet ): _index(index), _iface(usrp2_iface::make(ctrl_transport)) @@ -58,7 +62,6 @@ usrp2_mboard_impl::usrp2_mboard_impl( //contruct the interfaces to mboard perifs _clock_ctrl = usrp2_clock_ctrl::make(_iface); _codec_ctrl = usrp2_codec_ctrl::make(_iface); - _serdes_ctrl = usrp2_serdes_ctrl::make(_iface); //_gps_ctrl = usrp2_gps_ctrl::make(_iface); //if(_gps_ctrl->gps_detected()) std::cout << "GPS time: " << _gps_ctrl->get_time() << std::endl; @@ -98,14 +101,14 @@ usrp2_mboard_impl::usrp2_mboard_impl( _iface->poke32(_iface->regs.tx_ctrl_policy, U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET); //setting the cycles per update (disabled by default) - const double ups_per_sec = flow_control_hints.cast<double>("ups_per_sec", 0.0); + const double ups_per_sec = device_args.cast<double>("ups_per_sec", 0.0); if (ups_per_sec > 0.0){ const size_t cycles_per_up = size_t(_clock_ctrl->get_master_clock_rate()/ups_per_sec); _iface->poke32(_iface->regs.tx_ctrl_cycles_per_up, U2_FLAG_TX_CTRL_UP_ENB | cycles_per_up); } //setting the packets per update (enabled by default) - const double ups_per_fifo = flow_control_hints.cast<double>("ups_per_fifo", 8.0); + const double ups_per_fifo = device_args.cast<double>("ups_per_fifo", 8.0); if (ups_per_fifo > 0.0){ const size_t packets_per_up = size_t(usrp2_impl::sram_bytes/ups_per_fifo/data_transport->get_send_frame_size()); _iface->poke32(_iface->regs.tx_ctrl_packets_per_up, U2_FLAG_TX_CTRL_UP_ENB | packets_per_up); @@ -118,6 +121,20 @@ usrp2_mboard_impl::usrp2_mboard_impl( init_duc_config(); //initialize the clock configuration + if (device_args.has_key("mimo_mode")){ + if (device_args["mimo_mode"] == "master"){ + _mimo_clocking_mode_is_master = true; + } + else if (device_args["mimo_mode"] == "slave"){ + _mimo_clocking_mode_is_master = false; + } + else throw std::runtime_error( + "mimo_mode must be set to master or slave" + ); + } + else { + _mimo_clocking_mode_is_master = bool(_iface->peek32(_iface->regs.status) & (1 << 8)); + } init_clock_config(); //init the codec before the dboard @@ -155,7 +172,6 @@ void usrp2_mboard_impl::update_clock_config(void){ //translate pps source enums switch(_clock_config.pps_source){ case clock_config_t::PPS_SMA: pps_flags |= U2_FLAG_TIME64_PPS_SMA; break; - case clock_config_t::PPS_MIMO: pps_flags |= U2_FLAG_TIME64_PPS_MIMO; break; default: throw std::runtime_error("unhandled clock configuration pps source"); } @@ -176,7 +192,6 @@ void usrp2_mboard_impl::update_clock_config(void){ switch(_clock_config.ref_source){ case clock_config_t::REF_INT : _iface->poke32(_iface->regs.misc_ctrl_clock, 0x12); break; case clock_config_t::REF_SMA : _iface->poke32(_iface->regs.misc_ctrl_clock, 0x1C); break; - case clock_config_t::REF_MIMO: _iface->poke32(_iface->regs.misc_ctrl_clock, 0x15); break; default: throw std::runtime_error("unhandled clock configuration reference source"); } _clock_ctrl->enable_external_ref(true); //USRP2P has an internal 10MHz TCXO @@ -187,7 +202,6 @@ void usrp2_mboard_impl::update_clock_config(void){ switch(_clock_config.ref_source){ case clock_config_t::REF_INT : _iface->poke32(_iface->regs.misc_ctrl_clock, 0x10); break; case clock_config_t::REF_SMA : _iface->poke32(_iface->regs.misc_ctrl_clock, 0x1C); break; - case clock_config_t::REF_MIMO: _iface->poke32(_iface->regs.misc_ctrl_clock, 0x15); break; default: throw std::runtime_error("unhandled clock configuration reference source"); } _clock_ctrl->enable_external_ref(_clock_config.ref_source != clock_config_t::REF_INT); @@ -195,6 +209,36 @@ void usrp2_mboard_impl::update_clock_config(void){ case usrp2_iface::USRP_NXXX: break; } + + //Handle the serdes clocking based on master/slave mode: + // - Masters always drive the clock over serdes. + // - Slaves always lock to this serdes clock. + // - Slaves lock their time over the serdes. + if (_mimo_clocking_mode_is_master){ + _clock_ctrl->enable_mimo_clock_out(true); + switch(_iface->get_rev()){ + case usrp2_iface::USRP_N200: + case usrp2_iface::USRP_N210: + _clock_ctrl->set_mimo_clock_delay(mimo_clock_delay_usrp_n2xx); + break; + + case usrp2_iface::USRP2_REV4: + _clock_ctrl->set_mimo_clock_delay(mimo_clock_delay_usrp2_rev4); + break; + + default: break; //not handled + } + _iface->poke32(_iface->regs.time64_mimo_sync, 0); + } + else{ + _iface->poke32(_iface->regs.misc_ctrl_clock, 0x15); + _clock_ctrl->enable_external_ref(true); + _clock_ctrl->enable_mimo_clock_out(false); + _iface->poke32(_iface->regs.time64_mimo_sync, + (1 << 8) | (mimo_clock_sync_delay_cycles & 0xff) + ); + } + } void usrp2_mboard_impl::set_time_spec(const time_spec_t &time_spec, bool now){ diff --git a/host/lib/usrp/usrp2/serdes_ctrl.cpp b/host/lib/usrp/usrp2/serdes_ctrl.cpp deleted file mode 100644 index 1cda22f45..000000000 --- a/host/lib/usrp/usrp2/serdes_ctrl.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "serdes_ctrl.hpp" -#include "usrp2_regs.hpp" - -using namespace uhd; - -/*! - * A usrp2 serdes control implementation - */ -class usrp2_serdes_ctrl_impl : public usrp2_serdes_ctrl{ -public: - usrp2_serdes_ctrl_impl(usrp2_iface::sptr iface){ - _iface = iface; - _iface->poke32(_iface->regs.misc_ctrl_serdes, U2_FLAG_MISC_CTRL_SERDES_ENABLE | U2_FLAG_MISC_CTRL_SERDES_RXEN); - } - - ~usrp2_serdes_ctrl_impl(void){ - _iface->poke32(_iface->regs.misc_ctrl_serdes, 0); //power-down - } - -private: - usrp2_iface::sptr _iface; -}; - -/*********************************************************************** - * Public make function for the usrp2 serdes control - **********************************************************************/ -usrp2_serdes_ctrl::sptr usrp2_serdes_ctrl::make(usrp2_iface::sptr iface){ - return sptr(new usrp2_serdes_ctrl_impl(iface)); -} diff --git a/host/lib/usrp/usrp2/serdes_ctrl.hpp b/host/lib/usrp/usrp2/serdes_ctrl.hpp deleted file mode 100644 index 3c909c531..000000000 --- a/host/lib/usrp/usrp2/serdes_ctrl.hpp +++ /dev/null @@ -1,40 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_SERDES_CTRL_HPP -#define INCLUDED_SERDES_CTRL_HPP - -#include "usrp2_iface.hpp" -#include <boost/shared_ptr.hpp> -#include <boost/utility.hpp> - -class usrp2_serdes_ctrl : boost::noncopyable{ -public: - typedef boost::shared_ptr<usrp2_serdes_ctrl> sptr; - - /*! - * Make a serdes control object for the usrp2 serdes port. - * \param _iface a pointer to the usrp2 interface object - * \return a new serdes control object - */ - static sptr make(usrp2_iface::sptr iface); - - //TODO fill me in with virtual methods - -}; - -#endif /* INCLUDED_SERDES_CTRL_HPP */ diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index c3bbe4d65..133c39a35 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -201,8 +201,9 @@ sep_indexed_dev_addrs(device_addr); //create a ctrl and data transport for each address std::vector<udp_simple::sptr> ctrl_transports; std::vector<zero_copy_if::sptr> data_transports; + const device_addrs_t device_addrs = sep_indexed_dev_addrs(device_addr); - BOOST_FOREACH(const device_addr_t &dev_addr_i, sep_indexed_dev_addrs(device_addr)){ + BOOST_FOREACH(const device_addr_t &dev_addr_i, device_addrs){ ctrl_transports.push_back(udp_simple::make_connected( dev_addr_i["addr"], num2str(USRP2_UDP_CTRL_PORT) )); @@ -213,7 +214,7 @@ sep_indexed_dev_addrs(device_addr); //create the usrp2 implementation guts return device::sptr( - new usrp2_impl(ctrl_transports, data_transports, device_addr) + new usrp2_impl(ctrl_transports, data_transports, device_addrs) ); } @@ -227,7 +228,7 @@ UHD_STATIC_BLOCK(register_usrp2_device){ usrp2_impl::usrp2_impl( std::vector<udp_simple::sptr> ctrl_transports, std::vector<zero_copy_if::sptr> data_transports, - const device_addr_t &flow_control_hints + const device_addrs_t &device_args ): _data_transports(data_transports) { @@ -244,11 +245,10 @@ usrp2_impl::usrp2_impl( //!!!!! set the otw type here before continuing, its used below //create a new mboard handler for each control transport - for(size_t i = 0; i < ctrl_transports.size(); i++){ + for(size_t i = 0; i < device_args.size(); i++){ _mboards.push_back(usrp2_mboard_impl::sptr(new usrp2_mboard_impl( - i, ctrl_transports[i], data_transports[i], - this->get_max_recv_samps_per_packet(), - flow_control_hints + i, ctrl_transports[i], data_transports[i], device_args[i], + this->get_max_recv_samps_per_packet() ))); //use an empty name when there is only one mboard std::string name = (ctrl_transports.size() > 1)? boost::lexical_cast<std::string>(i) : ""; diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index aa8eb0155..85c00b079 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -22,7 +22,6 @@ #include "clock_ctrl.hpp" #include "codec_ctrl.hpp" #include "gps_ctrl.hpp" -#include "serdes_ctrl.hpp" #include <uhd/device.hpp> #include <uhd/utils/pimpl.hpp> #include <uhd/types/dict.hpp> @@ -86,8 +85,8 @@ public: size_t index, uhd::transport::udp_simple::sptr, uhd::transport::zero_copy_if::sptr, - size_t recv_samps_per_packet, - const uhd::device_addr_t &flow_control_hints + const uhd::device_addr_t &device_args, + size_t recv_samps_per_packet ); ~usrp2_mboard_impl(void); @@ -100,12 +99,12 @@ public: private: size_t _index; bool _continuous_streaming; + bool _mimo_clocking_mode_is_master; //interfaces usrp2_iface::sptr _iface; usrp2_clock_ctrl::sptr _clock_ctrl; usrp2_codec_ctrl::sptr _codec_ctrl; - usrp2_serdes_ctrl::sptr _serdes_ctrl; usrp2_gps_ctrl::sptr _gps_ctrl; //properties for this mboard @@ -192,7 +191,7 @@ public: usrp2_impl( std::vector<uhd::transport::udp_simple::sptr> ctrl_transports, std::vector<uhd::transport::zero_copy_if::sptr> data_transports, - const uhd::device_addr_t &flow_control_hints + const uhd::device_addrs_t &device_args ); ~usrp2_impl(void); diff --git a/host/lib/usrp/usrp2/usrp2_regs.cpp b/host/lib/usrp/usrp2/usrp2_regs.cpp index dd0433816..82ad30f08 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.cpp +++ b/host/lib/usrp/usrp2/usrp2_regs.cpp @@ -57,6 +57,8 @@ usrp2_regs_t usrp2_get_regs(bool use_n2xx_map) { x.time64_flags = sr_addr(misc_output_base, x.sr_time64 + 2); x.time64_imm = sr_addr(misc_output_base, x.sr_time64 + 3); x.time64_tps = sr_addr(misc_output_base, x.sr_time64 + 4); + x.time64_mimo_sync = sr_addr(misc_output_base, x.sr_time64 + 5); + x.status = bp_base + 4*8; x.time64_secs_rb = bp_base + 4*10; x.time64_ticks_rb = bp_base + 4*11; x.compat_num_rb = bp_base + 4*12; diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp index 9936d634a..56e64029e 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.hpp +++ b/host/lib/usrp/usrp2/usrp2_regs.hpp @@ -25,10 +25,10 @@ #define USRP2_ATR_BASE 0xE400 #define USRP2_BP_STATUS_BASE 0xCC00 -#define USRP2P_MISC_OUTPUT_BASE 0x2000 -#define USRP2P_GPIO_BASE 0x3200 -#define USRP2P_ATR_BASE 0x3800 -#define USRP2P_BP_STATUS_BASE 0x3300 +#define USRP2P_MISC_OUTPUT_BASE 0x5000 +#define USRP2P_GPIO_BASE 0x6200 +#define USRP2P_ATR_BASE 0x6800 +#define USRP2P_BP_STATUS_BASE 0x6300 typedef struct { int sr_misc; @@ -57,6 +57,8 @@ typedef struct { int time64_flags; // flags -- see chart below int time64_imm; // set immediate (0=latch on next pps, 1=latch immediate, default=0) int time64_tps; // ticks per second rollover count + int time64_mimo_sync; + int status; int time64_secs_rb; int time64_ticks_rb; int compat_num_rb; |