diff options
author | michael-west <michael.west@ettus.com> | 2015-08-17 14:41:46 -0700 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2015-08-17 18:10:09 -0700 |
commit | 92539438c228b784a0254d9b2aae143686fa672e (patch) | |
tree | 7c50343a852d64956ba77e89f5029d5863768428 | |
parent | 868cbac336eb4e4191079ba08c97fa9b40890157 (diff) | |
download | uhd-92539438c228b784a0254d9b2aae143686fa672e.tar.gz uhd-92539438c228b784a0254d9b2aae143686fa672e.tar.bz2 uhd-92539438c228b784a0254d9b2aae143686fa672e.zip |
B2XX: Added B200mini support
-rw-r--r-- | host/docs/usrp_b200.dox | 89 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_iface.hpp | 29 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_image_loader.cpp | 16 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_impl.cpp | 283 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_impl.hpp | 11 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_io_impl.cpp | 2 | ||||
-rw-r--r-- | host/lib/usrp/common/ad9361_ctrl.cpp | 5 | ||||
-rw-r--r-- | host/lib/usrp/common/ad9361_ctrl.hpp | 2 | ||||
-rw-r--r-- | host/lib/usrp/common/ad9361_driver/ad9361_device.cpp | 14 | ||||
-rw-r--r-- | host/lib/usrp/common/ad9361_driver/ad9361_device.h | 2 | ||||
-rw-r--r-- | host/lib/usrp/e300/e300_remote_codec_ctrl.cpp | 5 | ||||
-rw-r--r-- | host/utils/b2xx_fx3_utils.cpp | 3 |
12 files changed, 356 insertions, 105 deletions
diff --git a/host/docs/usrp_b200.dox b/host/docs/usrp_b200.dox index 1da7f2aee..6c4e52dd6 100644 --- a/host/docs/usrp_b200.dox +++ b/host/docs/usrp_b200.dox @@ -2,7 +2,7 @@ \tableofcontents -\section b200_features Comparative features list - B200/B210 +\section b200_features Comparative features list - B200/B210/B200mini - Hardware Capabilities: - Integrated RF frontend (70 MHz - 6 GHz) @@ -10,16 +10,20 @@ - External 10 MHz reference input - Configurable clock rate - Variable analog bandwidth (200 kHz - 56 MHz) - - Internal GPSDO option (see \subpage page_gpsdo_b2x0 for details) - - B210 Only: - - MICTOR Debug Connector - - JTAG Connector - - Revision 6 with GPIO header + - GPIO header + - [B200/B210] Internal GPSDO option (see \subpage page_gpsdo_b2x0 for details) + - [B210/B200mini] JTAG Connector + - [B210] MICTOR Debug Connector - FPGA Capabilities: - Timed commands in FPGA - Timed sampling in FPGA -\section b200_imgs Specify a Non-standard Image +\section b200_power Power +In most cases, USB 3.0 bus power will be sufficient to power the device. +If using USB 2.0 or a internal GPSDO, an external power supply or a cable designed +to pull power from 2 USB ports (USB 3.0 dual A to micro-B or B) must be used. + +\section b200_imgs Specifying a Non-standard Image UHD software will automatically select the USRP B2X0 images from the installed images package. The image selection can be overridden with the @@ -79,7 +83,7 @@ The B200 features an integrated RF frontend. \subsection b200_fe_tuning Frontend tuning The RF frontend has individually tunable receive and transmit chains. On -the B200, there is one transmit and one receive RF frontend. On the +the B200 and B200 mini, there is one transmit and one receive RF frontend. On the B210, both transmit and receive can be used in a MIMO configuration. For the MIMO case, both receive frontends share the RX LO, and both transmit frontends share the TX LO. Each LO is tunable between 50 MHz and 6 GHz. @@ -114,7 +118,7 @@ rate. \subsection LED Indicators -Below is a table of the LED indicators and their meanings: +Below is a table of the B200/B210 LED indicators and their meanings: <table> <tr> @@ -150,6 +154,36 @@ Below is a table of the LED indicators and their meanings: </tr> </table> +Below is a table of the B200mini LED indicators and their meanings: + +<table> + <tr> + <th>Component ID</th><th>Description</th><th>Details</th> + </tr> + <tr> + <td>PWR LED</td> <td>Power Indicator</td> <td>off = no power applied<br> + on = power applied (external or USB)</td> + </tr> + <tr> + <td>TRX LED</td> <td>TX/RX Activity</td> <td>off = no activity<br> + green = receiving<br> + red = transmitting<br> + orange = switching between transmitting and receiving</td> + </tr> + <tr> + <td>RX2 LED</td> <td>RX2 Activity</td> <td>off = no activity<br> + green = receiving</td> + </tr> + <tr> + <td>S0 LED</td> <td>Reference Lock</td> <td>off = no activity + green = locked</td> + </tr> + <tr> + <td>S1 LED</td> <td>Reference Present</td> <td>off = reference level low or not present<br> + green = reference level high</td> + </tr> +</table> + TX LED indicators are on when transimitting data and off when no samples are available to transmit. RX LED indicators are on when sending samples to the host and off when unable to do so. This means that TX/RX activity LED @@ -160,7 +194,7 @@ well. \subsection External Connections -Below is a table showing the external connections and respective power information: +Below is a table showing the B200/B210 external connections and respective power information: <table> <tr> @@ -197,15 +231,36 @@ Below is a table showing the external connections and respective power informati </tr> </table> +Below is a table showing the B200mini external connections and respective power information: + +<table> +<tr> + <th>Component ID</th> <th>Description</th> <th> Details</th> +</tr> +<tr> + <td>USB3</td> <td>USB Connector</td> <td>USB 3.0</td> +</tr> +<tr> + <td>J1</td> <td>TRX</td> <td>TX power +20dBm max<br> + RX power -15dBm max</td> +</tr> +<tr> + <td>J2</td> <td>RX2</td> <td>RX power -15dBm max</td> +</tr> +<tr> + <td>J3</td> <td>External 10MHz/PPS Reference</td> <td>+15 dBm max</td +</tr> +</table> + \subsection b200_switches On-Board Connectors and Switches -Below is a table showing the on-board connectors and switches: +Below is a table showing the B200/B210 on-board connectors and switches: Component ID | Description | Details ------------------------|----------------------------|--------------------------------------------------- J502<sup>1</sup> | Mictor Connector | Interface to FPGA for I/O and inspection. J503<sup>1</sup> | JTAG Header | Interface to FPGA for programming and debugging. - J504<sup>2</sup> | GPIO Header | Header running to the FPGA for GPIO purposes. + J504<sup>2</sup> | GPIO Header | Header connected to the FPGA for GPIO purposes. S700 | FX3 Hard Reset Switch | Resets the USB controller / System reset U100 | GPSDO socket | Interface to GPS disciplined reference oscillator @@ -213,6 +268,16 @@ Component ID | Description | Details <sup>2</sup> Only since rev. 6 (green board) +Below is a table showing the B200mini on-board connectors and switches: + +Component ID | Description | Details +------------------------|----------------------------|--------------------------------------------------- + J5 | JTAG Header | Interface to FPGA for programming and debugging. + J6<sup>1</sup> | GPIO Header | Header connected to the FPGA for GPIO purposes. + SW1 | FX3 Hard Reset Switch | Resets the USB controller / System reset + + <sup>1</sup> GPIO pinout is 1=3.3V, 2=GPIO_0, 3=GPIO_1, 4=GPIO_2, 5=GPIO_3, 6=GND, 7=3.3V, 8=GPIO_4, 9=GPIO_5, 10=,GPIO_6 11=GPIO_7, 12=GND + */ // vim:ft=doxygen: 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; diff --git a/host/lib/usrp/common/ad9361_ctrl.cpp b/host/lib/usrp/common/ad9361_ctrl.cpp index 2d9f297b3..54f0fcdbf 100644 --- a/host/lib/usrp/common/ad9361_ctrl.cpp +++ b/host/lib/usrp/common/ad9361_ctrl.cpp @@ -251,6 +251,11 @@ public: _device.set_filter(direction, chain, filter_name, filter); } + void output_digital_test_tone(bool enb) + { + _device.digital_test_tone(enb); + } + private: static ad9361_device_t::direction_t _get_direction_from_antenna(const std::string& antenna) { diff --git a/host/lib/usrp/common/ad9361_ctrl.hpp b/host/lib/usrp/common/ad9361_ctrl.hpp index 044265422..5c438ee9c 100644 --- a/host/lib/usrp/common/ad9361_ctrl.hpp +++ b/host/lib/usrp/common/ad9361_ctrl.hpp @@ -154,6 +154,8 @@ public: //! Write back a filter virtual void set_filter(const std::string &which, const std::string &filter_name, const filter_info_base::sptr) = 0; + + virtual void output_digital_test_tone(bool enb) = 0; }; }} diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp index c3bc2d32b..0a8a61575 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp +++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp @@ -1286,16 +1286,16 @@ double ad9361_device_t::_tune_helper(direction_t direction, const double value) /* Set band-specific settings. */ if (value < _client_params->get_band_edge(AD9361_RX_BAND0)) { - _regs.inputsel = (_regs.inputsel & 0xC0) | 0x30; + _regs.inputsel = (_regs.inputsel & 0xC0) | 0x30; // Port C, balanced } else if ((value >= _client_params->get_band_edge(AD9361_RX_BAND0)) && (value < _client_params->get_band_edge(AD9361_RX_BAND1))) { - _regs.inputsel = (_regs.inputsel & 0xC0) | 0x0C; + _regs.inputsel = (_regs.inputsel & 0xC0) | 0x0C; // Port B, balanced } else if ((value >= _client_params->get_band_edge(AD9361_RX_BAND1)) && (value <= 6e9)) { - _regs.inputsel = (_regs.inputsel & 0xC0) | 0x03; + _regs.inputsel = (_regs.inputsel & 0xC0) | 0x03; // Port A, balanced } else { throw uhd::runtime_error("[ad9361_device_t] [_tune_helper] INVALID_CODE_PATH"); } @@ -2127,7 +2127,7 @@ double ad9361_device_t::set_gain(direction_t direction, chain_t chain, const dou } } -void ad9361_device_t::output_test_tone() +void ad9361_device_t::output_test_tone() // On RF side! { boost::lock_guard<boost::recursive_mutex> lock(_mutex); /* Output a 480 kHz tone at 800 MHz */ @@ -2137,6 +2137,12 @@ void ad9361_device_t::output_test_tone() _io_iface->poke8(0x3FE, 0x3F); } +void ad9361_device_t::digital_test_tone(bool enb) // Digital output +{ + boost::lock_guard<boost::recursive_mutex> lock(_mutex); + _io_iface->poke8(0x3F4, 0x02 | (enb ? 0x01 : 0x00)); +} + void ad9361_device_t::data_port_loopback(const bool loopback_enabled) { boost::lock_guard<boost::recursive_mutex> lock(_mutex); diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.h b/host/lib/usrp/common/ad9361_driver/ad9361_device.h index efd0f017c..66bc2e8b9 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_device.h +++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.h @@ -115,6 +115,8 @@ public: /* Make AD9361 output its test tone. */ void output_test_tone(); + void digital_test_tone(bool enb); // Digital output + /* Turn on/off AD9361's TX port --> RX port loopback. */ void data_port_loopback(const bool loopback_enabled); diff --git a/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp b/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp index 1e0895393..be98f4027 100644 --- a/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp +++ b/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp @@ -242,6 +242,11 @@ public: UHD_MSG(warning) << "Attempting to set filter on E300 in network mode." << std::endl; } + void output_digital_test_tone(bool enb) + { + UHD_THROW_INVALID_CODE_PATH(); + } + private: void _transact() { { diff --git a/host/utils/b2xx_fx3_utils.cpp b/host/utils/b2xx_fx3_utils.cpp index bc14932f1..a3eaf862a 100644 --- a/host/utils/b2xx_fx3_utils.cpp +++ b/host/utils/b2xx_fx3_utils.cpp @@ -52,9 +52,10 @@ const static vid_pid_t known_vid_pids[] = { {FX3_VID, FX3_DEFAULT_PID}, {FX3_VID, FX3_REENUM_PID}, {B200_VENDOR_ID, B200_PRODUCT_ID}, + {B200_VENDOR_ID, B205_PRODUCT_ID}, {B200_VENDOR_NI_ID, B200_PRODUCT_NI_ID}, {B200_VENDOR_NI_ID, B210_PRODUCT_NI_ID} - }; +}; const static std::vector<vid_pid_t> known_vid_pid_vector(known_vid_pids, known_vid_pids + (sizeof(known_vid_pids) / sizeof(known_vid_pids[0]))); static const size_t EEPROM_INIT_VALUE_VECTOR_SIZE = 8; |