diff options
| author | Mark Meserve <mark.meserve@ni.com> | 2017-08-09 15:17:44 -0700 | 
|---|---|---|
| committer | Martin Braun <martin.braun@ettus.com> | 2017-12-22 15:04:00 -0800 | 
| commit | 309a2f04e3da6667bc44c78121064b2d03e24e75 (patch) | |
| tree | 08b453917053ac0a445ee261c694a706d9f5e180 | |
| parent | 8ee3da3ef9b812eda2ac3269927191e09916dc3c (diff) | |
| download | uhd-309a2f04e3da6667bc44c78121064b2d03e24e75.tar.gz uhd-309a2f04e3da6667bc44c78121064b2d03e24e75.tar.bz2 uhd-309a2f04e3da6667bc44c78121064b2d03e24e75.zip  | |
mg: General fixes
- Make DB probe-able
- Add RPC client
| -rw-r--r-- | host/include/uhd/rfnoc/blocks/radio_magnesium.xml | 2 | ||||
| -rw-r--r-- | host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.cpp | 200 | ||||
| -rw-r--r-- | host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.hpp | 21 | ||||
| -rw-r--r-- | host/lib/usrp/mpmd/mpmd_impl.cpp | 7 | ||||
| -rw-r--r-- | mpm/include/mpm/ad937x/ad937x_ctrl.hpp | 5 | ||||
| -rw-r--r-- | mpm/lib/mykonos/ad937x_ctrl.cpp | 17 | ||||
| -rw-r--r-- | mpm/lib/mykonos/ad937x_device.cpp | 222 | ||||
| -rw-r--r-- | mpm/lib/mykonos/ad937x_device.hpp | 20 | ||||
| -rw-r--r-- | mpm/lib/mykonos/config/ad937x_default_config.hpp | 2 | ||||
| -rw-r--r-- | mpm/python/usrp_mpm/dboard_manager/magnesium.py | 10 | 
10 files changed, 332 insertions, 174 deletions
diff --git a/host/include/uhd/rfnoc/blocks/radio_magnesium.xml b/host/include/uhd/rfnoc/blocks/radio_magnesium.xml index 55065d0d3..a67e2722f 100644 --- a/host/include/uhd/rfnoc/blocks/radio_magnesium.xml +++ b/host/include/uhd/rfnoc/blocks/radio_magnesium.xml @@ -5,7 +5,7 @@    <key>MagnesiumRadio</key>    <!--There can be several of these:-->    <ids> -    <id revision="0">12AD100000000003</id> +    <id revision="0">12AD100000000310</id>    </ids>    <!-- Registers -->    <registers> diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.cpp index b659902ae..cc51562aa 100644 --- a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.cpp +++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.cpp @@ -23,90 +23,246 @@  #include <uhd/utils/math.hpp>  #include <boost/algorithm/string.hpp>  #include <boost/make_shared.hpp> -#include <boost/date_time/posix_time/posix_time_io.hpp> +#include <boost/format.hpp> +#include <sstream>  using namespace uhd;  using namespace uhd::usrp;  using namespace uhd::rfnoc;  static const size_t IO_MASTER_RADIO = 0; +static const double MAGNESIUM_TICK_RATE = 125e6; // Hz +static const double MAGNESIUM_RADIO_RATE = 125e6; // Hz +static const double MAGNESIUM_CENTER_FREQ = 2.5e9; // Hz +static const double MAGNESIUM_DEFAULT_GAIN = 0.0; // dB +static const double MAGNESIUM_DEFAULT_BANDWIDTH = 40e6; // Hz TODO: fix +static const size_t MAGNESIUM_NUM_TX_CHANS = 2; +static const size_t MAGNESIUM_NUM_RX_CHANS = 2; + +std::string _get_which(direction_t dir, size_t chan) +{ +    std::stringstream ss; +    switch (dir) +    { +    case RX_DIRECTION: +        ss << "RX"; +        break; +    case TX_DIRECTION: +        ss << "TX"; +        break; +    default: +        UHD_THROW_INVALID_CODE_PATH(); +    } + +    switch (chan) +    { +    case 0: +        ss << "1"; +        break; +    case 1: +        ss << "2"; +        break; +    default: +        throw uhd::runtime_error("invalid channel number"); +    } + +    return ss.str(); +}  UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR(magnesium_radio_ctrl)  { -    std::cout << "magnesium_radio_ctrl_impl::ctor() " << std::endl; +    UHD_LOG_TRACE("MAGNESIUM", "magnesium_radio_ctrl_impl::ctor() "); +    _radio_slot = (get_block_id().get_block_count() == IO_MASTER_RADIO) ? "A" : "B"; +    _slot_prefix = (get_block_id().get_block_count() == IO_MASTER_RADIO) ? "db_0_" : "db_1_"; +    UHD_LOG_TRACE("MAGNESIUM", "Radio slot: " << _radio_slot); + + +    const size_t num_rx_chans = get_output_ports().size(); +    UHD_ASSERT_THROW(num_rx_chans == MAGNESIUM_NUM_RX_CHANS); +    const size_t num_tx_chans = get_input_ports().size(); +    UHD_ASSERT_THROW(num_tx_chans == MAGNESIUM_NUM_TX_CHANS); + +    UHD_LOG_TRACE("MAGNESIUM", "Setting tick rate to " << MAGNESIUM_TICK_RATE / 1e6 << " MHz"); +    radio_ctrl_impl::set_rate(MAGNESIUM_TICK_RATE); + +    for (size_t chan = 0; chan < num_rx_chans; chan++) { +        radio_ctrl_impl::set_rx_frequency(MAGNESIUM_CENTER_FREQ, chan); +        radio_ctrl_impl::set_rx_gain(MAGNESIUM_DEFAULT_GAIN, chan); +        // TODO: fix antenna name +        radio_ctrl_impl::set_rx_antenna(str(boost::format("RX%d") % (chan+1)), chan); +        radio_ctrl_impl::set_rx_bandwidth(MAGNESIUM_DEFAULT_BANDWIDTH, chan); +    } + +    for (size_t chan = 0; chan < num_tx_chans; chan++) { +        radio_ctrl_impl::set_tx_frequency(MAGNESIUM_CENTER_FREQ, chan); +        radio_ctrl_impl::set_tx_gain(MAGNESIUM_DEFAULT_GAIN, chan); +        // TODO: fix antenna name +        radio_ctrl_impl::set_tx_antenna(str(boost::format("TX%d") % (chan + 1)), chan); +    } + +    /**** Set up legacy compatible properties ******************************/ +    // For use with multi_usrp APIs etc. +    // For legacy prop tree init: +    // TODO: determine DB number +    fs_path fe_base = fs_path("dboards") / _radio_slot; +    std::vector<std::string> fe({ "rx_frontends" , "tx_frontends" }); +    std::vector<std::string> ant({ "RX" , "TX" }); + +    UHD_ASSERT_THROW(MAGNESIUM_NUM_RX_CHANS == MAGNESIUM_NUM_TX_CHANS); +    for (size_t fe_idx = 0; fe_idx < fe.size(); ++fe_idx) +    { +        fs_path fe_direction_path = fe_base / fe[fe_idx]; +        for (size_t chan = 0; chan < MAGNESIUM_NUM_RX_CHANS; ++chan) { +            fs_path fe_path = fe_direction_path / chan; +            UHD_LOG_TRACE("MAGNESIUM", "Adding FE at " << fe_path); +            _tree->create<std::string>(fe_path / "name") +                .set(str(boost::format("Magnesium %s %d") % ant[fe_idx] % chan)) +                ; +            _tree->create<std::string>(fe_path / "connection") +                .set("IQ") +                ; +            // TODO: fix antenna name +            _tree->create<std::string>(fe_path / "antenna" / "value") +                .set(str(boost::format("%s%d") % ant[fe_idx] % (chan+1))) +                .add_coerced_subscriber(boost::bind(&magnesium_radio_ctrl_impl::set_rx_antenna, this, _1, chan)) +                .set_publisher(boost::bind(&radio_ctrl_impl::get_rx_antenna, this, chan)) +                ; +            _tree->create<std::vector<std::string>>(fe_path / "antenna" / "options") +                .set(std::vector<std::string>(1, str(boost::format("%s%d") % ant[fe_idx] % (chan + 1)))) +                ; +            _tree->create<double>(fe_path / "freq" / "value") +                .set(MAGNESIUM_CENTER_FREQ) +                .set_coercer(boost::bind(&magnesium_radio_ctrl_impl::set_rx_frequency, this, _1, chan)) +                .set_publisher(boost::bind(&radio_ctrl_impl::get_rx_frequency, this, chan)) +                ; +            _tree->create<meta_range_t>(fe_path / "freq" / "range") +                .set(meta_range_t(MAGNESIUM_CENTER_FREQ, MAGNESIUM_CENTER_FREQ)) +                ; +            _tree->create<double>(fe_path / "gains" / "null" / "value") +                .set(MAGNESIUM_DEFAULT_GAIN) +                .set_coercer(boost::bind(&magnesium_radio_ctrl_impl::set_rx_gain, this, _1, chan)) +                .set_publisher(boost::bind(&radio_ctrl_impl::get_rx_gain, this, chan)) +                ; +            _tree->create<meta_range_t>(fe_path / "gains" / "null" / "range") +                .set(meta_range_t(MAGNESIUM_DEFAULT_GAIN, MAGNESIUM_DEFAULT_GAIN)) +                ; +            _tree->create<double>(fe_path / "bandwidth" / "value") +                .set(MAGNESIUM_DEFAULT_BANDWIDTH) +                .set_coercer(boost::bind(&magnesium_radio_ctrl_impl::set_rx_bandwidth, this, _1, chan)) +                .set_publisher(boost::bind(&radio_ctrl_impl::get_rx_bandwidth, this, chan)) +                ; +            _tree->create<meta_range_t>(fe_path / "bandwidth" / "range") +                .set(meta_range_t(MAGNESIUM_DEFAULT_BANDWIDTH, MAGNESIUM_DEFAULT_BANDWIDTH)) +                ; +        } +    } + +    // TODO change codec names +    _tree->create<int>("rx_codecs" / _radio_slot / "gains"); +    _tree->create<int>("tx_codecs" / _radio_slot / "gains"); +    _tree->create<std::string>("rx_codecs" / _radio_slot / "name").set("AD9361 Dual ADC"); +    _tree->create<std::string>("tx_codecs" / _radio_slot / "name").set("AD9361 Dual DAC"); + +    // TODO remove this dirty hack +    if (not _tree->exists("tick_rate")) +    { +        _tree->create<double>("tick_rate").set(MAGNESIUM_TICK_RATE); +    }  }  magnesium_radio_ctrl_impl::~magnesium_radio_ctrl_impl()  { +    UHD_LOG_TRACE("MAGNESIUM", "magnesium_radio_ctrl_impl::dtor() ");  }  double magnesium_radio_ctrl_impl::set_rate(double rate)  { -  return 0; +    // TODO: implement +    if (rate != get_rate()) { +        UHD_LOG_WARNING("MAGNESIUM", "Attempting to set sampling rate to invalid value " << rate); +    } +    return get_rate();  }  void magnesium_radio_ctrl_impl::set_tx_antenna(const std::string &ant, const size_t chan)  { +    // TODO: implement +    UHD_LOG_WARNING("MAGNESIUM", "Ignoring attempt to set Tx antenna"); +    // CPLD control?  }  void magnesium_radio_ctrl_impl::set_rx_antenna(const std::string &ant, const size_t chan)  { +    // TODO: implement +    UHD_LOG_WARNING("MAGNESIUM", "Ignoring attempt to set Rx antenna"); +    // CPLD control?  }  double magnesium_radio_ctrl_impl::set_tx_frequency(const double freq, const size_t chan)  { -  return 0; +    return _set_freq(freq, chan, TX_DIRECTION);  }  double magnesium_radio_ctrl_impl::set_rx_frequency(const double freq, const size_t chan)  { -  return 0; +    return _set_freq(freq, chan, RX_DIRECTION);  }  double magnesium_radio_ctrl_impl::set_rx_bandwidth(const double bandwidth, const size_t chan)  { -  return 0; +    // TODO: implement +    return get_rx_bandwidth(chan);  } -double magnesium_radio_ctrl_impl::get_tx_frequency(const size_t chan) +double magnesium_radio_ctrl_impl::set_tx_gain(const double gain, const size_t chan)  { -  return 0; +    return _set_gain(gain, chan, TX_DIRECTION);  } -double magnesium_radio_ctrl_impl::get_rx_frequency(const size_t chan) +double magnesium_radio_ctrl_impl::set_rx_gain(const double gain, const size_t chan)  { -  return 0; +    return _set_gain(gain, chan, RX_DIRECTION);  } -double magnesium_radio_ctrl_impl::get_rx_bandwidth(const size_t chan) +size_t magnesium_radio_ctrl_impl::get_chan_from_dboard_fe(const std::string &fe, const direction_t dir)  { -  return 0; +    UHD_LOG_TRACE("MAGNESIUM", "get_chan_from_dboard_fe " << fe << " returns " << boost::lexical_cast<size_t>(fe)); +    return boost::lexical_cast<size_t>(fe);  } -double magnesium_radio_ctrl_impl::set_tx_gain(const double gain, const size_t chan) +std::string magnesium_radio_ctrl_impl::get_dboard_fe_from_chan(const size_t chan, const direction_t dir)  { -  return 0; +    UHD_LOG_TRACE("MAGNESIUM", "get_dboard_fe_from_chan " << chan << " returns " << std::to_string(chan)); +    return std::to_string(chan);  } -double magnesium_radio_ctrl_impl::set_rx_gain(const double gain, const size_t chan) +double magnesium_radio_ctrl_impl::get_output_samp_rate(size_t port)  { -  return 0; +    return 125e6;  } -size_t magnesium_radio_ctrl_impl::get_chan_from_dboard_fe(const std::string &fe, const direction_t dir) +void magnesium_radio_ctrl_impl::set_rpc_client( +    uhd::rpc_client::sptr rpcc, +    const uhd::device_addr_t &block_args +)  { -  return 0; +    _rpcc = rpcc; +    _block_args = block_args;  } -std::string magnesium_radio_ctrl_impl::get_dboard_fe_from_chan(const size_t chan, const direction_t dir) +double magnesium_radio_ctrl_impl::_set_freq(const double freq, const size_t chan, const direction_t dir)  { -  return ""; +    auto which = _get_which(dir, chan); +    UHD_LOG_TRACE("MAGNESIUM", "calling " << _slot_prefix << "set_freq on " << which << " with " << freq); +    return _rpcc->request_with_token<double>(_slot_prefix + "set_freq", which, freq, false);  } -double magnesium_radio_ctrl_impl::get_output_samp_rate(size_t port) +double magnesium_radio_ctrl_impl::_set_gain(const double gain, const size_t chan, const direction_t dir)  { -  return 0; +    auto which = _get_which(dir, chan); +    UHD_LOG_TRACE("MAGNESIUM", "calling " << _slot_prefix << "set_gain on " << which << " with " << gain); +    return _rpcc->request_with_token<double>(_slot_prefix + "set_gain", which, gain);  }  UHD_RFNOC_BLOCK_REGISTER(magnesium_radio_ctrl, "MagnesiumRadio"); diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.hpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.hpp index ea8282532..0bb1b26b8 100644 --- a/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.hpp +++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.hpp @@ -19,6 +19,7 @@  #define INCLUDED_LIBUHD_RFNOC_MAGNESIUM_RADIO_CTRL_IMPL_HPP  #include "radio_ctrl_impl.hpp" +#include "rpc_block_ctrl.hpp"  #include <uhd/usrp/dboard_manager.hpp>  #include <uhd/usrp/gpio_defs.hpp> @@ -27,7 +28,7 @@ namespace uhd {  /*! \brief Provide access to an Magnesium radio.   */ -class magnesium_radio_ctrl_impl : public radio_ctrl_impl +class magnesium_radio_ctrl_impl : public radio_ctrl_impl, public rpc_block_ctrl  {  public:      typedef boost::shared_ptr<magnesium_radio_ctrl_impl> sptr; @@ -49,9 +50,6 @@ public:      double set_tx_frequency(const double freq, const size_t chan);      double set_rx_frequency(const double freq, const size_t chan);      double set_rx_bandwidth(const double bandwidth, const size_t chan); -    double get_tx_frequency(const size_t chan); -    double get_rx_frequency(const size_t chan); -    double get_rx_bandwidth(const size_t chan);      double set_tx_gain(const double gain, const size_t chan);      double set_rx_gain(const double gain, const size_t chan); @@ -61,7 +59,22 @@ public:      double get_output_samp_rate(size_t port); +    void set_rpc_client( +        uhd::rpc_client::sptr rpcc, +        const uhd::device_addr_t &block_args +    ); +private: +    double _set_freq(const double freq, const size_t chan, const direction_t dir); +    double _set_gain(const double gain, const size_t chan, const direction_t dir); + +    std::string _radio_slot; +    std::string _slot_prefix; +    //! Additional block args; gets set during set_rpc_client() +    uhd::device_addr_t _block_args; + +    //! Reference to the RPC client +    uhd::rpc_client::sptr _rpcc;  }; /* class radio_ctrl_impl */ diff --git a/host/lib/usrp/mpmd/mpmd_impl.cpp b/host/lib/usrp/mpmd/mpmd_impl.cpp index c8c860c00..38a089788 100644 --- a/host/lib/usrp/mpmd/mpmd_impl.cpp +++ b/host/lib/usrp/mpmd/mpmd_impl.cpp @@ -106,13 +106,6 @@ namespace {                  );              })          ; -        tree->create<int>( -                mb_path / "rx_codecs" / "A" / "gains") -            .set_publisher([](){ -                return 1                              // FIXME: Remove hardcoding -                ; -            }) -        ;      }      void reset_time_synchronized(uhd::property_tree::sptr tree) diff --git a/mpm/include/mpm/ad937x/ad937x_ctrl.hpp b/mpm/include/mpm/ad937x/ad937x_ctrl.hpp index ee3b5d6f3..f26eee92d 100644 --- a/mpm/include/mpm/ad937x/ad937x_ctrl.hpp +++ b/mpm/include/mpm/ad937x/ad937x_ctrl.hpp @@ -74,7 +74,6 @@ public:      virtual uint8_t get_framer_status() = 0;      virtual uint8_t get_deframer_status() = 0; -    virtual uint8_t get_deframer_irq() = 0;      virtual uint16_t get_ilas_config_match() = 0;      virtual void enable_jesd_loopback(uint8_t enable) = 0; @@ -140,9 +139,10 @@ public:       * Sets the RF frequency.  This is a per direction setting.       * \param which frontend string to specify direction to tune       * \param value target frequency +     * \param wait_for_lock wait after tuning for the PLL to lock       * \return actual frequency       */ -    virtual double set_freq(const std::string &which, double value) = 0; +    virtual double set_freq(const std::string &which, double value, bool wait_for_lock) = 0;      /*! \brief get the RF frequency for the direction specified in which       * @@ -189,7 +189,6 @@ void export_mykonos(){          .def("get_multichip_sync_status", &ad937x_ctrl::get_multichip_sync_status)          .def("get_framer_status", &ad937x_ctrl::get_framer_status)          .def("get_deframer_status", &ad937x_ctrl::get_deframer_status) -        //.def("get_deframer_irq", &ad937x_ctrl::get_deframer_irq)          .def("get_ilas_config_match", &ad937x_ctrl::get_ilas_config_match)          .def("enable_jesd_loopback", &ad937x_ctrl::enable_jesd_loopback)          .def("get_rf_freq_range", &ad937x_ctrl::get_rf_freq_range) diff --git a/mpm/lib/mykonos/ad937x_ctrl.cpp b/mpm/lib/mykonos/ad937x_ctrl.cpp index 6bd8b5ce1..55479fb1d 100644 --- a/mpm/lib/mykonos/ad937x_ctrl.cpp +++ b/mpm/lib/mykonos/ad937x_ctrl.cpp @@ -157,41 +157,30 @@ public:          device.start_jesd_tx();      } -    // TODO: interpret the status byte -    // or provide means to do so      virtual uint8_t get_multichip_sync_status()      {          std::lock_guard<std::mutex> lock(*spi_mutex);          return device.get_multichip_sync_status();      } -    // TODO: interpret the status byte -    // or provide means to do so      virtual uint8_t get_framer_status()      {          std::lock_guard<std::mutex> lock(*spi_mutex);          return device.get_framer_status();      } -    // TODO: interpret the status byte -    // or provide means to do so      virtual uint8_t get_deframer_status()      {          std::lock_guard<std::mutex> lock(*spi_mutex);          return device.get_deframer_status();      } -    virtual uint8_t get_deframer_irq() -    { -        std::lock_guard<std::mutex> lock(*spi_mutex); -        return device.get_deframer_irq(); -    } -      virtual uint16_t get_ilas_config_match()      {          std::lock_guard<std::mutex> lock(*spi_mutex);          return device.get_ilas_config_match();      } +      virtual void enable_jesd_loopback(uint8_t enable)      {          std::lock_guard<std::mutex> lock(*spi_mutex); @@ -297,13 +286,13 @@ public:          return device.enable_channel(dir, chain, enable);      } -    virtual double set_freq(const std::string &which, double value) +    virtual double set_freq(const std::string &which, double value, bool wait_for_lock)      {          auto dir = _get_direction_from_antenna(which);          auto clipped_value = get_rf_freq_range().clip(value);          std::lock_guard<std::mutex> lock(*spi_mutex); -        return device.tune(dir, clipped_value); +        return device.tune(dir, clipped_value, wait_for_lock);      }      virtual double get_freq(const std::string &which) diff --git a/mpm/lib/mykonos/ad937x_device.cpp b/mpm/lib/mykonos/ad937x_device.cpp index 0e0851f41..e9815112e 100644 --- a/mpm/lib/mykonos/ad937x_device.cpp +++ b/mpm/lib/mykonos/ad937x_device.cpp @@ -25,6 +25,7 @@  #include <functional>  #include <iostream>  #include <thread> +#include <fstream>  using namespace mpm::ad937x::device;  using namespace mpm::ad937x::gpio; @@ -39,8 +40,10 @@ const double ad937x_device::MIN_TX_GAIN = 0.0;  const double ad937x_device::MAX_TX_GAIN = 41.95;  const double ad937x_device::TX_GAIN_STEP = 0.05; -static const double RX_DEFAULT_FREQ = 1e9; -static const double TX_DEFAULT_FREQ = 1e9; +static const double RX_DEFAULT_FREQ = 2.5e9; +static const double TX_DEFAULT_FREQ = 2.5e9; +static const double RX_DEFAULT_GAIN = 0; +static const double TX_DEFAULT_GAIN = 0;  // TODO: get the actual device ID  static const uint32_t AD9371_PRODUCT_ID = 0x1; @@ -112,89 +115,59 @@ void ad937x_device::_call_gpio_api_function(std::function<mykonosGpioErr_t()> fu      }  } -//void ad937x_device::_call_debug_api_function(std::function<mykonosDbgErr_t()> func) -//{ -    //auto error = func(); -    //if (error != MYKONOS_ERR_DBG_OK) -    //{ -        //std::cout << getDbgJesdMykonosErrorMessage(error); -        //// TODO: make UHD exception -        ////throw std::exception(getMykonosErrorMessage(error)); -    //} -//} - -// TODO: delete this comment closer to release -/* -EX 1 Preconditions -EX      1. Check revision register -EX      2. Initialize Clocking -EX      3. Initialize FPGA JESD - -begin_initialize() -IN 2 Start -IN      1. Reset Myk -IN      2. Init Myk -IN      3. Check base PLL -IN      4. Start Multichip Sync - -EX 3 Multichip Pulses -EX      1. Send 2 SYSREF pulses - -finish_initialize() -IN 4 Verify Multichip -IN    1. Verify Multichip -IN    2. Complete Init - ---skipping this for now using special hack from jepson ---IN    3. Load ARM ---IN    4. RF Start ---IN        Set RF Freq ---IN        Check RF PLLs ---IN        Set GPIO controls ---IN        Set gain ---IN        Init TX attenuations ---IN        Initialization Calibrations ---IN        External LOL Calibration (do we need this ???) - ---separate functions here for reusability-- - -start_jesd_rx() -IN 5 Start Myk JESD RX -IN    1. Reset Myk JESD RX (???) -IN    2. Enable Myk JESD RX Transmitter - -EX 6 Start FPGA CGS -EX    1. Reset and Ready RX JESD for CGS -EX    2. Reset and Ready TX JESD for CGS - -start_jesd_tx() -IN 7 Start Myk JESD TX -IN    1. Disable Myk JESD Receiver -IN    2. Reset Myk JESD Receiver -IN    3. Enable Myk JESD Receiver - -EX 8 Finish CGS -EX    1. Enable FPGA LMFC Generator -EX    2. Send SYSREF Pulse -EX    3. Wait (200 ms ???) -EX    4. Check TX Core is Synced -EX    5. Check RX Core is Synced - -OTHER FUNCTIONS THAT SHOULD BE WRITTEN -get_framer_status() get_deframer_status() Read framer/deframer status -get_deframer_irq() Read Deframer IRQ -get_ilas_config_match() Check ILAS Config Match -set_jesd_loopback() Enable Loopback -stop_jesd() Stop Link - -*/ +std::string ad937x_device::_get_arm_binary_path() +{ +    // TODO: possibly add more options here, for now it's always in /lib/firmware or we explode +    return "/lib/firmware/Mykonos_M3.bin"; +} -void ad937x_device::begin_initialization() +std::vector<uint8_t> ad937x_device::_get_arm_binary()  { -    // TODO: make this reset actually do something (implement CMB_HardReset or replace) -    _call_api_function(std::bind(MYKONOS_resetDevice, mykonos_config.device)); -    _call_api_function(std::bind(MYKONOS_initialize, mykonos_config.device)); +    auto path = _get_arm_binary_path(); +    std::ifstream file(path, std::ios::binary); +    if (!file.is_open()) +    { +        throw mpm::runtime_error("Could not open AD9371 ARM binary at path " + path); +        return{}; +    } + +    std::vector<uint8_t> binary(ARM_BINARY_SIZE); +    file.read(reinterpret_cast<char*>(binary.data()), ARM_BINARY_SIZE); +    if (file.bad()) +    { +        throw mpm::runtime_error("Error reading AD9371 ARM binary at path " + path); +    } +    return binary; +} + +void ad937x_device::_initialize_rf() +{ +    // Set frequencies +    tune(uhd::RX_DIRECTION, RX_DEFAULT_FREQ, true); +    tune(uhd::TX_DIRECTION, TX_DEFAULT_FREQ, true); + +    if (!get_pll_lock_status(pll_t::CLK_SYNTH)) +    { +        throw mpm::runtime_error("CLK SYNTH PLL became unlocked!"); +    } +    // Set gain control GPIO pins +    _apply_gain_pins(uhd::RX_DIRECTION, chain_t::ONE); +    _apply_gain_pins(uhd::RX_DIRECTION, chain_t::TWO); +    _apply_gain_pins(uhd::TX_DIRECTION, chain_t::ONE); +    _apply_gain_pins(uhd::TX_DIRECTION, chain_t::TWO); + +    // Set manual gain values +    set_gain(uhd::RX_DIRECTION, chain_t::ONE, RX_DEFAULT_GAIN); +    set_gain(uhd::RX_DIRECTION, chain_t::TWO, RX_DEFAULT_GAIN); +    set_gain(uhd::TX_DIRECTION, chain_t::ONE, TX_DEFAULT_GAIN); +    set_gain(uhd::TX_DIRECTION, chain_t::TWO, TX_DEFAULT_GAIN); + +    // TODO: add calibration stuff +} + +void ad937x_device::_verify_product_id() +{      uint8_t product_id = get_product_id();      if (product_id != AD9371_PRODUCT_ID)      { @@ -203,10 +176,30 @@ void ad937x_device::begin_initialization()              % int(product_id) % int(AD9371_PRODUCT_ID)          ));      } +} + +void ad937x_device::_verify_multichip_sync_status(multichip_sync_t mcs) +{ +    uint8_t status_expected = (mcs == multichip_sync_t::FULL) ? 0x0B : 0x0A; +    uint8_t status_mask = status_expected; // all 1s expected, mask is the same + +    uint8_t mcs_status = get_multichip_sync_status(); +    if ((mcs_status & status_mask) != status_expected) +    { +        throw mpm::runtime_error(str(boost::format("Multichip sync failed! Read: %X Expected: %X") +            % int(mcs_status) % int(status_expected))); +    } +} + +void ad937x_device::begin_initialization() +{ +    _call_api_function(std::bind(MYKONOS_initialize, mykonos_config.device)); + +    _verify_product_id();      if (!get_pll_lock_status(pll_t::CLK_SYNTH))      { -        throw mpm::runtime_error("AD937x CLK_SYNTH PLL failed to lock in initialize()"); +        throw mpm::runtime_error("AD937x CLK_SYNTH PLL failed to lock");      }      uint8_t mcs_status = 0; @@ -215,33 +208,24 @@ void ad937x_device::begin_initialization()  void ad937x_device::finish_initialization()  { -    std::this_thread::sleep_for(std::chrono::milliseconds(200)); -    // to check status, just call the same function with a 0 instead of a 1, seems good -    uint8_t mcs_status = 0; -    _call_api_function(std::bind(MYKONOS_enableMultichipSync, mykonos_config.device, 0, &mcs_status)); +    _verify_multichip_sync_status(multichip_sync_t::PARTIAL); -    if ((mcs_status & 0x0A) != 0x0A) -    { -        throw mpm::runtime_error(str(boost::format("Multichip sync failed! Read: %X Expected: %X") -            % int(mcs_status) % int(0x0A))); -    } - -    _call_api_function(std::bind(MYKONOS_initSubRegisterTables, mykonos_config.device)); -    // according to djepson, we can call only this function and avoid loading the ARM or -    // doing an RF stuff -    // TODO: fix all this once we want to more than just loopback +    _call_api_function(std::bind(MYKONOS_initArm, mykonos_config.device)); +    auto binary = _get_arm_binary(); +    _call_api_function(std::bind(MYKONOS_loadArmFromBinary, +        mykonos_config.device, +        binary.data(), +        binary.size())); -    // load ARM -    // ARM init -    // RF setup +    _initialize_rf();  } -void ad937x_device::start_jesd_rx() +void ad937x_device::start_jesd_tx()  {      _call_api_function(std::bind(MYKONOS_enableSysrefToRxFramer, mykonos_config.device, 1));  } -void ad937x_device::start_jesd_tx() +void ad937x_device::start_jesd_rx()  {      _call_api_function(std::bind(MYKONOS_enableSysrefToDeframer, mykonos_config.device, 0));      _call_api_function(std::bind(MYKONOS_resetDeframer, mykonos_config.device)); @@ -251,6 +235,7 @@ void ad937x_device::start_jesd_tx()  uint8_t ad937x_device::get_multichip_sync_status()  {      uint8_t mcs_status = 0; +    // to check status, just call the enable function with a 0 instead of a 1, seems good      _call_api_function(std::bind(MYKONOS_enableMultichipSync, mykonos_config.device, 0, &mcs_status));      return mcs_status;  } @@ -269,19 +254,11 @@ uint8_t ad937x_device::get_deframer_status()      return status;  } -uint8_t ad937x_device::get_deframer_irq() -{ -    uint8_t irq_status = 0; -    //_call_debug_api_function(std::bind(MYKONOS_deframerGetIrq, mykonos_config.device, &irq_status)); -    return irq_status; -} -  uint16_t ad937x_device::get_ilas_config_match()  {      uint16_t ilas_status = 0;      _call_api_function(std::bind(MYKONOS_jesd204bIlasCheck, mykonos_config.device, &ilas_status));      return ilas_status; -  }  void ad937x_device::enable_jesd_loopback(uint8_t enable) @@ -351,21 +328,24 @@ void ad937x_device::enable_channel(direction_t direction, chain_t chain, bool en      // is _initialize(). Need to figure out how to deal with this.  } -double ad937x_device::tune(direction_t direction, double value) +double ad937x_device::tune(direction_t direction, double value, bool wait_for_lock = false)  {      // I'm not sure why we set the PLL value in the config AND as a function parameter      // but here it is      mykonosRfPllName_t pll; +    pll_t locked_pll;      uint64_t integer_value = static_cast<uint64_t>(value);      switch (direction)      {      case TX_DIRECTION:          pll = TX_PLL; +        locked_pll = pll_t::TX_SYNTH;          mykonos_config.device->tx->txPllLoFrequency_Hz = integer_value;          break;      case RX_DIRECTION:          pll = RX_PLL; +        locked_pll = pll_t::RX_SYNTH;          mykonos_config.device->rx->rxPllLoFrequency_Hz = integer_value;          break;      default: @@ -373,11 +353,30 @@ double ad937x_device::tune(direction_t direction, double value)      }      _call_api_function(std::bind(MYKONOS_setRfPllFrequency, mykonos_config.device, pll, integer_value)); +    auto lock_time = std::chrono::steady_clock::now() + std::chrono::milliseconds(200);      // TODO: coercion here causes extra device accesses, when the formula is provided on pg 119 of the user guide      // Furthermore, because coerced is returned as an integer, it's not even accurate      uint64_t coerced_pll;      _call_api_function(std::bind(MYKONOS_getRfPllFrequency, mykonos_config.device, pll, &coerced_pll)); + +    if (wait_for_lock) +    { +        bool locked = false; +        while (not locked and lock_time > std::chrono::steady_clock::now()) +        { +            locked = get_pll_lock_status(locked_pll); +        } + +        if (!locked) +        { +            if (!get_pll_lock_status(locked_pll)) // last chance +            { +                throw mpm::runtime_error("RF PLL did not lock"); +            } +        } +    } +      return static_cast<double>(coerced_pll);  } @@ -403,6 +402,7 @@ bool ad937x_device::get_pll_lock_status(pll_t pll)  {      uint8_t pll_status;      _call_api_function(std::bind(MYKONOS_checkPllsLockStatus, mykonos_config.device, &pll_status)); +      switch (pll)      {      case pll_t::CLK_SYNTH: diff --git a/mpm/lib/mykonos/ad937x_device.hpp b/mpm/lib/mykonos/ad937x_device.hpp index 17a09f249..b20feb3f7 100644 --- a/mpm/lib/mykonos/ad937x_device.hpp +++ b/mpm/lib/mykonos/ad937x_device.hpp @@ -30,6 +30,7 @@  #include <mpm/spi/spi_iface.hpp>  #include <mpm/exception.hpp>  #include <boost/noncopyable.hpp> +#include <boost/filesystem.hpp>  #include <memory>  #include <functional> @@ -37,7 +38,7 @@ class ad937x_device : public boost::noncopyable  {  public:      enum class gain_mode_t { MANUAL, AUTOMATIC, HYBRID }; -    enum class pll_t {CLK_SYNTH, RX_SYNTH, TX_SYNTH, SNIFF_SYNTH, CALPLL_SDM}; +    enum class pll_t { CLK_SYNTH, RX_SYNTH, TX_SYNTH, SNIFF_SYNTH, CALPLL_SDM };      ad937x_device(          mpm::types::regs_iface* iface, @@ -48,13 +49,10 @@ public:      void finish_initialization();      void start_jesd_rx();      void start_jesd_tx(); +      uint8_t get_multichip_sync_status();      uint8_t get_framer_status();      uint8_t get_deframer_status(); - -    // debug functions for JESD -    // TODO: make these returns useful -    uint8_t get_deframer_irq();      uint16_t get_ilas_config_match();      void enable_jesd_loopback(uint8_t enable); @@ -68,7 +66,7 @@ public:      void set_agc_mode(uhd::direction_t direction, gain_mode_t mode);      double set_clock_rate(double value);      void enable_channel(uhd::direction_t direction, mpm::ad937x::device::chain_t chain, bool enable); -    double tune(uhd::direction_t direction, double value); +    double tune(uhd::direction_t direction, double value, bool wait_for_lock);      double get_freq(uhd::direction_t direction);      bool get_pll_lock_status(pll_t pll); @@ -91,6 +89,8 @@ public:      const static double TX_GAIN_STEP;  private: +    enum class multichip_sync_t { PARTIAL, FULL }; +      ad9371_spiSettings_t full_spi_settings;      ad937x_config_t mykonos_config;      ad937x_gain_ctrl_config_t gain_ctrl; @@ -99,7 +99,13 @@ private:      void _call_api_function(std::function<mykonosErr_t()> func);      void _call_gpio_api_function(std::function<mykonosGpioErr_t()> func); -    //void _call_debug_api_function(std::function<mykonosDbgErr_t()> func); + +    std::string _get_arm_binary_path(); +    std::vector<uint8_t> _get_arm_binary(); + +    void _initialize_rf(); +    void _verify_product_id(); +    void _verify_multichip_sync_status(multichip_sync_t mcs);      static uint8_t _convert_rx_gain(double gain);      static uint16_t _convert_tx_gain(double gain); diff --git a/mpm/lib/mykonos/config/ad937x_default_config.hpp b/mpm/lib/mykonos/config/ad937x_default_config.hpp index b0f254308..fdf777795 100644 --- a/mpm/lib/mykonos/config/ad937x_default_config.hpp +++ b/mpm/lib/mykonos/config/ad937x_default_config.hpp @@ -199,7 +199,7 @@ static const mykonosObsRxSettings_t DEFAULT_ORX_SETTINGS =      nullptr,        // Sniffer datapath profile, 3dB corner frequencies, and digital filter enables      nullptr,        // SnRx gain control settings structure      nullptr,        // ObsRx JESD204b framer configuration structure -    MYK_OBS_RXOFF,  // obsRxChannel +    MYK_ORX1,       // obsRxChannel  TODO: fix this garbage please      OBSLO_TX_PLL,   // (obsRxLoSource) The Obs Rx mixer can use the Tx Synth(TX_PLL) or Sniffer Synth (SNIFFER_PLL)      2600000000U,    // SnRx PLL LO frequency in Hz      0,              // Flag to choose if complex baseband or real IF data are selected for Rx and ObsRx paths. Where if > 0 = real IF data, '0' = complex data diff --git a/mpm/python/usrp_mpm/dboard_manager/magnesium.py b/mpm/python/usrp_mpm/dboard_manager/magnesium.py index b779607c8..536503b62 100644 --- a/mpm/python/usrp_mpm/dboard_manager/magnesium.py +++ b/mpm/python/usrp_mpm/dboard_manager/magnesium.py @@ -64,8 +64,9 @@ class Magnesium(DboardManagerBase):      spi_chipselect = {"lmk": 0, "mykonos": 1}      def __init__(self, slot_idx, **kwargs): -        super(Magnesium, self).__init__(*args, **kwargs) -        self.log = get_logger("Magnesium") +        super(Magnesium, self).__init__(slot_idx, **kwargs) +        self.log = get_logger("Magnesium-{}".format(slot_idx)) +        self.log.trace("Initializing Magnesium daughterboard, slot index {}".format(self.slot_idx))      def init(self, args):          """ @@ -88,6 +89,7 @@ class Magnesium(DboardManagerBase):          self.radio_regs = UIO(label="jesd204b-regs", read_only=False)          self.log.info("Radio-register UIO object successfully generated!")          self.init_jesd(self.radio_regs) +        return True      def init_jesd(self, uio):          """ @@ -117,14 +119,14 @@ class Magnesium(DboardManagerBase):          self.mykonos.finish_initialization()          self.log.trace("Starting Mykonos framer...") -        self.mykonos.start_jesd_rx() +        self.mykonos.start_jesd_tx()          self.jesdcore.send_sysref_pulse()          self.log.trace("Resetting FPGA deframer...")          self.jesdcore.init_deframer()          self.log.trace("Resetting FPGA framer...")          self.jesdcore.init_framer()          self.log.trace("Starting Mykonos deframer...") -        self.mykonos.start_jesd_tx() +        self.mykonos.start_jesd_rx()          self.log.trace("Enable LMFC and send")          self.jesdcore.enable_lmfc()  | 
