aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/include/uhd/rfnoc/blocks/radio_magnesium.xml2
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.cpp200
-rw-r--r--host/lib/usrp/dboard/magnesium/magnesium_radio_ctrl_impl.hpp21
-rw-r--r--host/lib/usrp/mpmd/mpmd_impl.cpp7
-rw-r--r--mpm/include/mpm/ad937x/ad937x_ctrl.hpp5
-rw-r--r--mpm/lib/mykonos/ad937x_ctrl.cpp17
-rw-r--r--mpm/lib/mykonos/ad937x_device.cpp222
-rw-r--r--mpm/lib/mykonos/ad937x_device.hpp20
-rw-r--r--mpm/lib/mykonos/config/ad937x_default_config.hpp2
-rw-r--r--mpm/python/usrp_mpm/dboard_manager/magnesium.py10
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()