aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/b200
diff options
context:
space:
mode:
authormichael-west <michael.west@ettus.com>2015-08-17 14:41:46 -0700
committerMartin Braun <martin.braun@ettus.com>2015-08-17 18:10:09 -0700
commit92539438c228b784a0254d9b2aae143686fa672e (patch)
tree7c50343a852d64956ba77e89f5029d5863768428 /host/lib/usrp/b200
parent868cbac336eb4e4191079ba08c97fa9b40890157 (diff)
downloaduhd-92539438c228b784a0254d9b2aae143686fa672e.tar.gz
uhd-92539438c228b784a0254d9b2aae143686fa672e.tar.bz2
uhd-92539438c228b784a0254d9b2aae143686fa672e.zip
B2XX: Added B200mini support
Diffstat (limited to 'host/lib/usrp/b200')
-rw-r--r--host/lib/usrp/b200/b200_iface.hpp29
-rw-r--r--host/lib/usrp/b200/b200_image_loader.cpp16
-rw-r--r--host/lib/usrp/b200/b200_impl.cpp283
-rw-r--r--host/lib/usrp/b200/b200_impl.hpp11
-rw-r--r--host/lib/usrp/b200/b200_io_impl.cpp2
5 files changed, 253 insertions, 88 deletions
diff --git a/host/lib/usrp/b200/b200_iface.hpp b/host/lib/usrp/b200/b200_iface.hpp
index 0c7ee6b9e..19ec561fa 100644
--- a/host/lib/usrp/b200/b200_iface.hpp
+++ b/host/lib/usrp/b200/b200_iface.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2012-2013,2015 Ettus Research LLC
+// Copyright 2012-2013 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
@@ -27,40 +27,55 @@
#include <boost/utility.hpp>
#include "ad9361_ctrl.hpp"
-enum b200_type_t {
+enum b200_product_t {
B200,
- B210
+ B210,
+ B205
};
+// These are actual USB PIDs (not Ettus Product IDs)
const static boost::uint16_t B200_VENDOR_ID = 0x2500;
const static boost::uint16_t B200_VENDOR_NI_ID = 0x3923;
const static boost::uint16_t B200_PRODUCT_ID = 0x0020;
+const static boost::uint16_t B205_PRODUCT_ID = 0x0021;
const static boost::uint16_t B200_PRODUCT_NI_ID = 0x7813;
const static boost::uint16_t B210_PRODUCT_NI_ID = 0x7814;
const static boost::uint16_t FX3_VID = 0x04b4;
const static boost::uint16_t FX3_DEFAULT_PID = 0x00f3;
const static boost::uint16_t FX3_REENUM_PID = 0x00f0;
+//! Map the USB PID to the product (only for PIDs that map to a single product)
+static const uhd::dict<boost::uint16_t, b200_product_t> B2XX_PID_TO_PRODUCT = boost::assign::map_list_of
+ (B200_PRODUCT_NI_ID, B200)
+ (B210_PRODUCT_NI_ID, B210)
+ (B205_PRODUCT_ID, B205)
+;
+
static const std::string B200_FW_FILE_NAME = "usrp_b200_fw.hex";
-//! Map the product ID (in the EEPROM) to a device type
-static const uhd::dict<boost::uint16_t, b200_type_t> B2X0_PRODUCT_ID = boost::assign::map_list_of
+//! Map the EEPROM product ID codes to the product
+static const uhd::dict<boost::uint16_t, b200_product_t> B2XX_PRODUCT_ID = boost::assign::map_list_of
(0x0001, B200)
(0x7737, B200)
(B200_PRODUCT_NI_ID, B200)
(0x0002, B210)
(0x7738, B210)
(B210_PRODUCT_NI_ID, B210)
+ (0x0003, B205)
+ (0x7739, B205)
;
-static const uhd::dict<b200_type_t, std::string> B2X0_STR_NAMES = boost::assign::map_list_of
+
+static const uhd::dict<b200_product_t, std::string> B2XX_STR_NAMES = boost::assign::map_list_of
(B200, "B200")
(B210, "B210")
+ (B205, "B200mini")
;
-static const uhd::dict<b200_type_t, std::string> B2X0_FPGA_FILE_NAME = boost::assign::map_list_of
+static const uhd::dict<b200_product_t, std::string> B2XX_FPGA_FILE_NAME = boost::assign::map_list_of
(B200, "usrp_b200_fpga.bin")
(B210, "usrp_b210_fpga.bin")
+ (B205, "usrp_b200mini_fpga.bin")
;
diff --git a/host/lib/usrp/b200/b200_image_loader.cpp b/host/lib/usrp/b200/b200_image_loader.cpp
index 9eaeeff63..e8fb8afea 100644
--- a/host/lib/usrp/b200/b200_image_loader.cpp
+++ b/host/lib/usrp/b200/b200_image_loader.cpp
@@ -35,8 +35,8 @@ using namespace uhd::transport;
namespace uhd{
-static b200_iface::sptr get_b200_iface(const image_loader::image_loader_args_t &image_loader_args,
- mboard_eeprom_t &mb_eeprom,
+static b200_iface::sptr get_b200_iface(const image_loader::image_loader_args_t& image_loader_args,
+ mboard_eeprom_t &mb_eeprom, usb_device_handle::sptr& handle,
bool user_specified){
std::vector<usb_device_handle::sptr> dev_handles = get_b200_device_handles(image_loader_args.args);
@@ -67,6 +67,7 @@ static b200_iface::sptr get_b200_iface(const image_loader::image_loader_args_t &
// At this point, we should have a single B2XX
if(applicable_dev_handles.size() == 1){
mb_eeprom = eeprom;
+ handle = applicable_dev_handles[0];
return iface;
}
else if(applicable_dev_handles.size() > 1){
@@ -76,7 +77,7 @@ static b200_iface::sptr get_b200_iface(const image_loader::image_loader_args_t &
BOOST_FOREACH(usb_device_handle::sptr dev_handle, applicable_dev_handles){
eeprom = mboard_eeprom_t(*b200_iface::make(usb_control::make(dev_handle,0)), "B200");
err_msg += str(boost::format(" * %s (serial=%s)\n")
- % B2X0_STR_NAMES.get(get_b200_type(mb_eeprom), "B2XX")
+ % B2XX_STR_NAMES.get(get_b200_product(dev_handle, mb_eeprom), "B2XX")
% mb_eeprom.get("serial"));
}
@@ -101,7 +102,8 @@ static bool b200_image_loader(const image_loader::image_loader_args_t &image_loa
// See if a B2x0 with the given args is found
mboard_eeprom_t mb_eeprom;
- b200_iface::sptr iface = get_b200_iface(image_loader_args, mb_eeprom, user_specified);
+ usb_device_handle::sptr handle;
+ b200_iface::sptr iface = get_b200_iface(image_loader_args, mb_eeprom, handle, user_specified);
if(!iface) return false; // No initialized B2x0 found
std::string fpga_path;
@@ -112,7 +114,7 @@ static bool b200_image_loader(const image_loader::image_loader_args_t &image_loa
* filename for us to use.
*/
std::string product = mb_eeprom.get("product");
- if(not B2X0_PRODUCT_ID.has_key(boost::lexical_cast<boost::uint16_t>(product))){
+ if(not B2XX_PRODUCT_ID.has_key(boost::lexical_cast<boost::uint16_t>(product))){
if(user_specified){
// The user specified a bad device but expects us to know what it is
throw uhd::runtime_error("Could not determine model. You must manually specify an FPGA image filename.");
@@ -122,13 +124,13 @@ static bool b200_image_loader(const image_loader::image_loader_args_t &image_loa
}
}
else{
- fpga_path = find_image_path(B2X0_FPGA_FILE_NAME.get(get_b200_type(mb_eeprom)));
+ fpga_path = find_image_path(B2XX_FPGA_FILE_NAME.get(get_b200_product(handle, mb_eeprom)));
}
}
else fpga_path = image_loader_args.fpga_path;
std::cout << boost::format("Unit: USRP %s (%s)")
- % B2X0_STR_NAMES.get(get_b200_type(mb_eeprom), "B2XX")
+ % B2XX_STR_NAMES.get(get_b200_product(handle, mb_eeprom), "B2XX")
% mb_eeprom.get("serial")
<< std::endl;
diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp
index f9e7eacfc..6bd49e013 100644
--- a/host/lib/usrp/b200/b200_impl.cpp
+++ b/host/lib/usrp/b200/b200_impl.cpp
@@ -45,14 +45,15 @@ using namespace uhd::transport;
static const boost::posix_time::milliseconds REENUMERATION_TIMEOUT_MS(3000);
+// B200 + B210:
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;
+ case AD9361_RX_BAND0: return 2.2e9; // Port C
+ case AD9361_RX_BAND1: return 4.0e9; // Port B
+ case AD9361_TX_BAND0: return 2.5e9; // Port B
default: return 0;
}
}
@@ -72,25 +73,77 @@ public:
}
};
+// B205
+class b205_ad9361_client_t : public ad9361_params {
+public:
+ ~b205_ad9361_client_t() {}
+ double get_band_edge(frequency_band_t band) {
+ switch (band) {
+ case AD9361_RX_BAND0: return 0; // Set these all to
+ case AD9361_RX_BAND1: return 0; // zero, so RF port A
+ case AD9361_TX_BAND0: return 0; // is used all the time
+ default: return 0; // On both Rx and Tx
+ }
+ }
+ 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 = 0x6;
+ delays.tx_clk_delay = 0;
+ delays.tx_data_delay = 0xF;
+ return delays;
+ }
+};
+
+/***********************************************************************
+ * Helpers
+ **********************************************************************/
+std::string check_option_valid(
+ const std::string &name,
+ const std::vector<std::string> &valid_options,
+ const std::string &option
+) {
+ if (std::find(valid_options.begin(), valid_options.end(), option) == valid_options.end()) {
+ throw uhd::runtime_error(str(
+ boost::format("Invalid option chosen for: %s")
+ % name
+ ));
+ }
+
+ return option;
+}
+
/***********************************************************************
* Discovery
**********************************************************************/
//! Look up the type of B-Series device we're currently running.
-// If the product ID stored in mb_eeprom is invalid, throws a
-// uhd::runtime_error.
-b200_type_t get_b200_type(const mboard_eeprom_t &mb_eeprom)
+// Throws a uhd::runtime_error if the USB PID and the product ID stored
+// in the MB EEPROM are invalid,
+b200_product_t get_b200_product(const usb_device_handle::sptr& handle, const mboard_eeprom_t &mb_eeprom)
{
+ // Try USB PID first
+ boost::uint16_t product_id = handle->get_product_id();
+ if (B2XX_PID_TO_PRODUCT.has_key(product_id))
+ return B2XX_PID_TO_PRODUCT[product_id];
+
+ // Try EEPROM product ID code second
if (mb_eeprom["product"].empty()) {
throw uhd::runtime_error("B200: Missing product ID on EEPROM.");
}
- boost::uint16_t product_id = boost::lexical_cast<boost::uint16_t>(mb_eeprom["product"]);
- if (not B2X0_PRODUCT_ID.has_key(product_id)) {
+ product_id = boost::lexical_cast<boost::uint16_t>(mb_eeprom["product"]);
+ if (not B2XX_PRODUCT_ID.has_key(product_id)) {
throw uhd::runtime_error(str(
boost::format("B200 unknown product code: 0x%04x")
% product_id
));
}
- return B2X0_PRODUCT_ID[product_id];
+ return B2XX_PRODUCT_ID[product_id];
}
std::vector<usb_device_handle::sptr> get_b200_device_handles(const device_addr_t &hint)
@@ -173,9 +226,10 @@ static device_addrs_t b200_find(const device_addr_t &hint)
new_addr["serial"] = handle->get_serial();
try {
// Turn the 16-Bit product ID into a string representation
- new_addr["product"] = B2X0_STR_NAMES[get_b200_type(mb_eeprom)];
+ new_addr["product"] = B2XX_STR_NAMES[get_b200_product(handle, mb_eeprom)];
} catch (const uhd::runtime_error &e) {
// No problem if this fails -- this is just device discovery, after all.
+ new_addr["product"] = "B2??";
}
//this is a found b200 when the hint serial and name match or blank
@@ -225,7 +279,9 @@ UHD_STATIC_BLOCK(register_b200_device)
* Structors
**********************************************************************/
b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::sptr &handle) :
+ _product(B200), // Some safe value
_revision(0),
+ _time_source(UNKNOWN),
_tick_rate(0.0) // Forces a clock initialization at startup
{
_tree = property_tree::make();
@@ -260,9 +316,10 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s
// Search for all supported PIDs limited to specified VID if only VID specified
else if (specified_vid)
{
- vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B200_PRODUCT_ID));
- vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B200_PRODUCT_NI_ID));
- vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B210_PRODUCT_NI_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid, B200_PRODUCT_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid, B205_PRODUCT_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid, B200_PRODUCT_NI_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid, B210_PRODUCT_NI_ID));
}
// Search for all supported VIDs limited to specified PID if only PID specified
else if (specified_pid)
@@ -273,9 +330,10 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s
// Search for all supported devices if neither VID nor PID specified
else
{
- vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID,B200_PRODUCT_ID));
- vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID,B200_PRODUCT_NI_ID));
- vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID,B210_PRODUCT_NI_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID, B200_PRODUCT_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID, B205_PRODUCT_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B200_PRODUCT_NI_ID));
+ vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B210_PRODUCT_NI_ID));
}
std::vector<usb_device_handle::sptr> device_list = usb_device_handle::get_device_list(vid_pid_pair_list);
@@ -309,9 +367,9 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s
std::string product_name;
try {
// This will throw if the product ID is invalid:
- _b200_type = get_b200_type(mb_eeprom);
- default_file_name = B2X0_FPGA_FILE_NAME.get(_b200_type);
- product_name = B2X0_STR_NAMES.get(_b200_type);
+ _product = get_b200_product(handle, mb_eeprom);
+ default_file_name = B2XX_FPGA_FILE_NAME.get(_product);
+ product_name = B2XX_STR_NAMES.get(_product);
} catch (const uhd::runtime_error &e) {
// The only reason we may let this pass is if the user specified
// the FPGA file name:
@@ -320,12 +378,15 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s
}
// In this case, we must provide a default product name:
product_name = "B200?";
- _b200_type = B200;
}
if (not mb_eeprom["revision"].empty()) {
_revision = boost::lexical_cast<size_t>(mb_eeprom["revision"]);
}
+ UHD_MSG(status) << "Detected Device: " << B2XX_STR_NAMES[_product] << std::endl;
+
+ _gpsdo_capable = (_product != B205);
+
////////////////////////////////////////////////////////////////////
// Set up frontend mapping
////////////////////////////////////////////////////////////////////
@@ -343,7 +404,7 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s
_fe2 = 0;
_gpio_state.swap_atr = 1;
// Unswapped setup:
- if (_b200_type == B200 and _revision >= 5) {
+ if (_product == B205 or (_product == B200 and _revision >= 5)) {
_fe1 = 0; //map radio0 to FE1
_fe2 = 1; //map radio1 to FE2
_gpio_state.swap_atr = 0; // ATRs for radio0 are mapped to FE1
@@ -411,34 +472,37 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s
////////////////////////////////////////////////////////////////////
// Create the GPSDO control
////////////////////////////////////////////////////////////////////
- _async_task_data->gpsdo_uart = b200_uart::make(_ctrl_transport, B200_TX_GPS_UART_SID);
- _async_task_data->gpsdo_uart->set_baud_divider(B200_BUS_CLOCK_RATE/115200);
- _async_task_data->gpsdo_uart->write_uart("\n"); //cause the baud and response to be setup
- boost::this_thread::sleep(boost::posix_time::seconds(1)); //allow for a little propagation
-
- if ((_local_ctrl->peek32(RB32_CORE_STATUS) & 0xff) != B200_GPSDO_ST_NONE)
+ if (_gpsdo_capable)
{
- UHD_MSG(status) << "Detecting internal GPSDO.... " << std::flush;
- try
- {
- _gps = gps_ctrl::make(_async_task_data->gpsdo_uart);
- }
- catch(std::exception &e)
- {
- UHD_MSG(error) << "An error occurred making GPSDO control: " << e.what() << std::endl;
- }
- if (_gps and _gps->gps_detected())
+ _async_task_data->gpsdo_uart = b200_uart::make(_ctrl_transport, B200_TX_GPS_UART_SID);
+ _async_task_data->gpsdo_uart->set_baud_divider(B200_BUS_CLOCK_RATE/115200);
+ _async_task_data->gpsdo_uart->write_uart("\n"); //cause the baud and response to be setup
+ boost::this_thread::sleep(boost::posix_time::seconds(1)); //allow for a little propagation
+
+ if ((_local_ctrl->peek32(RB32_CORE_STATUS) & 0xff) != B200_GPSDO_ST_NONE)
{
- //UHD_MSG(status) << "found" << std::endl;
- BOOST_FOREACH(const std::string &name, _gps->get_sensors())
+ UHD_MSG(status) << "Detecting internal GPSDO.... " << std::flush;
+ try
{
- _tree->create<sensor_value_t>(mb_path / "sensors" / name)
- .publish(boost::bind(&gps_ctrl::get_sensor, _gps, name));
+ _gps = gps_ctrl::make(_async_task_data->gpsdo_uart);
+ }
+ catch(std::exception &e)
+ {
+ UHD_MSG(error) << "An error occurred making GPSDO control: " << e.what() << std::endl;
+ }
+ if (_gps and _gps->gps_detected())
+ {
+ //UHD_MSG(status) << "found" << std::endl;
+ BOOST_FOREACH(const std::string &name, _gps->get_sensors())
+ {
+ _tree->create<sensor_value_t>(mb_path / "sensors" / name)
+ .publish(boost::bind(&gps_ctrl::get_sensor, _gps, name));
+ }
+ }
+ else
+ {
+ _local_ctrl->poke32(TOREG(SR_CORE_GPSDO_ST), B200_GPSDO_ST_NONE);
}
- }
- else
- {
- _local_ctrl->poke32(TOREG(SR_CORE_GPSDO_ST), B200_GPSDO_ST_NONE);
}
}
@@ -447,7 +511,7 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s
////////////////////////////////////////////////////////////////////
_tree->create<std::string>("/name").set("B-Series Device");
_tree->create<std::string>(mb_path / "name").set(product_name);
- _tree->create<std::string>(mb_path / "codename").set("Sasquatch");
+ _tree->create<std::string>(mb_path / "codename").set((_product == B205) ? "Pixie" : "Sasquatch");
////////////////////////////////////////////////////////////////////
// Create data transport
@@ -475,13 +539,20 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s
// 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);
+ if (_product != B205) {
+ _adf4001_iface = boost::make_shared<b200_ref_pll_ctrl>(_spi_iface);
+ }
////////////////////////////////////////////////////////////////////
// Init codec - turns on clocks
////////////////////////////////////////////////////////////////////
UHD_MSG(status) << "Initialize CODEC control..." << std::endl;
- ad9361_params::sptr client_settings = boost::make_shared<b200_ad9361_client_t>();
+ ad9361_params::sptr client_settings;
+ if (_product == B205) {
+ client_settings = boost::make_shared<b205_ad9361_client_t>();
+ } else {
+ 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();
@@ -564,15 +635,23 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s
}
//setup time source props
+ static const std::vector<std::string> time_sources = (_gpsdo_capable) ?
+ boost::assign::list_of("none")("internal")("external")("gpsdo") :
+ boost::assign::list_of("none")("internal")("external") ;
+ _tree->create<std::vector<std::string> >(mb_path / "time_source" / "options")
+ .set(time_sources);
_tree->create<std::string>(mb_path / "time_source" / "value")
+ .coerce(boost::bind(&check_option_valid, "time source", time_sources, _1))
.subscribe(boost::bind(&b200_impl::update_time_source, this, _1));
- 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
+ static const std::vector<std::string> clock_sources = (_gpsdo_capable) ?
+ boost::assign::list_of("internal")("external")("gpsdo") :
+ boost::assign::list_of("internal")("external") ;
+ _tree->create<std::vector<std::string> >(mb_path / "clock_source" / "options")
+ .set(clock_sources);
_tree->create<std::string>(mb_path / "clock_source" / "value")
+ .coerce(boost::bind(&check_option_valid, "clock source", clock_sources, _1))
.subscribe(boost::bind(&b200_impl::update_clock_source, this, _1));
- static const std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("gpsdo");
- _tree->create<std::vector<std::string> >(mb_path / "clock_source" / "options").set(clock_sources);
////////////////////////////////////////////////////////////////////
// front panel gpio
@@ -870,12 +949,14 @@ void b200_impl::check_fpga_compat(void)
if (signature != 0xACE0BA5E) throw uhd::runtime_error(
"b200::check_fpga_compat signature register readback failed");
- if (compat_major != B200_FPGA_COMPAT_NUM){
+ const boost::uint16_t expected = (_product == B205 ? B205_FPGA_COMPAT_NUM : B200_FPGA_COMPAT_NUM);
+ if (compat_major != expected)
+ {
throw uhd::runtime_error(str(boost::format(
"Expected FPGA compatibility number %d, but got %d:\n"
"The FPGA build is not compatible with the host code build.\n"
"%s"
- ) % int(B200_FPGA_COMPAT_NUM) % compat_major % print_utility_error("uhd_images_downloader.py")));
+ ) % int(expected) % compat_major % print_utility_error("uhd_images_downloader.py")));
}
_tree->create<std::string>("/mboards/0/fpga_version").set(str(boost::format("%u.%u")
% compat_major % compat_minor));
@@ -913,35 +994,92 @@ void b200_impl::set_fp_gpio(gpio_core_200::sptr gpio, const gpio_attr_t attr, co
void b200_impl::update_clock_source(const std::string &source)
{
- // present the PLL with a valid 10 MHz signal before switching its reference
- _gpio_state.ref_sel = (source == "gpsdo")? 1 : 0;
- this->update_gpio_state();
+ // For B205, ref_sel selects whether or not to lock to the external clock source
+ if (_product == B205)
+ {
+ if (source == "external" and _time_source == EXTERNAL)
+ {
+ throw uhd::value_error("external reference cannot be both a clock source and a time source");
+ }
- if (source == "internal"){
- _adf4001_iface->set_lock_to_ext_ref(false);
+ if (source == "internal")
+ {
+ if (_gpio_state.ref_sel != 0)
+ {
+ _gpio_state.ref_sel = 0;
+ this->update_gpio_state();
+ }
+ }
+ else if (source == "external")
+ {
+ if (_gpio_state.ref_sel != 1)
+ {
+ _gpio_state.ref_sel = 1;
+ this->update_gpio_state();
+ }
+ }
+ else
+ {
+ throw uhd::key_error("update_clock_source: unknown source: " + source);
+ }
+ return;
}
- else if ((source == "external")
- or (source == "gpsdo")){
+ // For all other devices, ref_sel selects the external or gpsdo clock source
+ // and the ADF4001 selects whether to lock to it or not
+ if (source == "internal")
+ {
+ _adf4001_iface->set_lock_to_ext_ref(false);
+ }
+ else if (source == "external")
+ {
+ if (_gpio_state.ref_sel != 0)
+ {
+ _gpio_state.ref_sel = 0;
+ this->update_gpio_state();
+ }
_adf4001_iface->set_lock_to_ext_ref(true);
- } else {
+ }
+ else if (_gps and source == "gpsdo")
+ {
+ if (_gpio_state.ref_sel != 1)
+ {
+ _gpio_state.ref_sel = 1;
+ this->update_gpio_state();
+ }
+ _adf4001_iface->set_lock_to_ext_ref(true);
+ }
+ else
+ {
throw uhd::key_error("update_clock_source: unknown source: " + source);
}
}
void b200_impl::update_time_source(const std::string &source)
{
- boost::uint32_t value = 0;
+ if (_product == B205 and source == "external" and _gpio_state.ref_sel == 1)
+ {
+ throw uhd::value_error("external reference cannot be both a time source and a clock source");
+ }
+
+ // We assume source is valid for this device (if it's gone through
+ // the prop three, then it definitely is thanks to our coercer)
+ time_source_t value;
if (source == "none")
- value = 3;
+ value = NONE;
else if (source == "internal")
- value = 2;
+ value = INTERNAL;
else if (source == "external")
- value = 1;
- else if (source == "gpsdo")
- value = 0;
- else throw uhd::key_error("update_time_source: unknown source: " + source);
- _local_ctrl->poke32(TOREG(SR_CORE_PPS_SEL), value);
+ value = EXTERNAL;
+ else if (_gps and source == "gpsdo")
+ value = GPSDO;
+ else
+ throw uhd::key_error("update_time_source: unknown source: " + source);
+ if (_time_source != value)
+ {
+ _local_ctrl->poke32(TOREG(SR_CORE_PPS_SEL), value);
+ _time_source = value;
+ }
}
/***********************************************************************
@@ -950,6 +1088,11 @@ void b200_impl::update_time_source(const std::string &source)
void b200_impl::update_bandsel(const std::string& which, double freq)
{
+ // B205 does not have bandsels
+ if (_product == B205) {
+ return;
+ }
+
if(which[0] == 'R') {
if(freq < 2.2e9) {
_gpio_state.rx_bandsel_a = 0;
diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp
index 8f527221f..b291f8e5c 100644
--- a/host/lib/usrp/b200/b200_impl.hpp
+++ b/host/lib/usrp/b200/b200_impl.hpp
@@ -50,6 +50,7 @@
static const boost::uint8_t B200_FW_COMPAT_NUM_MAJOR = 8;
static const boost::uint8_t B200_FW_COMPAT_NUM_MINOR = 0;
static const boost::uint16_t B200_FPGA_COMPAT_NUM = 10;
+static const boost::uint16_t B205_FPGA_COMPAT_NUM = 1;
static const double B200_BUS_CLOCK_RATE = 100e6;
static const boost::uint32_t B200_GPSDO_ST_NONE = 0x83;
static const size_t B200_MAX_RATE_USB2 = 53248000; // bytes/s
@@ -94,11 +95,12 @@ static const unsigned char B200_USB_DATA_SEND_ENDPOINT = 2;
static std::vector<uhd::transport::usb_device_handle::vid_pid_pair_t> b200_vid_pid_pairs =
boost::assign::list_of
(uhd::transport::usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID, B200_PRODUCT_ID))
+ (uhd::transport::usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID, B205_PRODUCT_ID))
(uhd::transport::usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B200_PRODUCT_NI_ID))
(uhd::transport::usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B210_PRODUCT_NI_ID))
;
-b200_type_t get_b200_type(const uhd::usrp::mboard_eeprom_t &mb_eeprom);
+b200_product_t get_b200_product(const uhd::transport::usb_device_handle::sptr& handle, const uhd::usrp::mboard_eeprom_t &mb_eeprom);
std::vector<uhd::transport::usb_device_handle::sptr> get_b200_device_handles(const uhd::device_addr_t &hint);
//! Implementation guts
@@ -122,8 +124,9 @@ public:
void check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const std::string &direction = "");
private:
- b200_type_t _b200_type;
- size_t _revision;
+ b200_product_t _product;
+ size_t _revision;
+ bool _gpsdo_capable;
//controllers
b200_iface::sptr _iface;
@@ -216,6 +219,8 @@ private:
}
} _gpio_state;
+ enum time_source_t {GPSDO=0,EXTERNAL=1,INTERNAL=2,NONE=3,UNKNOWN=4} _time_source;
+
void update_gpio_state(void);
void reset_codec_dcm(void);
diff --git a/host/lib/usrp/b200/b200_io_impl.cpp b/host/lib/usrp/b200/b200_io_impl.cpp
index 20807bdd4..4aa1a46af 100644
--- a/host/lib/usrp/b200/b200_io_impl.cpp
+++ b/host/lib/usrp/b200/b200_io_impl.cpp
@@ -228,7 +228,7 @@ uhd::usrp::subdev_spec_t b200_impl::coerce_subdev_spec(const uhd::usrp::subdev_s
//
// Any other spec is probably illegal and will be caught by
// validate_subdev_spec().
- if (spec.size() and _b200_type == B200 and spec[0].sd_name == "B") {
+ if (spec.size() and (_product == B200 or _product == B205) and spec[0].sd_name == "B") {
spec[0].sd_name = "A";
}
return spec;