diff options
Diffstat (limited to 'host/lib/usrp/b200')
| -rw-r--r-- | host/lib/usrp/b200/b200_iface.hpp | 45 | ||||
| -rw-r--r-- | host/lib/usrp/b200/b200_impl.cpp | 111 | ||||
| -rw-r--r-- | host/lib/usrp/b200/b200_impl.hpp | 14 | 
3 files changed, 113 insertions, 57 deletions
| diff --git a/host/lib/usrp/b200/b200_iface.hpp b/host/lib/usrp/b200/b200_iface.hpp index 83adfdd64..1d123439a 100644 --- a/host/lib/usrp/b200/b200_iface.hpp +++ b/host/lib/usrp/b200/b200_iface.hpp @@ -1,5 +1,5 @@  // -// Copyright 2012-2013 Ettus Research LLC +// Copyright 2012-2013,2015 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 @@ -21,19 +21,48 @@  #include <stdint.h>  #include <uhd/transport/usb_control.hpp>  #include <uhd/types/serial.hpp> //i2c iface +#include <uhd/types/dict.hpp> +#include <boost/assign/list_of.hpp>  #include <boost/shared_ptr.hpp>  #include <boost/utility.hpp>  #include "ad9361_ctrl.hpp" -const static boost::uint16_t B200_VENDOR_ID  = 0x2500; -const static boost::uint16_t B200_PRODUCT_ID = 0x0020; -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; +enum b200_type_t { +    B200, +    B210 +}; + +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 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;  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"; + +//! 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 +        (0x0001,             B200) +        (0x7737,             B200) +        (B200_PRODUCT_NI_ID, B200) +        (0x0002,             B210) +        (0x7738,             B210) +        (B210_PRODUCT_NI_ID, B210) +; + +static const uhd::dict<b200_type_t, std::string> B2X0_STR_NAMES = boost::assign::map_list_of +        (B200, "B200") +        (B210, "B210") +; + +static const uhd::dict<b200_type_t, std::string> B2X0_FPGA_FILE_NAME = boost::assign::map_list_of +        (B200, "usrp_b200_fpga.bin") +        (B210, "usrp_b210_fpga.bin") +; +  class UHD_API b200_iface: boost::noncopyable, public virtual uhd::i2c_iface {  public: diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index e567ff434..273153c16 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -43,10 +43,6 @@ using namespace uhd::transport;  static const boost::posix_time::milliseconds REENUMERATION_TIMEOUT_MS(3000); -//! mapping of frontend to radio perif index -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() {} @@ -77,6 +73,24 @@ public:  /***********************************************************************   * 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. +static b200_type_t get_b200_type(const mboard_eeprom_t &mb_eeprom) +{ +    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)) { +        throw uhd::runtime_error(str( +            boost::format("B200 unknown product code: 0x%04x") +            % product_id +        )); +    } +    return B2X0_PRODUCT_ID[product_id]; +} +  static device_addrs_t b200_find(const device_addr_t &hint)  {      device_addrs_t b200_addrs; @@ -152,20 +166,14 @@ static device_addrs_t b200_find(const device_addr_t &hint)              new_addr["type"] = "b200";              new_addr["name"] = mb_eeprom["name"];              new_addr["serial"] = handle->get_serial(); -            if (not mb_eeprom["product"].empty()) -            { -                switch (boost::lexical_cast<boost::uint16_t>(mb_eeprom["product"])) -                { -                case 0x0001: -                case 0x7737: -                    new_addr["product"] = "B200"; -                    break; -                case 0x7738: -                case 0x0002: -                    new_addr["product"] = "B210"; -                    break; -                default: UHD_MSG(error) << "B200 unknown product code: " << mb_eeprom["product"] << std::endl; -                } +            try { +                // Turn the 16-Bit product ID into a string representation +                new_addr["product"] = B2X0_STR_NAMES[get_b200_type(mb_eeprom)]; +            } catch (const uhd::runtime_error &e) { +                // No problem if this fails -- this is just device discovery, after all. +                UHD_MSG(error) << e.what() << std::endl; +                // Skip this loop. +                continue;              }              //this is a found b200 when the hint serial and name match or blank              if ( @@ -238,32 +246,41 @@ b200_impl::b200_impl(const device_addr_t &device_addr) :          .subscribe(boost::bind(&b200_impl::set_mb_eeprom, this, _1));      //////////////////////////////////////////////////////////////////// -    // Load the FPGA image, then reset GPIF +    // Identify the device type      ////////////////////////////////////////////////////////////////////      std::string default_file_name; -    std::string product_name = "B200?"; -    if (not mb_eeprom["product"].empty()) -    { -        switch (boost::lexical_cast<boost::uint16_t>(mb_eeprom["product"])) -        { -        case 0x0001: -        case 0x7737: -            product_name = "B200"; -            default_file_name = B200_FPGA_FILE_NAME; -            break; -        case 0x7738: -        case 0x0002: -            product_name = "B210"; -            default_file_name = B210_FPGA_FILE_NAME; -            break; -        default: UHD_MSG(error) << "B200 unknown product code: " << mb_eeprom["product"] << std::endl; +    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); +    } catch (const uhd::runtime_error &e) { +        // The only reason we may let this pass is if the user specified +        // the FPGA file name: +        if (not device_addr.has_key("fpga")) { +            throw e;          } +        // In this case, we must provide a default product name: +        product_name = "B200?"; +        _b200_type = B200;      } -    if (default_file_name.empty()) + +    //set up frontend mapping +    _fe1 = 1; +    _fe2 = 0; +    if (_b200_type == B200 and +        not mb_eeprom["revision"].empty() and +        boost::lexical_cast<size_t>(mb_eeprom["revision"]) >= 5)      { -        UHD_ASSERT_THROW(device_addr.has_key("fpga")); +        _fe1 = 0;                   //map radio0 to FE1 +        _fe2 = 1;                   //map radio1 to FE2 +        _gpio_state.atr_sel = 1;    //map radio0 ATR pins to FE2      } +    //////////////////////////////////////////////////////////////////// +    // Load the FPGA image, then reset GPIF +    ////////////////////////////////////////////////////////////////////      //extract the FPGA path for the B200      std::string b200_fpga_image = find_image_path(          device_addr.has_key("fpga")? device_addr["fpga"] : default_file_name @@ -316,7 +333,6 @@ b200_impl::b200_impl(const device_addr_t &device_addr) :      /* Initialize the GPIOs, set the default bandsels to the lower range. Note       * that calling update_bandsel calls update_gpio_state(). */ -    _gpio_state = gpio_state();      update_bandsel("RX", 800e6);      update_bandsel("TX", 850e6); @@ -628,7 +644,7 @@ void b200_impl::setup_radio(const size_t dspno)      for(size_t direction = 0; direction < 2; direction++)      {          const std::string x = direction? "rx" : "tx"; -        const std::string key = std::string((direction? "RX" : "TX")) + std::string(((dspno == FE1)? "1" : "2")); +        const std::string key = std::string((direction? "RX" : "TX")) + std::string(((dspno == _fe1)? "1" : "2"));          const fs_path rf_fe_path = mb_path / "dboards" / "A" / (x+"_frontends") / (dspno? "B" : "A");          _tree->create<std::string>(rf_fe_path / "name").set("FE-"+key); @@ -900,6 +916,7 @@ void b200_impl::update_bandsel(const std::string& which, double freq)  void b200_impl::update_gpio_state(void)  {      const boost::uint32_t misc_word = 0 +        | (_gpio_state.atr_sel << 8)          | (_gpio_state.tx_bandsel_a << 7)          | (_gpio_state.tx_bandsel_b << 6)          | (_gpio_state.rx_bandsel_a << 5) @@ -924,9 +941,9 @@ void b200_impl::reset_codec_dcm(void)  void b200_impl::update_atrs(void)  { -    if (_radio_perifs.size() > FE1 and _radio_perifs[FE1].atr) +    if (_radio_perifs.size() > _fe1 and _radio_perifs[_fe1].atr)      { -        radio_perifs_t &perif = _radio_perifs[FE1]; +        radio_perifs_t &perif = _radio_perifs[_fe1];          const bool enb_rx = bool(perif.rx_streamer.lock());          const bool enb_tx = bool(perif.tx_streamer.lock());          const bool is_rx2 = perif.ant_rx2; @@ -942,9 +959,9 @@ void b200_impl::update_atrs(void)          atr->set_atr_reg(dboard_iface::ATR_REG_TX_ONLY, txonly);          atr->set_atr_reg(dboard_iface::ATR_REG_FULL_DUPLEX, fd);      } -    if (_radio_perifs.size() > FE2 and _radio_perifs[FE2].atr) +    if (_radio_perifs.size() > _fe2 and _radio_perifs[_fe2].atr)      { -        radio_perifs_t &perif = _radio_perifs[FE2]; +        radio_perifs_t &perif = _radio_perifs[_fe2];          const bool enb_rx = bool(perif.rx_streamer.lock());          const bool enb_tx = bool(perif.tx_streamer.lock());          const bool is_rx2 = perif.ant_rx2; @@ -972,10 +989,10 @@ void b200_impl::update_antenna_sel(const size_t which, const std::string &ant)  void b200_impl::update_enables(void)  {      //extract settings from state variables -    const bool enb_tx1 = (_radio_perifs.size() > FE1) and bool(_radio_perifs[FE1].tx_streamer.lock()); -    const bool enb_rx1 = (_radio_perifs.size() > FE1) and bool(_radio_perifs[FE1].rx_streamer.lock()); -    const bool enb_tx2 = (_radio_perifs.size() > FE2) and bool(_radio_perifs[FE2].tx_streamer.lock()); -    const bool enb_rx2 = (_radio_perifs.size() > FE2) and bool(_radio_perifs[FE2].rx_streamer.lock()); +    const bool enb_tx1 = (_radio_perifs.size() > _fe1) and bool(_radio_perifs[_fe1].tx_streamer.lock()); +    const bool enb_rx1 = (_radio_perifs.size() > _fe1) and bool(_radio_perifs[_fe1].rx_streamer.lock()); +    const bool enb_tx2 = (_radio_perifs.size() > _fe2) and bool(_radio_perifs[_fe2].tx_streamer.lock()); +    const bool enb_rx2 = (_radio_perifs.size() > _fe2) and bool(_radio_perifs[_fe2].rx_streamer.lock());      const size_t num_rx = (enb_rx1?1:0) + (enb_rx2?1:0);      const size_t num_tx = (enb_tx1?1:0) + (enb_tx2?1:0);      const bool mimo = num_rx == 2 or num_tx == 2; diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp index 396819f9a..8d0c637d7 100644 --- a/host/lib/usrp/b200/b200_impl.hpp +++ b/host/lib/usrp/b200/b200_impl.hpp @@ -47,7 +47,7 @@  #include "recv_packet_demuxer_3000.hpp"  static const boost::uint8_t  B200_FW_COMPAT_NUM_MAJOR = 7;  static const boost::uint8_t  B200_FW_COMPAT_NUM_MINOR = 0; -static const boost::uint16_t B200_FPGA_COMPAT_NUM = 4; +static const boost::uint16_t B200_FPGA_COMPAT_NUM = 5;  static const double          B200_BUS_CLOCK_RATE = 100e6;  static const double          B200_DEFAULT_TICK_RATE = 32e6;  static const double          B200_DEFAULT_FREQ = 100e6; // Hz @@ -101,6 +101,8 @@ public:      void check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const char* direction = NULL);  private: +    b200_type_t _b200_type; +      //controllers      b200_iface::sptr _iface;      radio_ctrl_core_3000::sptr _local_ctrl; @@ -161,6 +163,13 @@ private:      };      std::vector<radio_perifs_t> _radio_perifs; +    //mapping of AD936x frontends (FE1 and FE2) to radio perif index (0 and 1) +    //FE1 corresponds to the ports labeled "RF B" on the B200/B210 +    //FE2 corresponds to the ports labeled "RF A" on the B200/B210 +    //the mapping is product and revision specific +    size_t _fe1; +    size_t _fe2; +      /*! \brief Setup the DSP chain for one radio front-end.       *       */ @@ -168,7 +177,7 @@ private:      void handle_overflow(const size_t radio_index);      struct gpio_state { -        boost::uint32_t  tx_bandsel_a, tx_bandsel_b, rx_bandsel_a, rx_bandsel_b, rx_bandsel_c, codec_arst, mimo, ref_sel; +        boost::uint32_t  tx_bandsel_a, tx_bandsel_b, rx_bandsel_a, rx_bandsel_b, rx_bandsel_c, codec_arst, mimo, ref_sel, atr_sel;          gpio_state() {              tx_bandsel_a = 0; @@ -179,6 +188,7 @@ private:              codec_arst = 0;              mimo = 0;              ref_sel = 0; +            atr_sel = 0;          }      } _gpio_state; | 
