diff options
Diffstat (limited to 'host/lib/usrp/b200')
-rw-r--r-- | host/lib/usrp/b200/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_cores.cpp | 83 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_cores.hpp | 66 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_iface.cpp | 80 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_iface.hpp | 7 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_impl.cpp | 49 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_impl.hpp | 9 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_regs.hpp | 2 |
8 files changed, 197 insertions, 100 deletions
diff --git a/host/lib/usrp/b200/CMakeLists.txt b/host/lib/usrp/b200/CMakeLists.txt index 3d8aad052..a08c4bd03 100644 --- a/host/lib/usrp/b200/CMakeLists.txt +++ b/host/lib/usrp/b200/CMakeLists.txt @@ -30,5 +30,6 @@ IF(ENABLE_B200) ${CMAKE_CURRENT_SOURCE_DIR}/b200_iface.cpp ${CMAKE_CURRENT_SOURCE_DIR}/b200_io_impl.cpp ${CMAKE_CURRENT_SOURCE_DIR}/b200_uart.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/b200_cores.cpp ) ENDIF(ENABLE_B200) diff --git a/host/lib/usrp/b200/b200_cores.cpp b/host/lib/usrp/b200/b200_cores.cpp new file mode 100644 index 000000000..19e637ef4 --- /dev/null +++ b/host/lib/usrp/b200/b200_cores.cpp @@ -0,0 +1,83 @@ +// +// Copyright 2013-2014 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 "b200_cores.hpp" +#include "b200_regs.hpp" +#include "b200_impl.hpp" + +b200_local_spi_core::b200_local_spi_core( + uhd::wb_iface::sptr iface, + perif_t default_perif) : + _spi_core(spi_core_3000::make(iface, TOREG(SR_CORE_SPI), RB32_CORE_SPI)), + _current_perif(default_perif), + _last_perif(default_perif) +{ + change_perif(default_perif); +} + +boost::uint32_t b200_local_spi_core::transact_spi( + int which_slave, + const uhd::spi_config_t &config, + boost::uint32_t data, + size_t num_bits, + bool readback) +{ + boost::mutex::scoped_lock lock(_mutex); + return _spi_core->transact_spi(which_slave, config, data, num_bits, readback); +} + +void b200_local_spi_core::change_perif(perif_t perif) +{ + boost::mutex::scoped_lock lock(_mutex); + _last_perif = _current_perif; + _current_perif = perif; + + switch (_current_perif) { + case CODEC: + _spi_core->set_divider(B200_BUS_CLOCK_RATE/AD9361_SPI_RATE); + break; + case PLL: + _spi_core->set_divider(B200_BUS_CLOCK_RATE/ADF4001_SPI_RATE); + break; + } +} + +void b200_local_spi_core::restore_perif() +{ + change_perif(_last_perif); +} + +b200_ref_pll_ctrl::b200_ref_pll_ctrl(b200_local_spi_core::sptr spi) : + uhd::usrp::adf4001_ctrl(spi, ADF4001_SLAVENO), + _spi(spi) +{ +} + +void b200_ref_pll_ctrl::set_lock_to_ext_ref(bool external) +{ + _spi->change_perif(b200_local_spi_core::PLL); + adf4001_ctrl::set_lock_to_ext_ref(external); + _spi->restore_perif(); +} + + +b200_local_spi_core::sptr b200_local_spi_core::make( + uhd::wb_iface::sptr iface, b200_local_spi_core::perif_t default_perif) +{ + return sptr(new b200_local_spi_core(iface, default_perif)); +} + diff --git a/host/lib/usrp/b200/b200_cores.hpp b/host/lib/usrp/b200/b200_cores.hpp new file mode 100644 index 000000000..8a8900412 --- /dev/null +++ b/host/lib/usrp/b200/b200_cores.hpp @@ -0,0 +1,66 @@ +// +// Copyright 2013-2014 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_B200_CORES_HPP +#define INCLUDED_B200_CORES_HPP + +#include "spi_core_3000.hpp" +#include "adf4001_ctrl.hpp" +#include <boost/thread/mutex.hpp> + +class b200_local_spi_core : boost::noncopyable, public uhd::spi_iface { + +public: + typedef boost::shared_ptr<b200_local_spi_core> sptr; + + enum perif_t { + CODEC, PLL + }; + + b200_local_spi_core(uhd::wb_iface::sptr iface, perif_t default_perif); + + virtual boost::uint32_t transact_spi( + int which_slave, + const uhd::spi_config_t &config, + boost::uint32_t data, + size_t num_bits, + bool readback); + + void change_perif(perif_t perif); + void restore_perif(); + + static sptr make(uhd::wb_iface::sptr iface, perif_t default_perif = CODEC); + +private: + spi_core_3000::sptr _spi_core; + perif_t _current_perif; + perif_t _last_perif; + boost::mutex _mutex; +}; + +class b200_ref_pll_ctrl : public uhd::usrp::adf4001_ctrl { +public: + typedef boost::shared_ptr<b200_ref_pll_ctrl> sptr; + + b200_ref_pll_ctrl(b200_local_spi_core::sptr spi); + void set_lock_to_ext_ref(bool external); + +private: + b200_local_spi_core::sptr _spi; +}; + +#endif /* INCLUDED_B200_CORES_HPP */ diff --git a/host/lib/usrp/b200/b200_iface.cpp b/host/lib/usrp/b200/b200_iface.cpp index efb9b3a35..820090959 100644 --- a/host/lib/usrp/b200/b200_iface.cpp +++ b/host/lib/usrp/b200/b200_iface.cpp @@ -57,15 +57,11 @@ const static boost::uint8_t B200_VREQ_GET_FPGA_HASH = 0x1D; const static boost::uint8_t B200_VREQ_SET_FW_HASH = 0x1E; const static boost::uint8_t B200_VREQ_GET_FW_HASH = 0x1F; const static boost::uint8_t B200_VREQ_LOOP = 0x22; -const static boost::uint8_t B200_VREQ_SPI_WRITE = 0x32; -const static boost::uint8_t B200_VREQ_SPI_READ = 0x42; const static boost::uint8_t B200_VREQ_FPGA_CONFIG = 0x55; const static boost::uint8_t B200_VREQ_FPGA_RESET = 0x62; const static boost::uint8_t B200_VREQ_GPIF_RESET = 0x72; const static boost::uint8_t B200_VREQ_GET_USB = 0x80; const static boost::uint8_t B200_VREQ_GET_STATUS = 0x83; -const static boost::uint8_t B200_VREQ_AD9361_CTRL_WRITE = 0x90; -const static boost::uint8_t B200_VREQ_AD9361_CTRL_READ = 0x91; const static boost::uint8_t B200_VREQ_FX3_RESET = 0x99; const static boost::uint8_t B200_VREQ_EEPROM_WRITE = 0xBA; const static boost::uint8_t B200_VREQ_EEPROM_READ = 0xBB; @@ -270,82 +266,6 @@ public: return recv_bytes; } - void transact_spi( - unsigned char *tx_data, - size_t num_tx_bits, - unsigned char *rx_data, - size_t num_rx_bits) { - int ret = 0; - boost::uint16_t tx_length = num_tx_bits / 8; - - if(tx_data[0] & 0x80) { - ret = fx3_control_write(B200_VREQ_SPI_WRITE, 0x00, \ - 0x00, tx_data, tx_length); - } else { - ret = fx3_control_write(B200_VREQ_SPI_READ, 0x00, \ - 0x00, tx_data, tx_length); - } - - if (ret < 0) - throw uhd::io_error((boost::format("Failed to write SPI (%d: %s)") % ret % libusb_error_name(ret)).str()); - else if (ret != tx_length) - throw uhd::io_error((boost::format("Short write on write SPI (expecting: %d, returned: %d)") % tx_length % ret).str()); - - - if(num_rx_bits) { - boost::uint16_t total_length = num_rx_bits / 8; - - ret = fx3_control_read(B200_VREQ_LOOP, 0x00, \ - 0x00, rx_data, total_length); - - if (ret < 0) - throw uhd::io_error((boost::format("Failed to readback (%d: %s)") % ret % libusb_error_name(ret)).str()); - else if (ret != total_length) - throw uhd::io_error((boost::format("Short read on readback (expecting: %d, returned: %d)") % total_length % ret).str()); - } - } - - void ad9361_transact(const unsigned char in_buff[AD9361_DISPATCH_PACKET_SIZE], unsigned char out_buff[AD9361_DISPATCH_PACKET_SIZE]) { - const int bytes_to_write = AD9361_DISPATCH_PACKET_SIZE; - const int bytes_to_read = AD9361_DISPATCH_PACKET_SIZE; - const size_t read_retries = 5; - - int ret = fx3_control_write(B200_VREQ_AD9361_CTRL_WRITE, 0x00, 0x00, (unsigned char *)in_buff, bytes_to_write); - if (ret < 0) - throw uhd::io_error((boost::format("Failed to write AD9361 (%d: %s)") % ret % libusb_error_name(ret)).str()); - else if (ret != bytes_to_write) - throw uhd::io_error((boost::format("Short write on write AD9361 (expecting: %d, returned: %d)") % bytes_to_write % ret).str()); - - for (size_t i = 0; i < read_retries; i++) - { - ret = fx3_control_read(B200_VREQ_AD9361_CTRL_READ, 0x00, 0x00, out_buff, bytes_to_read, 3000); - if (ret < 0) - { - if (ret == LIBUSB_ERROR_TIMEOUT) - { - UHD_LOG << (boost::format("Failed to read AD9361 (%d: %s). Retrying (%d of %d)...") - % ret - % libusb_error_name(ret) - % (i+1) - % read_retries - ) << std::endl; - } - else - { - throw uhd::io_error((boost::format("Failed to read AD9361 (%d: %s)") - % ret - % libusb_error_name(ret) - ).str()); - } - } - - if (ret == bytes_to_read) - return; - } - - throw uhd::io_error(str(boost::format("Failed to read complete AD9361 (expecting: %d, last read: %d)") % bytes_to_read % ret)); - } - void load_firmware(const std::string filestring, UHD_UNUSED(bool force) = false) { const char *filename = filestring.c_str(); diff --git a/host/lib/usrp/b200/b200_iface.hpp b/host/lib/usrp/b200/b200_iface.hpp index 20b4a7a89..83adfdd64 100644 --- a/host/lib/usrp/b200/b200_iface.hpp +++ b/host/lib/usrp/b200/b200_iface.hpp @@ -35,8 +35,7 @@ static const std::string B200_FW_FILE_NAME = "usrp_b200_fw.hex"; static const std::string B200_FPGA_FILE_NAME = "usrp_b200_fpga.bin"; static const std::string B210_FPGA_FILE_NAME = "usrp_b210_fpga.bin"; -class UHD_API b200_iface: boost::noncopyable, public virtual uhd::i2c_iface, - public ad9361_ctrl_iface_type { +class UHD_API b200_iface: boost::noncopyable, public virtual uhd::i2c_iface { public: typedef boost::shared_ptr<b200_iface> sptr; @@ -71,10 +70,6 @@ public: //! load an FPGA image virtual boost::uint32_t load_fpga(const std::string filestring) = 0; - //! send SPI through the FX3 - virtual void transact_spi( unsigned char *tx_data, size_t num_tx_bits, \ - unsigned char *rx_data, size_t num_rx_bits) = 0; - virtual void write_eeprom(boost::uint16_t addr, boost::uint16_t offset, const uhd::byte_vector_t &bytes) = 0; virtual uhd::byte_vector_t read_eeprom(boost::uint16_t addr, boost::uint16_t offset, size_t num_bytes) = 0; diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index bf5fdd251..5c9324cb9 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -31,6 +31,7 @@ #include <boost/thread/thread.hpp> #include <boost/lexical_cast.hpp> #include <boost/functional/hash.hpp> +#include <boost/make_shared.hpp> #include <cstdio> #include <ctime> #include <cmath> @@ -45,6 +46,33 @@ static const boost::posix_time::milliseconds REENUMERATION_TIMEOUT_MS(3000); static const size_t FE1 = 1; static const size_t FE2 = 0; +class b200_ad9361_client_t : public ad9361_params { +public: + ~b200_ad9361_client_t() {} + double get_band_edge(frequency_band_t band) { + switch (band) { + case AD9361_RX_BAND0: return 2.2e9; + case AD9361_RX_BAND1: return 4.0e9; + case AD9361_TX_BAND0: return 2.5e9; + default: return 0; + } + } + clocking_mode_t get_clocking_mode() { + return AD9361_XTAL_N_CLK_PATH; + } + digital_interface_mode_t get_digital_interface_mode() { + return AD9361_DDR_FDD_LVCMOS; + } + digital_interface_delays_t get_digital_interface_timing() { + digital_interface_delays_t delays; + delays.rx_clk_delay = 0; + delays.rx_data_delay = 0xF; + delays.tx_clk_delay = 0; + delays.tx_data_delay = 0xF; + return delays; + } +}; + /*********************************************************************** * Discovery **********************************************************************/ @@ -146,7 +174,7 @@ static device::sptr b200_make(const device_addr_t &device_addr) UHD_STATIC_BLOCK(register_b200_device) { - device::register_device(&b200_find, &b200_make); + device::register_device(&b200_find, &b200_make, device::USRP); } /*********************************************************************** @@ -155,6 +183,7 @@ UHD_STATIC_BLOCK(register_b200_device) b200_impl::b200_impl(const device_addr_t &device_addr) { _tree = property_tree::make(); + _type = device::USRP; const fs_path mb_path = "/mboards/0"; //try to match the given device address with something on the USB bus @@ -338,10 +367,17 @@ b200_impl::b200_impl(const device_addr_t &device_addr) _demux = recv_packet_demuxer_3000::make(_data_transport); //////////////////////////////////////////////////////////////////// + // create time and clock control objects + //////////////////////////////////////////////////////////////////// + _spi_iface = b200_local_spi_core::make(_local_ctrl); + _adf4001_iface = boost::make_shared<b200_ref_pll_ctrl>(_spi_iface); + + //////////////////////////////////////////////////////////////////// // Init codec - turns on clocks //////////////////////////////////////////////////////////////////// UHD_MSG(status) << "Initialize CODEC control..." << std::endl; - _codec_ctrl = ad9361_ctrl::make(_iface); + ad9361_params::sptr client_settings = boost::make_shared<b200_ad9361_client_t>(); + _codec_ctrl = ad9361_ctrl::make_spi(client_settings, _spi_iface, AD9361_SLAVENO); this->reset_codec_dcm(); //////////////////////////////////////////////////////////////////// @@ -404,13 +440,6 @@ b200_impl::b200_impl(const device_addr_t &device_addr) } _codec_ctrl->data_port_loopback(false); - //////////////////////////////////////////////////////////////////// - // create time and clock control objects - //////////////////////////////////////////////////////////////////// - _spi_iface = spi_core_3000::make(_local_ctrl, TOREG(SR_CORE_SPI), RB32_CORE_SPI); - _spi_iface->set_divider(B200_BUS_CLOCK_RATE/ADF4001_SPI_RATE); - _adf4001_iface = boost::shared_ptr<adf4001_ctrl>(new adf4001_ctrl(_spi_iface, ADF4001_SLAVENO)); - //register time now and pps onto available radio cores _tree->create<time_spec_t>(mb_path / "time" / "now") .publish(boost::bind(&time_core_3000::get_time_now, _radio_perifs[0].time64)); @@ -680,7 +709,7 @@ void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, co } else { - const double max_tick_rate = ((chan_count <= 1) ? AD9361_1_CHAN_CLOCK_RATE_MAX : AD9361_2_CHAN_CLOCK_RATE_MAX); + const double max_tick_rate = ad9361_device_t::AD9361_MAX_CLOCK_RATE / ((chan_count <= 1) ? 1 : 2); if (tick_rate - max_tick_rate >= 1.0) { throw uhd::value_error(boost::str( diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp index c3508c550..155ff699c 100644 --- a/host/lib/usrp/b200/b200_impl.hpp +++ b/host/lib/usrp/b200/b200_impl.hpp @@ -20,6 +20,7 @@ #include "b200_iface.hpp" #include "b200_uart.hpp" +#include "b200_cores.hpp" #include "ad9361_ctrl.hpp" #include "adf4001_ctrl.hpp" #include "rx_vita_core_3000.hpp" @@ -44,9 +45,9 @@ #include <uhd/transport/bounded_buffer.hpp> #include <boost/weak_ptr.hpp> #include "recv_packet_demuxer_3000.hpp" -static const boost::uint8_t B200_FW_COMPAT_NUM_MAJOR = 0x04; +static const boost::uint8_t B200_FW_COMPAT_NUM_MAJOR = 0x06; static const boost::uint8_t B200_FW_COMPAT_NUM_MINOR = 0x00; -static const boost::uint16_t B200_FPGA_COMPAT_NUM = 0x03; +static const boost::uint16_t B200_FPGA_COMPAT_NUM = 0x04; static const double B200_BUS_CLOCK_RATE = 100e6; static const double B200_DEFAULT_TICK_RATE = 32e6; static const boost::uint32_t B200_GPSDO_ST_NONE = 0x83; @@ -99,8 +100,8 @@ private: //controllers b200_iface::sptr _iface; radio_ctrl_core_3000::sptr _local_ctrl; - ad9361_ctrl::sptr _codec_ctrl; - spi_core_3000::sptr _spi_iface; + uhd::usrp::ad9361_ctrl::sptr _codec_ctrl; + b200_local_spi_core::sptr _spi_iface; boost::shared_ptr<uhd::usrp::adf4001_ctrl> _adf4001_iface; uhd::gps_ctrl::sptr _gps; diff --git a/host/lib/usrp/b200/b200_regs.hpp b/host/lib/usrp/b200/b200_regs.hpp index c64066b27..dc8a6b0dc 100644 --- a/host/lib/usrp/b200/b200_regs.hpp +++ b/host/lib/usrp/b200/b200_regs.hpp @@ -52,7 +52,9 @@ localparam RB64_TIME_PPS = 16; localparam RB64_CODEC_READBACK = 24; //pll constants +static const int AD9361_SLAVENO = (1 << 0); static const int ADF4001_SLAVENO = (1 << 1); +static const double AD9361_SPI_RATE = 1e6; static const double ADF4001_SPI_RATE = 10e3; //slow for large time constant on spi lines /* ATR Control Bits */ |