summaryrefslogtreecommitdiffstats
path: root/host/lib
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib')
-rw-r--r--host/lib/CMakeLists.txt2
-rw-r--r--host/lib/gain_group.cpp149
-rw-r--r--host/lib/gain_handler.cpp177
-rw-r--r--host/lib/ic_reg_maps/CMakeLists.txt5
-rwxr-xr-xhost/lib/ic_reg_maps/gen_ads62p44_regs.py124
-rw-r--r--host/lib/usrp/CMakeLists.txt2
-rw-r--r--host/lib/usrp/dboard_manager.cpp23
-rw-r--r--host/lib/usrp/mimo_usrp.cpp17
-rw-r--r--host/lib/usrp/misc_utils.cpp114
-rw-r--r--host/lib/usrp/misc_utils.hpp35
-rw-r--r--host/lib/usrp/simple_usrp.cpp29
-rw-r--r--host/lib/usrp/usrp2/CMakeLists.txt2
-rw-r--r--host/lib/usrp/usrp2/clock_ctrl.cpp105
-rw-r--r--host/lib/usrp/usrp2/codec_ctrl.cpp51
-rw-r--r--host/lib/usrp/usrp2/codec_ctrl.hpp21
-rw-r--r--host/lib/usrp/usrp2/codec_impl.cpp163
-rw-r--r--host/lib/usrp/usrp2/dboard_iface.cpp26
-rw-r--r--host/lib/usrp/usrp2/dboard_impl.cpp34
-rw-r--r--host/lib/usrp/usrp2/dsp_impl.cpp12
-rw-r--r--host/lib/usrp/usrp2/fw_common.h22
-rw-r--r--host/lib/usrp/usrp2/mboard_impl.cpp65
-rw-r--r--host/lib/usrp/usrp2/serdes_ctrl.cpp4
-rw-r--r--host/lib/usrp/usrp2/usrp2_clk_regs.hpp63
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp15
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.hpp37
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp12
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.cpp98
-rw-r--r--host/lib/usrp/usrp2/usrp2_regs.hpp171
28 files changed, 1177 insertions, 401 deletions
diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt
index 767029dc4..4899d3dbc 100644
--- a/host/lib/CMakeLists.txt
+++ b/host/lib/CMakeLists.txt
@@ -112,7 +112,7 @@ CONFIGURE_FILE(
LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/device.cpp
- ${CMAKE_CURRENT_SOURCE_DIR}/gain_handler.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/gain_group.cpp
${CMAKE_CURRENT_SOURCE_DIR}/load_modules.cpp
${CMAKE_CURRENT_SOURCE_DIR}/thread_priority.cpp
${CMAKE_CURRENT_SOURCE_DIR}/types.cpp
diff --git a/host/lib/gain_group.cpp b/host/lib/gain_group.cpp
new file mode 100644
index 000000000..1be09dee2
--- /dev/null
+++ b/host/lib/gain_group.cpp
@@ -0,0 +1,149 @@
+//
+// Copyright 2010 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
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include <uhd/utils/gain_group.hpp>
+#include <uhd/types/dict.hpp>
+#include <uhd/utils/algorithm.hpp>
+#include <uhd/utils/assert.hpp>
+#include <boost/foreach.hpp>
+#include <boost/bind.hpp>
+#include <algorithm>
+#include <vector>
+#include <iostream>
+
+using namespace uhd;
+
+static const bool verbose = false;
+
+static bool compare_by_step_size(
+ const size_t &rhs, const size_t &lhs, std::vector<gain_fcns_t> &fcns
+){
+ return fcns.at(rhs).get_range().step > fcns.at(lhs).get_range().step;
+}
+
+/***********************************************************************
+ * gain group implementation
+ **********************************************************************/
+class gain_group_impl : public gain_group{
+public:
+ gain_group_impl(void){
+ /*NOP*/
+ }
+
+ gain_range_t get_range(void){
+ float overall_min = 0, overall_max = 0, overall_step = 0;
+ BOOST_FOREACH(const gain_fcns_t &fcns, get_all_fcns()){
+ const gain_range_t range = fcns.get_range();
+ overall_min += range.min;
+ overall_max += range.max;
+ //the overall step is the min (zero is invalid, first run)
+ if (overall_step == 0) overall_step = range.step;
+ overall_step = std::min(overall_step, range.step);
+ }
+ return gain_range_t(overall_min, overall_max, overall_step);
+ }
+
+ float get_value(void){
+ float overall_gain = 0;
+ BOOST_FOREACH(const gain_fcns_t &fcns, get_all_fcns()){
+ overall_gain += fcns.get_value();
+ }
+ return overall_gain;
+ }
+
+ void set_value(float gain){
+ std::vector<gain_fcns_t> all_fcns = get_all_fcns();
+ if (all_fcns.size() == 0) return; //nothing to set!
+
+ //get the max step size among the gains
+ float max_step = 0;
+ BOOST_FOREACH(const gain_fcns_t &fcns, all_fcns){
+ max_step = std::max(max_step, fcns.get_range().step);
+ }
+
+ //create gain bucket to distribute power
+ std::vector<float> gain_bucket;
+
+ //distribute power according to priority (round to max step)
+ float gain_left_to_distribute = gain;
+ BOOST_FOREACH(const gain_fcns_t &fcns, all_fcns){
+ const gain_range_t range = fcns.get_range();
+ gain_bucket.push_back(
+ max_step*int(std::clip(gain_left_to_distribute, range.min, range.max)/max_step)
+ );
+ gain_left_to_distribute -= gain_bucket.back();
+ }
+
+ //get a list of indexes sorted by step size large to small
+ std::vector<size_t> indexes_step_size_dec;
+ for (size_t i = 0; i < all_fcns.size(); i++){
+ indexes_step_size_dec.push_back(i);
+ }
+ std::sort(
+ indexes_step_size_dec.begin(), indexes_step_size_dec.end(),
+ boost::bind(&compare_by_step_size, _1, _2, all_fcns)
+ );
+ UHD_ASSERT_THROW(
+ all_fcns.at(indexes_step_size_dec.front()).get_range().step >=
+ all_fcns.at(indexes_step_size_dec.back()).get_range().step
+ );
+
+ //distribute the remainder (less than max step)
+ //fill in the largest step sizes first that are less than the remainder
+ BOOST_FOREACH(size_t i, indexes_step_size_dec){
+ const gain_range_t range = all_fcns.at(i).get_range();
+ float additional_gain = range.step*int(
+ std::clip(gain_bucket.at(i) + gain_left_to_distribute, range.min, range.max
+ )/range.step) - gain_bucket.at(i);
+ gain_bucket.at(i) += additional_gain;
+ gain_left_to_distribute -= additional_gain;
+ }
+ if (verbose) std::cout << "gain_left_to_distribute " << gain_left_to_distribute << std::endl;
+
+ //now write the bucket out to the individual gain values
+ for (size_t i = 0; i < gain_bucket.size(); i++){
+ if (verbose) std::cout << gain_bucket.at(i) << std::endl;
+ all_fcns.at(i).set_value(gain_bucket.at(i));
+ }
+ }
+
+ void register_fcns(
+ const gain_fcns_t &gain_fcns, size_t priority
+ ){
+ _registry[priority].push_back(gain_fcns);
+ }
+
+private:
+ //! get the gain function sets in order (highest priority first)
+ std::vector<gain_fcns_t> get_all_fcns(void){
+ std::vector<gain_fcns_t> all_fcns;
+ BOOST_FOREACH(ssize_t key, std::sorted(_registry.keys())){
+ const std::vector<gain_fcns_t> &fcns = _registry[key];
+ all_fcns.insert(all_fcns.begin(), fcns.begin(), fcns.end());
+ }
+ return all_fcns;
+ }
+
+ uhd::dict<size_t, std::vector<gain_fcns_t> > _registry;
+};
+
+/***********************************************************************
+ * gain group factory function
+ **********************************************************************/
+gain_group::sptr gain_group::make(void){
+ return sptr(new gain_group_impl());
+}
diff --git a/host/lib/gain_handler.cpp b/host/lib/gain_handler.cpp
deleted file mode 100644
index 36e2e8ed3..000000000
--- a/host/lib/gain_handler.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-//
-// Copyright 2010 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
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-//
-
-#include <uhd/utils/gain_handler.hpp>
-#include <uhd/utils/assert.hpp>
-#include <uhd/types/ranges.hpp>
-#include <uhd/utils/props.hpp>
-#include <boost/assign/list_of.hpp>
-#include <boost/foreach.hpp>
-#include <boost/format.hpp>
-#include <cmath>
-#include <vector>
-
-using namespace uhd;
-
-/***********************************************************************
- * gain handler implementation interface
- **********************************************************************/
-class gain_handler_impl : public gain_handler{
-public:
- gain_handler_impl(
- const wax::obj &link,
- const props_t &props,
- is_equal_t is_equal
- );
- ~gain_handler_impl(void);
- bool intercept_get(const wax::obj &key, wax::obj &val);
- bool intercept_set(const wax::obj &key, const wax::obj &val);
-
-private:
- wax::obj _link;
- props_t _props;
- is_equal_t _is_equal;
-
- prop_names_t get_gain_names(void);
- float get_overall_gain_val(void);
- gain_range_t get_overall_gain_range(void);
- template <class T> T get_named_prop(const wax::obj &prop, const std::string &name){
- return _link[named_prop_t(prop, name)].as<T>();
- }
-};
-
-/***********************************************************************
- * the make function
- **********************************************************************/
-gain_handler::sptr gain_handler::make(
- const wax::obj &link,
- const props_t &props,
- is_equal_t is_equal
-){
- return sptr(new gain_handler_impl(link, props, is_equal));
-}
-
-/***********************************************************************
- * gain handler implementation methods
- **********************************************************************/
-gain_handler::props_t::props_t(void){
- /* NOP */
-}
-
-gain_handler_impl::gain_handler_impl(
- const wax::obj &link,
- const props_t &props,
- is_equal_t is_equal
-){
- _link = link;
- _props = props;
- _is_equal = is_equal;
-}
-
-gain_handler_impl::~gain_handler_impl(void){
- /* NOP */
-}
-
-prop_names_t gain_handler_impl::get_gain_names(void){
- return _link[_props.names].as<prop_names_t>();
-}
-
-float gain_handler_impl::get_overall_gain_val(void){
- float gain_val = 0;
- BOOST_FOREACH(std::string name, get_gain_names()){
- gain_val += get_named_prop<float>(_props.value, name);
- }
- return gain_val;
-}
-
-gain_range_t gain_handler_impl::get_overall_gain_range(void){
- float gain_min = 0, gain_max = 0, gain_step = 0;
- BOOST_FOREACH(std::string name, get_gain_names()){
- gain_range_t floatmp = get_named_prop<gain_range_t>(_props.range, name);
- gain_min += floatmp.min;
- gain_max += floatmp.max;
- gain_step = std::max(gain_step, floatmp.step);
- }
- return gain_range_t(gain_min, gain_max, gain_step);
-}
-
-/***********************************************************************
- * gain handler implementation get method
- **********************************************************************/
-bool gain_handler_impl::intercept_get(const wax::obj &key_, wax::obj &val){
- wax::obj key; std::string name;
- boost::tie(key, name) = extract_named_prop(key_);
-
- //not a wildcard... dont handle (but check name)
- if (name != ""){
- assert_has(get_gain_names(), name, "gain name");
- return false;
- }
-
- if (_is_equal(key, _props.value)){
- val = get_overall_gain_val();
- return true;
- }
-
- if (_is_equal(key, _props.range)){
- val = get_overall_gain_range();
- return true;
- }
-
- return false; //not handled
-}
-
-/***********************************************************************
- * gain handler implementation set method
- **********************************************************************/
-bool gain_handler_impl::intercept_set(const wax::obj &key_, const wax::obj &val){
- wax::obj key; std::string name;
- boost::tie(key, name) = extract_named_prop(key_);
-
- //not a gain value key... dont handle
- if (not _is_equal(key, _props.value)) return false;
-
- float gain_val = val.as<float>();
-
- //not a wildcard... dont handle (but check name and range)
- if (name != ""){
- assert_has(get_gain_names(), name, "gain name");
- gain_range_t gain = get_named_prop<gain_range_t>(_props.range, name);
- if (gain_val > gain.max or gain_val < gain.min) throw std::range_error(str(
- boost::format("A value of %f for gain %s is out of range of (%f, %f)")
- % gain_val % name % gain.min % gain.max
- ));
- return false;
- }
-
- //set the overall gain
- BOOST_FOREACH(std::string name, get_gain_names()){
- //get the min, max, step for this gain name
- gain_range_t gain = get_named_prop<gain_range_t>(_props.range, name);
-
- //clip g to be within the allowed range
- float g = std::min(std::max(gain_val, gain.min), gain.max);
- //set g to be a multiple of the step size
- g -= std::fmod(g, gain.step);
- //set g to be the new gain
- _link[named_prop_t(_props.value, name)] = g;
- //subtract g out of the total gain left to apply
- gain_val -= g;
- }
-
- return true;
-}
diff --git a/host/lib/ic_reg_maps/CMakeLists.txt b/host/lib/ic_reg_maps/CMakeLists.txt
index ba1bbc9f0..39f26a5a6 100644
--- a/host/lib/ic_reg_maps/CMakeLists.txt
+++ b/host/lib/ic_reg_maps/CMakeLists.txt
@@ -63,3 +63,8 @@ LIBUHD_PYTHON_GEN_SOURCE(
${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_ad9522_regs.py
${CMAKE_BINARY_DIR}/lib/ic_reg_maps/ad9522_regs.hpp
)
+
+LIBUHD_PYTHON_GEN_SOURCE(
+ ${CMAKE_SOURCE_DIR}/lib/ic_reg_maps/gen_ads62p44_regs.py
+ ${CMAKE_BINARY_DIR}/lib/ic_reg_maps/ads62p44_regs.hpp
+)
diff --git a/host/lib/ic_reg_maps/gen_ads62p44_regs.py b/host/lib/ic_reg_maps/gen_ads62p44_regs.py
new file mode 100755
index 000000000..f0a84d940
--- /dev/null
+++ b/host/lib/ic_reg_maps/gen_ads62p44_regs.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python
+#
+# Copyright 2010 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
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+########################################################################
+# Template for raw text data describing registers
+# name addr[bit range inclusive] default optional enums
+########################################################################
+REGS_TMPL="""\
+########################################################################
+## address 0
+########################################################################
+reset 0[1] 0
+serial_readout 0[0] 0
+########################################################################
+## address 16
+########################################################################
+clkout_strength 16[6:7] 0 weaker=1, default=0, stronger=3
+########################################################################
+## address 17
+########################################################################
+dataout_strength 17[0:1] 0 weaker=1, default=0, stronger=3, maximum=2
+lvds_current 17[2:3] 0 3_5ma, 2_5ma, 4_5ma, 1_75ma
+lvds_current_double 17[4:5] 0 default, dblclk, dbldataclock
+########################################################################
+## address 18
+########################################################################
+lvds_clk_term 18[0:2] 0 none, 300, 180, 110, 150, 100, 81, 60
+lvds_data_term 18[3:5] 0 none, 300, 180, 110, 150, 100, 81, 60
+########################################################################
+## address 19
+########################################################################
+offset_freeze 19[4] 0
+########################################################################
+## address 20
+########################################################################
+power_down 20[0:2] 0 normal, a_dis, b_dis, ab_dis, global_pd, a_sby, b_sby, mux
+ref_select 20[3] 0 internal, external
+coarse_gain 20[4] 0 0db, 3_5db
+output_interface 20[5] 0 cmos, lvds
+override 20[7] 0
+########################################################################
+## address 22
+########################################################################
+test_patterns 22[0:2] 0 normal, zeros, ones, toggle, ramp, custom
+lvds_bytewise 22[3] 0
+data_format 22[4] 0 twos_complement, binary
+########################################################################
+## address 23
+########################################################################
+fine_gain 23[0:3] 0
+########################################################################
+## address 24 and 25
+########################################################################
+custom_low 24[0:7] 0
+custom_high 25[0:5] 0
+########################################################################
+## address 26
+########################################################################
+gain_correction 26[0:3] 0
+offset_tc 26[4:6] 0 1_1s, 0_55s, 0_27s, 0_13s, 2_15s, 4_3s
+low_latency 26[7] 0
+########################################################################
+## address 27
+########################################################################
+decimation 27[0:2] 0 decimate_2, decimate_4, decimate_1, decimate_8
+odd_tap_enable 27[3] 0
+filter_enable 27[4] 0
+filter_coeff_sel 27[5] 0 predefined, userdefined
+offset_enable 27[7] 0
+########################################################################
+## address 29
+########################################################################
+decimation_filter_bands 29[0:1] 0
+"""
+
+########################################################################
+# Template for methods in the body of the struct
+########################################################################
+BODY_TMPL="""\
+boost::uint8_t get_reg(boost::uint8_t addr){
+ boost::uint8_t reg = 0;
+ switch(addr){
+ #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs)))
+ case $addr:
+ #for $reg in filter(lambda r: r.get_addr() == addr, $regs)
+ reg |= (boost::uint8_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift();
+ #end for
+ break;
+ #end for
+ }
+ return reg;
+}
+
+boost::uint16_t get_write_reg(boost::uint8_t addr){
+ return (boost::uint16_t(addr) << 8) | get_reg(addr);
+}
+
+boost::uint16_t get_read_reg(boost::uint8_t addr){
+ return (boost::uint16_t(addr) << 8) | (1 << 7);
+}
+"""
+
+if __name__ == '__main__':
+ import common; common.generate(
+ name='ads62p44_regs',
+ regs_tmpl=REGS_TMPL,
+ body_tmpl=BODY_TMPL,
+ file=__file__,
+ )
diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt
index 814affdd0..4f0710b20 100644
--- a/host/lib/usrp/CMakeLists.txt
+++ b/host/lib/usrp/CMakeLists.txt
@@ -24,6 +24,8 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_SOURCE_DIR}/lib/usrp/dboard_manager.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/dsp_utils.hpp
${CMAKE_SOURCE_DIR}/lib/usrp/mimo_usrp.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/misc_utils.cpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/misc_utils.hpp
${CMAKE_SOURCE_DIR}/lib/usrp/simple_usrp.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/tune_helper.cpp
)
diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp
index bfaaf0969..ab80875f5 100644
--- a/host/lib/usrp/dboard_manager.cpp
+++ b/host/lib/usrp/dboard_manager.cpp
@@ -18,7 +18,6 @@
#include "dboard_ctor_args.hpp"
#include <uhd/usrp/dboard_manager.hpp>
#include <uhd/usrp/subdev_props.hpp>
-#include <uhd/utils/gain_handler.hpp>
#include <uhd/utils/static.hpp>
#include <uhd/utils/assert.hpp>
#include <uhd/types/dict.hpp>
@@ -98,33 +97,18 @@ public:
enum type_t{RX_TYPE, TX_TYPE};
//structors
- subdev_proxy(dboard_base::sptr subdev, type_t type)
- : _subdev(subdev), _type(type){
- //initialize gain props struct
- gain_handler::props_t gain_props;
- gain_props.value = SUBDEV_PROP_GAIN;
- gain_props.range = SUBDEV_PROP_GAIN_RANGE;
- gain_props.names = SUBDEV_PROP_GAIN_NAMES;
-
- //make a new gain handler
- _gain_handler = gain_handler::make(
- this->get_link(), gain_props,
- boost::bind(&gain_handler::is_equal<subdev_prop_t>, _1, _2)
- );
- }
-
- ~subdev_proxy(void){
+ subdev_proxy(dboard_base::sptr subdev, type_t type):
+ _subdev(subdev), _type(type)
+ {
/* NOP */
}
private:
- gain_handler::sptr _gain_handler;
dboard_base::sptr _subdev;
type_t _type;
//forward the get calls to the rx or tx
void get(const wax::obj &key, wax::obj &val){
- if (_gain_handler->intercept_get(key, val)) return;
switch(_type){
case RX_TYPE: return _subdev->rx_get(key, val);
case TX_TYPE: return _subdev->tx_get(key, val);
@@ -133,7 +117,6 @@ private:
//forward the set calls to the rx or tx
void set(const wax::obj &key, const wax::obj &val){
- if (_gain_handler->intercept_set(key, val)) return;
switch(_type){
case RX_TYPE: return _subdev->rx_set(key, val);
case TX_TYPE: return _subdev->tx_set(key, val);
diff --git a/host/lib/usrp/mimo_usrp.cpp b/host/lib/usrp/mimo_usrp.cpp
index ec0f1dcc8..6b9318c39 100644
--- a/host/lib/usrp/mimo_usrp.cpp
+++ b/host/lib/usrp/mimo_usrp.cpp
@@ -18,6 +18,7 @@
#include <uhd/usrp/mimo_usrp.hpp>
#include <uhd/usrp/tune_helper.hpp>
#include <uhd/utils/assert.hpp>
+#include <uhd/utils/gain_group.hpp>
#include <uhd/utils/algorithm.hpp>
#include <uhd/usrp/subdev_props.hpp>
#include <uhd/usrp/mboard_props.hpp>
@@ -56,11 +57,13 @@ public:
_rx_dboards.push_back(_mboards.back()[MBOARD_PROP_RX_DBOARD]);
std::string rx_subdev_in_use = _rx_dboards.back()[DBOARD_PROP_USED_SUBDEVS].as<prop_names_t>().at(0);
_rx_subdevs.push_back(_rx_dboards.back()[named_prop_t(DBOARD_PROP_SUBDEV, rx_subdev_in_use)]);
+ _rx_gain_groups.push_back(_rx_dboards.back()[named_prop_t(DBOARD_PROP_GAIN_GROUP, rx_subdev_in_use)].as<gain_group::sptr>());
//extract tx subdevice
_tx_dboards.push_back(_mboards.back()[MBOARD_PROP_TX_DBOARD]);
std::string tx_subdev_in_use = _tx_dboards.back()[DBOARD_PROP_USED_SUBDEVS].as<prop_names_t>().at(0);
_tx_subdevs.push_back(_tx_dboards.back()[named_prop_t(DBOARD_PROP_SUBDEV, tx_subdev_in_use)]);
+ _tx_gain_groups.push_back(_tx_dboards.back()[named_prop_t(DBOARD_PROP_GAIN_GROUP, tx_subdev_in_use)].as<gain_group::sptr>());
}
//set the clock config across all mboards (TODO set through api)
@@ -201,15 +204,15 @@ public:
}
void set_rx_gain(size_t chan, float gain){
- _rx_subdevs.at(chan)[SUBDEV_PROP_GAIN] = gain;
+ _rx_gain_groups.at(chan)->set_value(gain);
}
float get_rx_gain(size_t chan){
- return _rx_subdevs.at(chan)[SUBDEV_PROP_GAIN].as<float>();
+ return _rx_gain_groups.at(chan)->get_value();
}
gain_range_t get_rx_gain_range(size_t chan){
- return _rx_subdevs.at(chan)[SUBDEV_PROP_GAIN_RANGE].as<gain_range_t>();
+ return _rx_gain_groups.at(chan)->get_range();
}
void set_rx_antenna(size_t chan, const std::string &ant){
@@ -268,15 +271,15 @@ public:
}
void set_tx_gain(size_t chan, float gain){
- _tx_subdevs.at(chan)[SUBDEV_PROP_GAIN] = gain;
+ _tx_gain_groups.at(chan)->set_value(gain);
}
float get_tx_gain(size_t chan){
- return _tx_subdevs.at(chan)[SUBDEV_PROP_GAIN].as<float>();
+ return _tx_gain_groups.at(chan)->get_value();
}
gain_range_t get_tx_gain_range(size_t chan){
- return _tx_subdevs.at(chan)[SUBDEV_PROP_GAIN_RANGE].as<gain_range_t>();
+ return _tx_gain_groups.at(chan)->get_range();
}
void set_tx_antenna(size_t chan, const std::string &ant){
@@ -304,6 +307,8 @@ private:
std::vector<wax::obj> _tx_dboards;
std::vector<wax::obj> _rx_subdevs;
std::vector<wax::obj> _tx_subdevs;
+ std::vector<gain_group::sptr> _rx_gain_groups;
+ std::vector<gain_group::sptr> _tx_gain_groups;
//shadows
double _rx_rate, _tx_rate;
diff --git a/host/lib/usrp/misc_utils.cpp b/host/lib/usrp/misc_utils.cpp
new file mode 100644
index 000000000..0aa03a6cc
--- /dev/null
+++ b/host/lib/usrp/misc_utils.cpp
@@ -0,0 +1,114 @@
+//
+// Copyright 2010 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
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "misc_utils.hpp"
+#include <uhd/utils/gain_group.hpp>
+#include <uhd/usrp/subdev_props.hpp>
+#include <uhd/usrp/codec_props.hpp>
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+
+using namespace uhd;
+using namespace uhd::usrp;
+
+static const size_t subdev_gain_priority = 1; //higher, closer to the antenna
+static const size_t codec_gain_priority = 0;
+
+/***********************************************************************
+ * codec gain group helper functions:
+ * do this so we dont have to bind a templated function
+ **********************************************************************/
+static gain_range_t get_codec_gain_range(wax::obj codec, const std::string &name){
+ return codec[named_prop_t(CODEC_PROP_GAIN_RANGE, name)].as<gain_range_t>();
+}
+
+static float get_codec_gain_i(wax::obj codec, const std::string &name){
+ return codec[named_prop_t(CODEC_PROP_GAIN_I, name)].as<float>();
+}
+
+static float get_codec_gain_q(wax::obj codec, const std::string &name){
+ return codec[named_prop_t(CODEC_PROP_GAIN_Q, name)].as<float>();
+}
+
+static void set_codec_gain_both(wax::obj codec, const std::string &name, float gain){
+ codec[named_prop_t(CODEC_PROP_GAIN_I, name)] = gain;
+ codec[named_prop_t(CODEC_PROP_GAIN_Q, name)] = gain;
+}
+
+static void set_codec_gain_i(wax::obj codec, const std::string &name, float gain){
+ codec[named_prop_t(CODEC_PROP_GAIN_I, name)] = gain;
+}
+
+static void set_codec_gain_q(wax::obj codec, const std::string &name, float gain){
+ codec[named_prop_t(CODEC_PROP_GAIN_Q, name)] = gain;
+}
+
+/***********************************************************************
+ * subdev gain group helper functions:
+ * do this so we dont have to bind a templated function
+ **********************************************************************/
+static float get_subdev_gain(wax::obj subdev, const std::string &name){
+ return subdev[named_prop_t(SUBDEV_PROP_GAIN, name)].as<float>();
+}
+
+static gain_range_t get_subdev_gain_range(wax::obj subdev, const std::string &name){
+ return subdev[named_prop_t(SUBDEV_PROP_GAIN_RANGE, name)].as<gain_range_t>();
+}
+
+static void set_subdev_gain(wax::obj subdev, const std::string &name, float gain){
+ subdev[named_prop_t(SUBDEV_PROP_GAIN, name)] = gain;
+}
+
+/***********************************************************************
+ * gain group factory function for usrp
+ **********************************************************************/
+gain_group::sptr usrp::make_gain_group(wax::obj subdev, wax::obj codec){
+ gain_group::sptr gg = gain_group::make();
+ gain_fcns_t fcns;
+ //add all the subdev gains first (antenna to dsp order)
+ BOOST_FOREACH(const std::string &name, subdev[SUBDEV_PROP_GAIN_NAMES].as<prop_names_t>()){
+ fcns.get_range = boost::bind(&get_subdev_gain_range, subdev, name);
+ fcns.get_value = boost::bind(&get_subdev_gain, subdev, name);
+ fcns.set_value = boost::bind(&set_subdev_gain, subdev, name, _1);
+ gg->register_fcns(fcns, subdev_gain_priority);
+ }
+ //add all the codec gains last (antenna to dsp order)
+ BOOST_FOREACH(const std::string &name, codec[CODEC_PROP_GAIN_NAMES].as<prop_names_t>()){
+ fcns.get_range = boost::bind(&get_codec_gain_range, codec, name);
+
+ //register the value functions depending upon the connection type
+ switch(subdev[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()){
+ case SUBDEV_CONN_COMPLEX_IQ:
+ case SUBDEV_CONN_COMPLEX_QI:
+ fcns.get_value = boost::bind(&get_codec_gain_i, codec, name); //same as Q
+ fcns.set_value = boost::bind(&set_codec_gain_both, codec, name, _1); //sets both
+ break;
+
+ case SUBDEV_CONN_REAL_I:
+ fcns.get_value = boost::bind(&get_codec_gain_i, codec, name);
+ fcns.set_value = boost::bind(&set_codec_gain_i, codec, name, _1);
+ break;
+
+ case SUBDEV_CONN_REAL_Q:
+ fcns.get_value = boost::bind(&get_codec_gain_q, codec, name);
+ fcns.set_value = boost::bind(&set_codec_gain_q, codec, name, _1);
+ break;
+ }
+ gg->register_fcns(fcns, codec_gain_priority);
+ }
+ return gg;
+}
diff --git a/host/lib/usrp/misc_utils.hpp b/host/lib/usrp/misc_utils.hpp
new file mode 100644
index 000000000..7fe3c899d
--- /dev/null
+++ b/host/lib/usrp/misc_utils.hpp
@@ -0,0 +1,35 @@
+//
+// Copyright 2010 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
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_USRP_MISC_UTILS_HPP
+#define INCLUDED_LIBUHD_USRP_MISC_UTILS_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/wax.hpp>
+#include <uhd/utils/gain_group.hpp>
+
+namespace uhd{ namespace usrp{
+
+ /*!
+ * Create a gain group that represents the subdevice and its codec.
+ */
+ gain_group::sptr make_gain_group(wax::obj subdev, wax::obj codec);
+
+}} //namespace
+
+#endif /* INCLUDED_LIBUHD_USRP_MISC_UTILS_HPP */
+
diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp
index 5cb9511f4..a8c20c439 100644
--- a/host/lib/usrp/simple_usrp.cpp
+++ b/host/lib/usrp/simple_usrp.cpp
@@ -18,6 +18,7 @@
#include <uhd/usrp/simple_usrp.hpp>
#include <uhd/usrp/tune_helper.hpp>
#include <uhd/utils/assert.hpp>
+#include <uhd/utils/gain_group.hpp>
#include <uhd/usrp/subdev_props.hpp>
#include <uhd/usrp/mboard_props.hpp>
#include <uhd/usrp/device_props.hpp>
@@ -50,11 +51,13 @@ public:
_rx_dboard = _mboard[MBOARD_PROP_RX_DBOARD];
std::string rx_subdev_in_use = _rx_dboard[DBOARD_PROP_USED_SUBDEVS].as<prop_names_t>().at(0);
_rx_subdev = _rx_dboard[named_prop_t(DBOARD_PROP_SUBDEV, rx_subdev_in_use)];
+ _rx_gain_group = _rx_dboard[named_prop_t(DBOARD_PROP_GAIN_GROUP, rx_subdev_in_use)].as<gain_group::sptr>();
//extract tx subdevice
_tx_dboard = _mboard[MBOARD_PROP_TX_DBOARD];
std::string tx_subdev_in_use = _tx_dboard[DBOARD_PROP_USED_SUBDEVS].as<prop_names_t>().at(0);
_tx_subdev = _tx_dboard[named_prop_t(DBOARD_PROP_SUBDEV, tx_subdev_in_use)];
+ _tx_gain_group = _tx_dboard[named_prop_t(DBOARD_PROP_GAIN_GROUP, tx_subdev_in_use)].as<gain_group::sptr>();
}
~simple_usrp_impl(void){
@@ -139,15 +142,15 @@ public:
}
void set_rx_gain(float gain){
- _rx_subdev[SUBDEV_PROP_GAIN] = gain;
+ _rx_gain_group->set_value(gain);
}
float get_rx_gain(void){
- return _rx_subdev[SUBDEV_PROP_GAIN].as<float>();
+ return _rx_gain_group->get_value();
}
gain_range_t get_rx_gain_range(void){
- return _rx_subdev[SUBDEV_PROP_GAIN_RANGE].as<gain_range_t>();
+ return _rx_gain_group->get_range();
}
void set_rx_antenna(const std::string &ant){
@@ -198,15 +201,15 @@ public:
}
void set_tx_gain(float gain){
- _tx_subdev[SUBDEV_PROP_GAIN] = gain;
+ _tx_gain_group->set_value(gain);
}
float get_tx_gain(void){
- return _tx_subdev[SUBDEV_PROP_GAIN].as<float>();
+ return _tx_gain_group->get_value();
}
gain_range_t get_tx_gain_range(void){
- return _tx_subdev[SUBDEV_PROP_GAIN_RANGE].as<gain_range_t>();
+ return _tx_gain_group->get_range();
}
void set_tx_antenna(const std::string &ant){
@@ -225,6 +228,18 @@ public:
return _tx_subdev[SUBDEV_PROP_LO_LOCKED].as<bool>();
}
+ /*******************************************************************
+ * Interface access methods
+ ******************************************************************/
+
+ wax::obj get_rx_dboard_iface(void) {
+ return _rx_dboard;
+ }
+
+ wax::obj get_tx_dboard_iface(void) {
+ return _tx_dboard;
+ }
+
private:
device::sptr _dev;
wax::obj _mboard;
@@ -234,6 +249,8 @@ private:
wax::obj _tx_dboard;
wax::obj _rx_subdev;
wax::obj _tx_subdev;
+ gain_group::sptr _rx_gain_group;
+ gain_group::sptr _tx_gain_group;
};
/***********************************************************************
diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt
index 99d0b8bdd..b4a90a6ba 100644
--- a/host/lib/usrp/usrp2/CMakeLists.txt
+++ b/host/lib/usrp/usrp2/CMakeLists.txt
@@ -22,6 +22,7 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_ctrl.hpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.hpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_impl.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_impl.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_iface.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dsp_impl.cpp
@@ -34,4 +35,5 @@ LIBUHD_APPEND_SOURCES(
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.cpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.hpp
${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_regs.hpp
+ ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_regs.cpp
)
diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp
index b9be037c0..5ed8ec079 100644
--- a/host/lib/usrp/usrp2/clock_ctrl.cpp
+++ b/host/lib/usrp/usrp2/clock_ctrl.cpp
@@ -18,6 +18,7 @@
#include "clock_ctrl.hpp"
#include "ad9510_regs.hpp"
#include "usrp2_regs.hpp" //spi slave constants
+#include "usrp2_clk_regs.hpp"
#include <uhd/utils/assert.hpp>
#include <boost/cstdint.hpp>
@@ -29,10 +30,12 @@ using namespace uhd;
class usrp2_clock_ctrl_impl : public usrp2_clock_ctrl{
public:
usrp2_clock_ctrl_impl(usrp2_iface::sptr iface){
- _iface = iface;
+ _iface = iface; //_iface has get_hw_rev(), which lets us know if it's a USRP2+ (>=0x80) or USRP2 (<0x80).
+
+ clk_regs = usrp2_clk_regs_t(_iface->get_hw_rev());
_ad9510_regs.cp_current_setting = ad9510_regs_t::CP_CURRENT_SETTING_3_0MA;
- this->write_reg(0x09);
+ this->write_reg(clk_regs.pll_3);
// Setup the clock registers to 100MHz:
// This was already done by the firmware (or the host couldnt communicate).
@@ -42,20 +45,20 @@ public:
_ad9510_regs.pll_power_down = ad9510_regs_t::PLL_POWER_DOWN_NORMAL;
_ad9510_regs.prescaler_value = ad9510_regs_t::PRESCALER_VALUE_DIV2;
- this->write_reg(0x0A);
+ this->write_reg(clk_regs.pll_4);
_ad9510_regs.acounter = 0;
- this->write_reg(0x04);
+ this->write_reg(clk_regs.acounter);
_ad9510_regs.bcounter_msb = 0;
_ad9510_regs.bcounter_lsb = 5;
- this->write_reg(0x05);
- this->write_reg(0x06);
+ this->write_reg(clk_regs.bcounter_msb);
+ this->write_reg(clk_regs.bcounter_lsb);
_ad9510_regs.ref_counter_msb = 0;
_ad9510_regs.ref_counter_lsb = 1; // r divider = 1
- this->write_reg(0x0B);
- this->write_reg(0x0C);
+ this->write_reg(clk_regs.ref_counter_msb);
+ this->write_reg(clk_regs.ref_counter_lsb);
/* regs will be updated in commands below */
@@ -76,11 +79,12 @@ public:
}
//uses output clock 7 (cmos)
+ //this clock is the same between USRP2 and USRP2+ and so this fn does not get a switch statement
void enable_rx_dboard_clock(bool enb){
_ad9510_regs.power_down_lvds_cmos_out7 = enb? 0 : 1;
_ad9510_regs.lvds_cmos_select_out7 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT7_CMOS;
_ad9510_regs.output_level_lvds_out7 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT7_1_75MA;
- this->write_reg(0x43);
+ this->write_reg(clk_regs.output(clk_regs.rx_db));
this->update_regs();
}
@@ -96,8 +100,8 @@ public:
_ad9510_regs.divider_low_cycles_out7 = low - 1;
_ad9510_regs.divider_high_cycles_out7 = high - 1;
//write the registers
- this->write_reg(0x56);
- this->write_reg(0x57);
+ this->write_reg(clk_regs.div_lo(clk_regs.rx_db));
+ this->write_reg(clk_regs.div_hi(clk_regs.rx_db));
this->update_regs();
}
@@ -107,29 +111,50 @@ public:
return rates;
}
- //uses output clock 6 (cmos)
+ //uses output clock 6 (cmos) on USRP2 and output clock 5 (cmos) on USRP2+
void enable_tx_dboard_clock(bool enb){
- _ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1;
- _ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_CMOS;
- _ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA;
- this->write_reg(0x42);
+ switch(clk_regs.tx_db) {
+ case 5: //USRP2+
+ _ad9510_regs.power_down_lvds_cmos_out5 = enb? 0 : 1;
+ _ad9510_regs.lvds_cmos_select_out5 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT5_CMOS;
+ _ad9510_regs.output_level_lvds_out5 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT5_1_75MA;
+ break;
+ case 6: //USRP2
+ _ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1;
+ _ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_CMOS;
+ _ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA;
+ break;
+ }
+
+ this->write_reg(clk_regs.output(clk_regs.tx_db));
this->update_regs();
}
void set_rate_tx_dboard_clock(double rate){
assert_has(get_rates_tx_dboard_clock(), rate, "tx dboard clock rate");
size_t divider = size_t(rate/get_master_clock_rate());
- //bypass when the divider ratio is one
- _ad9510_regs.bypass_divider_out6 = (divider == 1)? 1 : 0;
//calculate the low and high dividers
size_t high = divider/2;
size_t low = divider - high;
- //set the registers (divider - 1)
- _ad9510_regs.divider_low_cycles_out6 = low - 1;
- _ad9510_regs.divider_high_cycles_out6 = high - 1;
+
+ switch(clk_regs.tx_db) {
+ case 5: //USRP2+
+ _ad9510_regs.bypass_divider_out5 = (divider == 1)? 1 : 0;
+ _ad9510_regs.divider_low_cycles_out5 = low - 1;
+ _ad9510_regs.divider_high_cycles_out5 = high - 1;
+ break;
+ case 6: //USRP2
+ //bypass when the divider ratio is one
+ _ad9510_regs.bypass_divider_out6 = (divider == 1)? 1 : 0;
+ //set the registers (divider - 1)
+ _ad9510_regs.divider_low_cycles_out6 = low - 1;
+ _ad9510_regs.divider_high_cycles_out6 = high - 1;
+ break;
+ }
+
//write the registers
- this->write_reg(0x54);
- this->write_reg(0x55);
+ this->write_reg(clk_regs.div_hi(clk_regs.tx_db));
+ this->write_reg(clk_regs.div_lo(clk_regs.tx_db));
this->update_regs();
}
@@ -147,7 +172,7 @@ public:
ad9510_regs_t::CHARGE_PUMP_MODE_3STATE ;
_ad9510_regs.pll_mux_control = ad9510_regs_t::PLL_MUX_CONTROL_DLD_HIGH;
_ad9510_regs.pfd_polarity = ad9510_regs_t::PFD_POLARITY_POS;
- this->write_reg(0x08);
+ this->write_reg(clk_regs.pll_2);
this->update_regs();
}
@@ -170,32 +195,44 @@ private:
*/
void update_regs(void){
_ad9510_regs.update_registers = 1;
- this->write_reg(0x5a);
+ this->write_reg(clk_regs.update);
}
//uses output clock 3 (pecl)
+ //this is the same between USRP2 and USRP2+ and doesn't get a switch statement
void enable_dac_clock(bool enb){
_ad9510_regs.power_down_lvpecl_out3 = (enb)?
ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_NORMAL :
ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_SAFE_PD;
_ad9510_regs.output_level_lvpecl_out3 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT3_810MV;
_ad9510_regs.bypass_divider_out3 = 1;
- this->write_reg(0x3F);
- this->write_reg(0x4F);
+ this->write_reg(clk_regs.output(clk_regs.dac));
+ this->write_reg(clk_regs.div_hi(clk_regs.dac));
this->update_regs();
}
- //uses output clock 4 (lvds)
+ //uses output clock 4 (lvds) on USRP2 and output clock 2 (lvpecl) on USRP2+
void enable_adc_clock(bool enb){
- _ad9510_regs.power_down_lvds_cmos_out4 = enb? 0 : 1;
- _ad9510_regs.lvds_cmos_select_out4 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT4_LVDS;
- _ad9510_regs.output_level_lvds_out4 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT4_1_75MA;
- _ad9510_regs.bypass_divider_out4 = 1;
- this->write_reg(0x40);
- this->write_reg(0x51);
+ switch(clk_regs.adc) {
+ case 2:
+ _ad9510_regs.power_down_lvpecl_out2 = enb? ad9510_regs_t::POWER_DOWN_LVPECL_OUT2_NORMAL : ad9510_regs_t::POWER_DOWN_LVPECL_OUT2_SAFE_PD;
+ _ad9510_regs.output_level_lvpecl_out2 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT2_500MV;
+ _ad9510_regs.bypass_divider_out2 = 1;
+ break;
+ case 4:
+ _ad9510_regs.power_down_lvds_cmos_out4 = enb? 0 : 1;
+ _ad9510_regs.lvds_cmos_select_out4 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT4_LVDS;
+ _ad9510_regs.output_level_lvds_out4 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT4_1_75MA;
+ _ad9510_regs.bypass_divider_out4 = 1;
+ break;
+ }
+
+ this->write_reg(clk_regs.output(clk_regs.adc));
+ this->write_reg(clk_regs.div_hi(clk_regs.adc));
this->update_regs();
}
+ usrp2_clk_regs_t clk_regs;
usrp2_iface::sptr _iface;
ad9510_regs_t _ad9510_regs;
};
diff --git a/host/lib/usrp/usrp2/codec_ctrl.cpp b/host/lib/usrp/usrp2/codec_ctrl.cpp
index 32cc13ded..e5be62205 100644
--- a/host/lib/usrp/usrp2/codec_ctrl.cpp
+++ b/host/lib/usrp/usrp2/codec_ctrl.cpp
@@ -17,10 +17,12 @@
#include "codec_ctrl.hpp"
#include "ad9777_regs.hpp"
+#include "ads62p44_regs.hpp"
#include "usrp2_regs.hpp"
#include <boost/cstdint.hpp>
#include <boost/foreach.hpp>
#include <iostream>
+#include <uhd/utils/exception.hpp>
static const bool codec_ctrl_debug = false;
@@ -57,7 +59,16 @@ public:
}
//power-up adc
- _iface->poke32(U2_REG_MISC_CTRL_ADC, U2_FLAG_MISC_CTRL_ADC_ON);
+ if(_iface->get_hw_rev() < USRP2P_FIRST_HW_REV) { //if we're on a USRP2
+ _iface->poke32(_iface->regs.misc_ctrl_adc, U2_FLAG_MISC_CTRL_ADC_ON);
+ } else { //we're on a USRP2+
+ _ads62p44_regs.reset = 1;
+ this->send_ads62p44_reg(0x00); //issue a reset to the ADC
+ //everything else should be pretty much default, i think
+// _ads62p44_regs.decimation = DECIMATION_DECIMATE_1;
+
+
+ }
}
~usrp2_codec_ctrl_impl(void){
@@ -66,11 +77,39 @@ public:
this->send_ad9777_reg(0);
//power-down adc
- _iface->poke32(U2_REG_MISC_CTRL_ADC, U2_FLAG_MISC_CTRL_ADC_OFF);
+ if(_iface->get_hw_rev() < USRP2P_FIRST_HW_REV) { //if we're on a USRP2
+ _iface->poke32(_iface->regs.misc_ctrl_adc, U2_FLAG_MISC_CTRL_ADC_OFF);
+ } else { //we're on a USRP2+
+ //send a global power-down to the ADC here... it will get lifted on reset
+ _ads62p44_regs.power_down = ads62p44_regs_t::POWER_DOWN_GLOBAL_PD;
+ this->send_ads62p44_reg(0x14);
+ }
+ }
+
+ void set_rx_digital_gain(float gain) { //fine digital gain
+ if(_iface->get_hw_rev() >= USRP2P_FIRST_HW_REV) {
+ _ads62p44_regs.fine_gain = int(gain/0.5);
+ this->send_ads62p44_reg(0x17);
+ } else UHD_THROW_INVALID_CODE_PATH(); //should never have been called for USRP2
+ }
+
+ void set_rx_digital_fine_gain(float gain) { //gain correction
+ if(_iface->get_hw_rev() >= USRP2P_FIRST_HW_REV) {
+ _ads62p44_regs.gain_correction = int(gain / 0.05);
+ this->send_ads62p44_reg(0x1A);
+ } else UHD_THROW_INVALID_CODE_PATH(); //should never have been called for USRP2
+ }
+
+ void set_rx_analog_gain(bool gain) { //turns on/off analog 3.5dB preamp
+ if(_iface->get_hw_rev() >= USRP2P_FIRST_HW_REV) {
+ _ads62p44_regs.coarse_gain = gain ? ads62p44_regs_t::COARSE_GAIN_3_5DB : ads62p44_regs_t::COARSE_GAIN_0DB;
+ this->send_ads62p44_reg(0x14);
+ } else UHD_THROW_INVALID_CODE_PATH();
}
private:
ad9777_regs_t _ad9777_regs;
+ ads62p44_regs_t _ads62p44_regs;
usrp2_iface::sptr _iface;
void send_ad9777_reg(boost::uint8_t addr){
@@ -81,6 +120,14 @@ private:
reg, 16, false /*no rb*/
);
}
+
+ void send_ads62p44_reg(boost::uint8_t addr) {
+ boost::uint16_t reg = _ads62p44_regs.get_write_reg(addr);
+ _iface->transact_spi(
+ SPI_SS_ADS62P44, spi_config_t::EDGE_FALL,
+ reg, 16, false /*no rb*/
+ );
+ }
};
/***********************************************************************
diff --git a/host/lib/usrp/usrp2/codec_ctrl.hpp b/host/lib/usrp/usrp2/codec_ctrl.hpp
index ad014e0e1..57a37b94b 100644
--- a/host/lib/usrp/usrp2/codec_ctrl.hpp
+++ b/host/lib/usrp/usrp2/codec_ctrl.hpp
@@ -33,6 +33,27 @@ public:
*/
static sptr make(usrp2_iface::sptr iface);
+ /*!
+ * Set the analog preamplifier on the USRP2+ ADC (ADS62P44).
+ * \param gain enable or disable the 3.5dB preamp
+ */
+
+ virtual void set_rx_analog_gain(bool gain) = 0;
+
+ /*!
+ * Set the digital gain on the USRP2+ ADC (ADS62P44).
+ * \param gain from 0-6dB
+ */
+
+ virtual void set_rx_digital_gain(float gain) = 0;
+
+ /*!
+ * Set the digital gain correction on the USRP2+ ADC (ADS62P44).
+ * \param gain from 0-0.5dB
+ */
+
+ virtual void set_rx_digital_fine_gain(float gain) = 0;
+
};
#endif /* INCLUDED_CODEC_CTRL_HPP */
diff --git a/host/lib/usrp/usrp2/codec_impl.cpp b/host/lib/usrp/usrp2/codec_impl.cpp
new file mode 100644
index 000000000..969b5b4b9
--- /dev/null
+++ b/host/lib/usrp/usrp2/codec_impl.cpp
@@ -0,0 +1,163 @@
+//
+// Copyright 2010 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
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "usrp2_impl.hpp"
+#include <uhd/usrp/codec_props.hpp>
+#include <uhd/types/dict.hpp>
+#include <uhd/types/ranges.hpp>
+#include <boost/bind.hpp>
+#include <boost/assign/list_of.hpp>
+#include <uhd/utils/assert.hpp>
+#include <uhd/utils/exception.hpp>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace boost::assign;
+
+//this only applies to USRP2P
+static const uhd::dict<std::string, gain_range_t> codec_rx_gain_ranges = map_list_of
+ ("analog", gain_range_t(0, 3.5, 3.5))
+ ("digital", gain_range_t(0, 6.0, 0.5))
+ ("digital-fine", gain_range_t(0, 0.5, 0.05));
+
+
+/***********************************************************************
+ * Helper Methods
+ **********************************************************************/
+void usrp2_mboard_impl::codec_init(void){
+ //make proxies
+ _rx_codec_proxy = wax_obj_proxy::make(
+ boost::bind(&usrp2_mboard_impl::rx_codec_get, this, _1, _2),
+ boost::bind(&usrp2_mboard_impl::rx_codec_set, this, _1, _2)
+ );
+ _tx_codec_proxy = wax_obj_proxy::make(
+ boost::bind(&usrp2_mboard_impl::tx_codec_get, this, _1, _2),
+ boost::bind(&usrp2_mboard_impl::tx_codec_set, this, _1, _2)
+ );
+}
+
+/***********************************************************************
+ * RX Codec Properties
+ **********************************************************************/
+void usrp2_mboard_impl::rx_codec_get(const wax::obj &key_, wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<codec_prop_t>()){
+ case CODEC_PROP_NAME:
+ val = std::string("usrp2 adc");
+ return;
+
+ case CODEC_PROP_OTHERS:
+ val = prop_names_t();
+ return;
+
+ case CODEC_PROP_GAIN_NAMES:
+ if(_iface->get_hw_rev() >= USRP2P_FIRST_HW_REV) {
+ val = prop_names_t(codec_rx_gain_ranges.keys());
+ } else val = prop_names_t();
+ return;
+
+ case CODEC_PROP_GAIN_I:
+ case CODEC_PROP_GAIN_Q:
+ assert_has(_codec_rx_gains.keys(), name, "codec rx gain name");
+ val = _codec_rx_gains[name];
+ return;
+
+ case CODEC_PROP_GAIN_RANGE:
+ assert_has(codec_rx_gain_ranges.keys(), name, "codec rx gain range name");
+ val = codec_rx_gain_ranges[name];
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void usrp2_mboard_impl::rx_codec_set(const wax::obj &key_, const wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ float gain;
+
+ switch(key.as<codec_prop_t>()) {
+ case CODEC_PROP_GAIN_I:
+ case CODEC_PROP_GAIN_Q:
+ if(_iface->get_hw_rev() < USRP2P_FIRST_HW_REV) UHD_THROW_PROP_SET_ERROR();//this capability is only found in USRP2P
+
+ gain = val.as<float>();
+ this->rx_codec_set_gain(gain, name);
+ return;
+
+ default:
+ UHD_THROW_PROP_SET_ERROR();
+ }
+}
+
+/***********************************************************************
+ * Helper function to set RX codec gain
+ ***********************************************************************/
+
+void usrp2_mboard_impl::rx_codec_set_gain(float gain, const std::string &name){
+ assert_has(codec_rx_gain_ranges.keys(), name, "codec rx gain name");
+
+ _codec_rx_gains[name] = gain;
+
+ if(name == "analog") {
+ _codec_ctrl->set_rx_analog_gain(gain > 0); //just turn it on or off
+ return;
+ }
+ if(name == "digital") {
+ _codec_ctrl->set_rx_digital_gain(gain);
+ return;
+ }
+ if(name == "digital-fine") {
+ _codec_ctrl->set_rx_digital_fine_gain(gain);
+ return;
+ }
+ UHD_THROW_PROP_SET_ERROR();
+}
+
+
+/***********************************************************************
+ * TX Codec Properties
+ **********************************************************************/
+void usrp2_mboard_impl::tx_codec_get(const wax::obj &key_, wax::obj &val){
+ wax::obj key; std::string name;
+ boost::tie(key, name) = extract_named_prop(key_);
+
+ //handle the get request conditioned on the key
+ switch(key.as<codec_prop_t>()){
+ case CODEC_PROP_NAME:
+ val = std::string("usrp2 dac - ad9777");
+ return;
+
+ case CODEC_PROP_OTHERS:
+ val = prop_names_t();
+ return;
+
+ case CODEC_PROP_GAIN_NAMES:
+ val = prop_names_t(); //no gain elements to be controlled
+ return;
+
+ default: UHD_THROW_PROP_GET_ERROR();
+ }
+}
+
+void usrp2_mboard_impl::tx_codec_set(const wax::obj &, const wax::obj &){
+ UHD_THROW_PROP_SET_ERROR();
+}
diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp
index 6f2fb9396..5c81856bb 100644
--- a/host/lib/usrp/usrp2/dboard_iface.cpp
+++ b/host/lib/usrp/usrp2/dboard_iface.cpp
@@ -168,8 +168,8 @@ void usrp2_dboard_iface::set_pin_ctrl(unit_t unit, boost::uint16_t value){
//write the selection mux value to register
switch(unit){
- case UNIT_RX: _iface->poke32(U2_REG_GPIO_RX_SEL, new_sels); return;
- case UNIT_TX: _iface->poke32(U2_REG_GPIO_TX_SEL, new_sels); return;
+ case UNIT_RX: _iface->poke32(_iface->regs.gpio_rx_sel, new_sels); return;
+ case UNIT_TX: _iface->poke32(_iface->regs.gpio_tx_sel, new_sels); return;
}
}
@@ -177,18 +177,18 @@ void usrp2_dboard_iface::set_gpio_ddr(unit_t unit, boost::uint16_t value){
_ddr_shadow = \
(_ddr_shadow & ~(0xffff << unit_to_shift[unit])) |
(boost::uint32_t(value) << unit_to_shift[unit]);
- _iface->poke32(U2_REG_GPIO_DDR, _ddr_shadow);
+ _iface->poke32(_iface->regs.gpio_ddr, _ddr_shadow);
}
void usrp2_dboard_iface::write_gpio(unit_t unit, boost::uint16_t value){
_gpio_shadow = \
(_gpio_shadow & ~(0xffff << unit_to_shift[unit])) |
(boost::uint32_t(value) << unit_to_shift[unit]);
- _iface->poke32(U2_REG_GPIO_IO, _gpio_shadow);
+ _iface->poke32(_iface->regs.gpio_io, _gpio_shadow);
}
boost::uint16_t usrp2_dboard_iface::read_gpio(unit_t unit){
- return boost::uint16_t(_iface->peek32(U2_REG_GPIO_IO) >> unit_to_shift[unit]);
+ return boost::uint16_t(_iface->peek32(_iface->regs.gpio_io) >> unit_to_shift[unit]);
}
void usrp2_dboard_iface::set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t value){
@@ -197,16 +197,16 @@ void usrp2_dboard_iface::set_atr_reg(unit_t unit, atr_reg_t atr, boost::uint16_t
unit_t, uhd::dict<atr_reg_t, boost::uint32_t>
> unit_to_atr_to_addr = map_list_of
(UNIT_RX, map_list_of
- (ATR_REG_IDLE, U2_REG_ATR_IDLE_RXSIDE)
- (ATR_REG_TX_ONLY, U2_REG_ATR_INTX_RXSIDE)
- (ATR_REG_RX_ONLY, U2_REG_ATR_INRX_RXSIDE)
- (ATR_REG_FULL_DUPLEX, U2_REG_ATR_FULL_RXSIDE)
+ (ATR_REG_IDLE, _iface->regs.atr_idle_rxside)
+ (ATR_REG_TX_ONLY, _iface->regs.atr_intx_rxside)
+ (ATR_REG_RX_ONLY, _iface->regs.atr_inrx_rxside)
+ (ATR_REG_FULL_DUPLEX, _iface->regs.atr_full_rxside)
)
(UNIT_TX, map_list_of
- (ATR_REG_IDLE, U2_REG_ATR_IDLE_TXSIDE)
- (ATR_REG_TX_ONLY, U2_REG_ATR_INTX_TXSIDE)
- (ATR_REG_RX_ONLY, U2_REG_ATR_INRX_TXSIDE)
- (ATR_REG_FULL_DUPLEX, U2_REG_ATR_FULL_TXSIDE)
+ (ATR_REG_IDLE, _iface->regs.atr_idle_txside)
+ (ATR_REG_TX_ONLY, _iface->regs.atr_intx_txside)
+ (ATR_REG_RX_ONLY, _iface->regs.atr_inrx_txside)
+ (ATR_REG_FULL_DUPLEX, _iface->regs.atr_full_txside)
)
;
_iface->poke16(unit_to_atr_to_addr[unit][atr], value);
diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp
index 8942f9d31..3a2a53674 100644
--- a/host/lib/usrp/usrp2/dboard_impl.cpp
+++ b/host/lib/usrp/usrp2/dboard_impl.cpp
@@ -15,10 +15,10 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
-
#include "usrp2_impl.hpp"
#include "usrp2_regs.hpp"
#include "../dsp_utils.hpp"
+#include "../misc_utils.hpp"
#include <uhd/usrp/subdev_props.hpp>
#include <uhd/usrp/dboard_props.hpp>
#include <uhd/utils/assert.hpp>
@@ -35,8 +35,8 @@ using namespace uhd::usrp;
**********************************************************************/
void usrp2_mboard_impl::dboard_init(void){
//read the dboard eeprom to extract the dboard ids
- _rx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_RX_DB, 0, dboard_eeprom_t::num_bytes()));
- _tx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_TX_DB, 0, dboard_eeprom_t::num_bytes()));
+ _rx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(USRP2_I2C_ADDR_RX_DB, 0, dboard_eeprom_t::num_bytes()));
+ _tx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(USRP2_I2C_ADDR_TX_DB, 0, dboard_eeprom_t::num_bytes()));
//create a new dboard interface and manager
_dboard_iface = make_usrp2_dboard_iface(_iface, _clock_ctrl);
@@ -92,6 +92,16 @@ void usrp2_mboard_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){
val = _dboard_iface;
return;
+ case DBOARD_PROP_CODEC:
+ val = _rx_codec_proxy->get_link();
+ return;
+
+ case DBOARD_PROP_GAIN_GROUP:
+ val = make_gain_group(
+ _dboard_manager->get_rx_subdev(name), _rx_codec_proxy->get_link()
+ );
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -103,7 +113,7 @@ void usrp2_mboard_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){
UHD_ASSERT_THROW(_rx_subdevs_in_use.size() == 1);
wax::obj rx_subdev = _dboard_manager->get_rx_subdev(_rx_subdevs_in_use.at(0));
std::cout << "Using: " << rx_subdev[SUBDEV_PROP_NAME].as<std::string>() << std::endl;
- _iface->poke32(U2_REG_DSP_RX_MUX, dsp_type1::calc_rx_mux_word(
+ _iface->poke32(_iface->regs.dsp_rx_mux, dsp_type1::calc_rx_mux_word(
rx_subdev[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()
));
}
@@ -111,7 +121,7 @@ void usrp2_mboard_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){
case DBOARD_PROP_DBOARD_ID:
_rx_db_eeprom.id = val.as<dboard_id_t>();
- _iface->write_eeprom(I2C_ADDR_RX_DB, 0, _rx_db_eeprom.get_eeprom_bytes());
+ _iface->write_eeprom(USRP2_I2C_ADDR_RX_DB, 0, _rx_db_eeprom.get_eeprom_bytes());
return;
default: UHD_THROW_PROP_SET_ERROR();
@@ -151,6 +161,16 @@ void usrp2_mboard_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){
val = _dboard_iface;
return;
+ case DBOARD_PROP_CODEC:
+ val = _tx_codec_proxy->get_link();
+ return;
+
+ case DBOARD_PROP_GAIN_GROUP:
+ val = make_gain_group(
+ _dboard_manager->get_tx_subdev(name), _tx_codec_proxy->get_link()
+ );
+ return;
+
default: UHD_THROW_PROP_GET_ERROR();
}
}
@@ -162,7 +182,7 @@ void usrp2_mboard_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){
UHD_ASSERT_THROW(_tx_subdevs_in_use.size() == 1);
wax::obj tx_subdev = _dboard_manager->get_tx_subdev(_tx_subdevs_in_use.at(0));
std::cout << "Using: " << tx_subdev[SUBDEV_PROP_NAME].as<std::string>() << std::endl;
- _iface->poke32(U2_REG_DSP_TX_MUX, dsp_type1::calc_tx_mux_word(
+ _iface->poke32(_iface->regs.dsp_tx_mux, dsp_type1::calc_tx_mux_word(
tx_subdev[SUBDEV_PROP_CONNECTION].as<subdev_conn_t>()
));
}
@@ -170,7 +190,7 @@ void usrp2_mboard_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){
case DBOARD_PROP_DBOARD_ID:
_tx_db_eeprom.id = val.as<dboard_id_t>();
- _iface->write_eeprom(I2C_ADDR_TX_DB, 0, _tx_db_eeprom.get_eeprom_bytes());
+ _iface->write_eeprom(USRP2_I2C_ADDR_TX_DB, 0, _tx_db_eeprom.get_eeprom_bytes());
return;
default: UHD_THROW_PROP_SET_ERROR();
diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp
index 7d9cdc441..936b1f7a2 100644
--- a/host/lib/usrp/usrp2/dsp_impl.cpp
+++ b/host/lib/usrp/usrp2/dsp_impl.cpp
@@ -86,7 +86,7 @@ void usrp2_mboard_impl::ddc_set(const wax::obj &key, const wax::obj &val){
case DSP_PROP_FREQ_SHIFT:{
double new_freq = val.as<double>();
- _iface->poke32(U2_REG_DSP_RX_FREQ,
+ _iface->poke32(_iface->regs.dsp_rx_freq,
dsp_type1::calc_cordic_word_and_update(new_freq, get_master_clock_freq())
);
_ddc_freq = new_freq; //shadow
@@ -98,11 +98,11 @@ void usrp2_mboard_impl::ddc_set(const wax::obj &key, const wax::obj &val){
_ddc_decim = pick_closest_rate(extact_rate, _allowed_decim_and_interp_rates);
//set the decimation
- _iface->poke32(U2_REG_DSP_RX_DECIM_RATE, dsp_type1::calc_cic_filter_word(_ddc_decim));
+ _iface->poke32(_iface->regs.dsp_rx_decim_rate, dsp_type1::calc_cic_filter_word(_ddc_decim));
//set the scaling
static const boost::int16_t default_rx_scale_iq = 1024;
- _iface->poke32(U2_REG_DSP_RX_SCALE_IQ,
+ _iface->poke32(_iface->regs.dsp_rx_scale_iq,
dsp_type1::calc_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq)
);
}
@@ -161,7 +161,7 @@ void usrp2_mboard_impl::duc_set(const wax::obj &key, const wax::obj &val){
case DSP_PROP_FREQ_SHIFT:{
double new_freq = val.as<double>();
- _iface->poke32(U2_REG_DSP_TX_FREQ,
+ _iface->poke32(_iface->regs.dsp_tx_freq,
dsp_type1::calc_cordic_word_and_update(new_freq, get_master_clock_freq())
);
_duc_freq = new_freq; //shadow
@@ -173,10 +173,10 @@ void usrp2_mboard_impl::duc_set(const wax::obj &key, const wax::obj &val){
_duc_interp = pick_closest_rate(extact_rate, _allowed_decim_and_interp_rates);
//set the interpolation
- _iface->poke32(U2_REG_DSP_TX_INTERP_RATE, dsp_type1::calc_cic_filter_word(_duc_interp));
+ _iface->poke32(_iface->regs.dsp_tx_interp_rate, dsp_type1::calc_cic_filter_word(_duc_interp));
//set the scaling
- _iface->poke32(U2_REG_DSP_TX_SCALE_IQ, dsp_type1::calc_iq_scale_word(_duc_interp));
+ _iface->poke32(_iface->regs.dsp_tx_scale_iq, dsp_type1::calc_iq_scale_word(_duc_interp));
}
return;
diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h
index fd728e393..389ac9892 100644
--- a/host/lib/usrp/usrp2/fw_common.h
+++ b/host/lib/usrp/usrp2/fw_common.h
@@ -44,6 +44,22 @@ extern "C" {
#define USRP2_UDP_CTRL_PORT 49152
#define USRP2_UDP_DATA_PORT 49153
+////////////////////////////////////////////////////////////////////////
+// I2C addresses
+////////////////////////////////////////////////////////////////////////
+#define USRP2_I2C_DEV_EEPROM 0x50 // 24LC02[45]: 7-bits 1010xxx
+#define USRP2_I2C_ADDR_MBOARD (USRP2_I2C_DEV_EEPROM | 0x0)
+#define USRP2_I2C_ADDR_TX_DB (USRP2_I2C_DEV_EEPROM | 0x4)
+#define USRP2_I2C_ADDR_RX_DB (USRP2_I2C_DEV_EEPROM | 0x5)
+
+////////////////////////////////////////////////////////////////////////
+// EEPROM Layout
+////////////////////////////////////////////////////////////////////////
+#define USRP2_EE_MBOARD_REV_LSB 0x00 //1 byte
+#define USRP2_EE_MBOARD_REV_MSB 0x01 //1 byte
+#define USRP2_EE_MBOARD_MAC_ADDR 0x02 //6 bytes
+#define USRP2_EE_MBOARD_IP_ADDR 0x0C //uint32, big-endian
+
typedef enum{
USRP2_CTRL_ID_HUH_WHAT = ' ',
//USRP2_CTRL_ID_FOR_SURE, //TODO error condition enums
@@ -88,12 +104,12 @@ typedef struct{
union{
__stdint(uint32_t) ip_addr;
struct {
- __stdint(uint8_t) dev;
+ __stdint(uint32_t) dev;
+ __stdint(uint32_t) data;
__stdint(uint8_t) miso_edge;
__stdint(uint8_t) mosi_edge;
- __stdint(uint8_t) readback;
- __stdint(uint32_t) data;
__stdint(uint8_t) num_bits;
+ __stdint(uint8_t) readback;
} spi_args;
struct {
__stdint(uint8_t) addr;
diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp
index 0ac988361..c8e22a709 100644
--- a/host/lib/usrp/usrp2/mboard_impl.cpp
+++ b/host/lib/usrp/usrp2/mboard_impl.cpp
@@ -45,8 +45,11 @@ usrp2_mboard_impl::usrp2_mboard_impl(
_iface = usrp2_iface::make(ctrl_transport);
//extract the mboard rev numbers
- _rev_lo = _iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_REV_LSB, 1).at(0);
- _rev_hi = _iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_REV_MSB, 1).at(0);
+ _rev_lo = _iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV_LSB, 1).at(0);
+ _rev_hi = _iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_REV_MSB, 1).at(0);
+
+ //set the device revision (USRP2 or USRP2+) based on the above
+ _iface->set_hw_rev((_rev_hi << 8) | _rev_lo);
//contruct the interfaces to mboard perifs
_clock_ctrl = usrp2_clock_ctrl::make(_iface);
@@ -67,25 +70,26 @@ usrp2_mboard_impl::usrp2_mboard_impl(
_allowed_decim_and_interp_rates.push_back(i);
}
- //init the rx control registers
- _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, _io_helper.get_max_recv_samps_per_packet());
- _iface->poke32(U2_REG_RX_CTRL_NCHANNELS, 1);
- _iface->poke32(U2_REG_RX_CTRL_CLEAR_OVERRUN, 1); //reset
- _iface->poke32(U2_REG_RX_CTRL_VRT_HEADER, 0
+ //setup the vrt rx registers
+ _iface->poke32(_iface->regs.rx_ctrl_nsamps_per_pkt, _io_helper.get_max_recv_samps_per_packet());
+ _iface->poke32(_iface->regs.rx_ctrl_nchannels, 1);
+ _iface->poke32(_iface->regs.rx_ctrl_clear_overrun, 1); //reset
+ _iface->poke32(_iface->regs.rx_ctrl_vrt_header, 0
+
| (0x1 << 28) //if data with stream id
| (0x1 << 26) //has trailer
| (0x3 << 22) //integer time other
| (0x1 << 20) //fractional time sample count
);
- _iface->poke32(U2_REG_RX_CTRL_VRT_STREAM_ID, 0);
- _iface->poke32(U2_REG_RX_CTRL_VRT_TRAILER, 0);
- _iface->poke32(U2_REG_TIME64_TPS, size_t(get_master_clock_freq()));
+ _iface->poke32(_iface->regs.rx_ctrl_vrt_stream_id, 0);
+ _iface->poke32(_iface->regs.rx_ctrl_vrt_trailer, 0);
+ _iface->poke32(_iface->regs.time64_tps, size_t(get_master_clock_freq()));
//init the tx control registers
- _iface->poke32(U2_REG_TX_CTRL_NUM_CHAN, 0); //1 channel
- _iface->poke32(U2_REG_TX_CTRL_CLEAR_STATE, 1); //reset
- _iface->poke32(U2_REG_TX_CTRL_REPORT_SID, 1); //sid 1 (different from rx)
- _iface->poke32(U2_REG_TX_CTRL_POLICY, U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET);
+ _iface->poke32(_iface->regs.tx_ctrl_num_chan, 0); //1 channel
+ _iface->poke32(_iface->regs.tx_ctrl_clear_state, 1); //reset
+ _iface->poke32(_iface->regs.tx_ctrl_report_sid, 1); //sid 1 (different from rx)
+ _iface->poke32(_iface->regs.tx_ctrl_policy, U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET);
//init the ddc
init_ddc_config();
@@ -96,6 +100,9 @@ usrp2_mboard_impl::usrp2_mboard_impl(
//initialize the clock configuration
init_clock_config();
+ //init the codec before the dboard
+ codec_init();
+
//init the tx and rx dboards (do last)
dboard_init();
}
@@ -135,13 +142,13 @@ void usrp2_mboard_impl::update_clock_config(void){
}
//set the pps flags
- _iface->poke32(U2_REG_TIME64_FLAGS, pps_flags);
+ _iface->poke32(_iface->regs.time64_flags, pps_flags);
//clock source ref 10mhz
switch(_clock_config.ref_source){
- case clock_config_t::REF_INT : _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x10); break;
- case clock_config_t::REF_SMA : _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x1C); break;
- case clock_config_t::REF_MIMO: _iface->poke32(U2_REG_MISC_CTRL_CLOCK, 0x15); break;
+ case clock_config_t::REF_INT : _iface->poke32(_iface->regs.misc_ctrl_clock, 0x10); break;
+ case clock_config_t::REF_SMA : _iface->poke32(_iface->regs.misc_ctrl_clock, 0x1C); break;
+ case clock_config_t::REF_MIMO: _iface->poke32(_iface->regs.misc_ctrl_clock, 0x15); break;
default: throw std::runtime_error("usrp2: unhandled clock configuration reference source");
}
@@ -152,22 +159,22 @@ void usrp2_mboard_impl::update_clock_config(void){
void usrp2_mboard_impl::set_time_spec(const time_spec_t &time_spec, bool now){
//set the ticks
- _iface->poke32(U2_REG_TIME64_TICKS, time_spec.get_tick_count(get_master_clock_freq()));
+ _iface->poke32(_iface->regs.time64_ticks, time_spec.get_tick_count(get_master_clock_freq()));
//set the flags register
boost::uint32_t imm_flags = (now)? U2_FLAG_TIME64_LATCH_NOW : U2_FLAG_TIME64_LATCH_NEXT_PPS;
- _iface->poke32(U2_REG_TIME64_IMM, imm_flags);
+ _iface->poke32(_iface->regs.time64_imm, imm_flags);
//set the seconds (latches in all 3 registers)
- _iface->poke32(U2_REG_TIME64_SECS, boost::uint32_t(time_spec.get_full_secs()));
+ _iface->poke32(_iface->regs.time64_secs, boost::uint32_t(time_spec.get_full_secs()));
}
void usrp2_mboard_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){
- _iface->poke32(U2_REG_RX_CTRL_STREAM_CMD, dsp_type1::calc_stream_cmd_word(
+ _iface->poke32(_iface->regs.rx_ctrl_stream_cmd, dsp_type1::calc_stream_cmd_word(
stream_cmd, _io_helper.get_max_recv_samps_per_packet()
));
- _iface->poke32(U2_REG_RX_CTRL_TIME_SECS, boost::uint32_t(stream_cmd.time_spec.get_full_secs()));
- _iface->poke32(U2_REG_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_tick_count(get_master_clock_freq()));
+ _iface->poke32(_iface->regs.rx_ctrl_time_secs, boost::uint32_t(stream_cmd.time_spec.get_full_secs()));
+ _iface->poke32(_iface->regs.rx_ctrl_time_ticks, stream_cmd.time_spec.get_tick_count(get_master_clock_freq()));
}
/***********************************************************************
@@ -180,14 +187,14 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){
//handle the other props
if (key.type() == typeid(std::string)){
if (key.as<std::string>() == "mac-addr"){
- byte_vector_t bytes = _iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_MAC_ADDR, 6);
+ byte_vector_t bytes = _iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, 6);
val = mac_addr_t::from_bytes(bytes).to_string();
return;
}
if (key.as<std::string>() == "ip-addr"){
boost::asio::ip::address_v4::bytes_type bytes;
- std::copy(_iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_IP_ADDR, 4), bytes);
+ std::copy(_iface->read_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, 4), bytes);
val = boost::asio::ip::address_v4(bytes).to_string();
return;
}
@@ -250,7 +257,7 @@ void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){
case MBOARD_PROP_TIME_NOW:{
usrp2_iface::pair64 time64(
- _iface->peek64(U2_REG_TIME64_SECS_RB, U2_REG_TIME64_TICKS_RB)
+ _iface->peek64(_iface->regs.time64_secs_rb, _iface->regs.time64_ticks_rb)
);
val = time_spec_t(
time64.first, time64.second, get_master_clock_freq()
@@ -270,14 +277,14 @@ void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){
if (key.type() == typeid(std::string)){
if (key.as<std::string>() == "mac-addr"){
byte_vector_t bytes = mac_addr_t::from_string(val.as<std::string>()).to_bytes();
- _iface->write_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_MAC_ADDR, bytes);
+ _iface->write_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_MAC_ADDR, bytes);
return;
}
if (key.as<std::string>() == "ip-addr"){
byte_vector_t bytes(4);
std::copy(boost::asio::ip::address_v4::from_string(val.as<std::string>()).to_bytes(), bytes);
- _iface->write_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_IP_ADDR, bytes);
+ _iface->write_eeprom(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_IP_ADDR, bytes);
return;
}
}
diff --git a/host/lib/usrp/usrp2/serdes_ctrl.cpp b/host/lib/usrp/usrp2/serdes_ctrl.cpp
index e83dceb96..1cda22f45 100644
--- a/host/lib/usrp/usrp2/serdes_ctrl.cpp
+++ b/host/lib/usrp/usrp2/serdes_ctrl.cpp
@@ -27,11 +27,11 @@ class usrp2_serdes_ctrl_impl : public usrp2_serdes_ctrl{
public:
usrp2_serdes_ctrl_impl(usrp2_iface::sptr iface){
_iface = iface;
- _iface->poke32(U2_REG_MISC_CTRL_SERDES, U2_FLAG_MISC_CTRL_SERDES_ENABLE | U2_FLAG_MISC_CTRL_SERDES_RXEN);
+ _iface->poke32(_iface->regs.misc_ctrl_serdes, U2_FLAG_MISC_CTRL_SERDES_ENABLE | U2_FLAG_MISC_CTRL_SERDES_RXEN);
}
~usrp2_serdes_ctrl_impl(void){
- _iface->poke32(U2_REG_MISC_CTRL_SERDES, 0); //power-down
+ _iface->poke32(_iface->regs.misc_ctrl_serdes, 0); //power-down
}
private:
diff --git a/host/lib/usrp/usrp2/usrp2_clk_regs.hpp b/host/lib/usrp/usrp2/usrp2_clk_regs.hpp
new file mode 100644
index 000000000..d057fb342
--- /dev/null
+++ b/host/lib/usrp/usrp2/usrp2_clk_regs.hpp
@@ -0,0 +1,63 @@
+//
+// Copyright 2010 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
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_USRP2_CLK_REGS_HPP
+#define INCLUDED_USRP2_CLK_REGS_HPP
+
+#include "usrp2_regs.hpp"
+
+class usrp2_clk_regs_t {
+public:
+ usrp2_clk_regs_t(void) { ; }
+ usrp2_clk_regs_t(int hw_rev) {
+ test = 0;
+ fpga = 1;
+ adc = (hw_rev>=USRP2P_FIRST_HW_REV) ? 2 : 4;
+ dac = 3;
+ serdes = (hw_rev>=USRP2P_FIRST_HW_REV) ? 4 : 2; //only used by usrp2+
+ tx_db = (hw_rev>=USRP2P_FIRST_HW_REV) ? 5 : 6;
+ exp = (hw_rev>=USRP2P_FIRST_HW_REV) ? 6 : 5;
+ rx_db = 7;
+ }
+
+ static int output(int clknum) { return 0x3C + clknum; }
+ static int div_lo(int clknum) { return 0x48 + 2 * clknum; }
+ static int div_hi(int clknum) { return 0x49 + 2 * clknum; }
+
+ const static int acounter = 0x04;
+ const static int bcounter_msb = 0x05;
+ const static int bcounter_lsb = 0x06;
+ const static int pll_1 = 0x07;
+ const static int pll_2 = 0x08;
+ const static int pll_3 = 0x09;
+ const static int pll_4 = 0x0A;
+ const static int ref_counter_msb = 0x0B;
+ const static int ref_counter_lsb = 0x0C;
+ const static int pll_5 = 0x0D;
+ const static int update = 0x5A;
+
+ int test;
+ int fpga;
+ int adc;
+ int dac;
+ int serdes;
+ int exp;
+ int tx_db;
+ int rx_db;
+};
+
+#endif //INCLUDED_USRP2_CLK_REGS_HPP
diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp
index a21157d76..2a380dc44 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.cpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.cpp
@@ -104,7 +104,7 @@ public:
//setup the out data
usrp2_ctrl_data_t out_data;
out_data.id = htonl(USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO);
- out_data.data.spi_args.dev = which_slave;
+ out_data.data.spi_args.dev = htonl(which_slave);
out_data.data.spi_args.miso_edge = spi_edge_to_otw[config.miso_edge];
out_data.data.spi_args.mosi_edge = spi_edge_to_otw[config.mosi_edge];
out_data.data.spi_args.readback = (readback)? 1 : 0;
@@ -193,6 +193,19 @@ public:
throw std::runtime_error("usrp2 no control response");
}
+ /***********************************************************************
+ * Get/set hardware revision
+ **********************************************************************/
+ void set_hw_rev(int rev) {
+ hw_rev = rev;
+ regs = usrp2_get_regs(rev); //might be a better place to do this
+ }
+
+ int get_hw_rev(void) {
+ return hw_rev;
+ }
+
+
private:
//this lovely lady makes it all possible
udp_simple::sptr _ctrl_transport;
diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp
index 9cc32104e..b9f5f0fb8 100644
--- a/host/lib/usrp/usrp2/usrp2_iface.hpp
+++ b/host/lib/usrp/usrp2/usrp2_iface.hpp
@@ -25,22 +25,7 @@
#include <boost/cstdint.hpp>
#include <utility>
#include "fw_common.h"
-
-////////////////////////////////////////////////////////////////////////
-// I2C addresses
-////////////////////////////////////////////////////////////////////////
-#define I2C_DEV_EEPROM 0x50 // 24LC02[45]: 7-bits 1010xxx
-#define I2C_ADDR_MBOARD (I2C_DEV_EEPROM | 0x0)
-#define I2C_ADDR_TX_DB (I2C_DEV_EEPROM | 0x4)
-#define I2C_ADDR_RX_DB (I2C_DEV_EEPROM | 0x5)
-
-////////////////////////////////////////////////////////////////////////
-// EEPROM Layout
-////////////////////////////////////////////////////////////////////////
-#define EE_MBOARD_REV_LSB 0x00 //1 byte
-#define EE_MBOARD_REV_MSB 0x01 //1 byte
-#define EE_MBOARD_MAC_ADDR 0x02 //6 bytes
-#define EE_MBOARD_IP_ADDR 0x0C //uint32, big-endian
+#include "usrp2_regs.hpp"
/*!
* The usrp2 interface class:
@@ -118,6 +103,26 @@ public:
size_t num_bits,
bool readback
) = 0;
+
+ /*!
+ * Set the hardware revision number. Also selects the proper register set for the device.
+ * \param rev the 16-bit revision
+ */
+ virtual void set_hw_rev(int rev) = 0;
+
+ /*! Return the hardware revision number
+ * \return hardware revision
+ */
+ virtual int get_hw_rev(void) = 0;
+
+ /*!
+ * Register map selected from USRP2/USRP2+.
+ */
+ usrp2_regs_t regs;
+ /*!
+ * Hardware revision as returned by the device.
+ */
+ int hw_rev;
};
#endif /* INCLUDED_USRP2_IFACE_HPP */
diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp
index 2eaf12350..8421b6b39 100644
--- a/host/lib/usrp/usrp2/usrp2_impl.hpp
+++ b/host/lib/usrp/usrp2/usrp2_impl.hpp
@@ -161,6 +161,18 @@ private:
void update_clock_config(void);
void set_time_spec(const uhd::time_spec_t &time_spec, bool now);
+ //properties interface for the codec
+ void codec_init(void);
+ void rx_codec_get(const wax::obj &, wax::obj &);
+ void rx_codec_set(const wax::obj &, const wax::obj &);
+ void tx_codec_get(const wax::obj &, wax::obj &);
+ void tx_codec_set(const wax::obj &, const wax::obj &);
+ wax_obj_proxy::sptr _rx_codec_proxy;
+ wax_obj_proxy::sptr _tx_codec_proxy;
+
+ void rx_codec_set_gain(float, const std::string &);
+ uhd::dict<std::string, float> _codec_rx_gains;
+
//properties interface for rx dboard
void rx_dboard_get(const wax::obj &, wax::obj &);
void rx_dboard_set(const wax::obj &, const wax::obj &);
diff --git a/host/lib/usrp/usrp2/usrp2_regs.cpp b/host/lib/usrp/usrp2/usrp2_regs.cpp
new file mode 100644
index 000000000..857fbda9c
--- /dev/null
+++ b/host/lib/usrp/usrp2/usrp2_regs.cpp
@@ -0,0 +1,98 @@
+//
+// Copyright 2010 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
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+#include "usrp2_regs.hpp"
+
+int sr_addr(int misc_output_base, int sr) {
+ return misc_output_base + 4 * sr;
+}
+
+usrp2_regs_t usrp2_get_regs(int hw_rev) {
+
+ //how about you just make this dependent on hw_rev instead of doing the init before main, and give up the const globals, since the application won't ever need both.
+ const int misc_output_base = (hw_rev>=USRP2P_FIRST_HW_REV) ? USRP2P_MISC_OUTPUT_BASE : USRP2_MISC_OUTPUT_BASE,
+ gpio_base = (hw_rev>=USRP2P_FIRST_HW_REV) ? USRP2P_GPIO_BASE : USRP2_GPIO_BASE,
+ atr_base = (hw_rev>=USRP2P_FIRST_HW_REV) ? USRP2P_ATR_BASE : USRP2_ATR_BASE,
+ bp_base = (hw_rev>=USRP2P_FIRST_HW_REV) ? USRP2P_BP_STATUS_BASE : USRP2_BP_STATUS_BASE;
+
+ usrp2_regs_t x;
+ x.sr_misc = 0;
+ x.sr_tx_prot_eng = 32;
+ x.sr_rx_prot_eng = 48;
+ x.sr_buffer_pool_ctrl = 64;
+ x.sr_udp_sm = 96;
+ x.sr_tx_dsp = 208;
+ x.sr_tx_ctrl = 224;
+ x.sr_rx_dsp = 160;
+ x.sr_rx_ctrl = 176;
+ x.sr_time64 = 192;
+ x.sr_simtimer = 198;
+ x.sr_last = 255;
+ x.misc_ctrl_clock = sr_addr(misc_output_base, 0);
+ x.misc_ctrl_serdes = sr_addr(misc_output_base, 1);
+ x.misc_ctrl_adc = sr_addr(misc_output_base, 2);
+ x.misc_ctrl_leds = sr_addr(misc_output_base, 3);
+ x.misc_ctrl_phy = sr_addr(misc_output_base, 4);
+ x.misc_ctrl_dbg_mux = sr_addr(misc_output_base, 5);
+ x.misc_ctrl_ram_page = sr_addr(misc_output_base, 6);
+ x.misc_ctrl_flush_icache = sr_addr(misc_output_base, 7);
+ x.misc_ctrl_led_src = sr_addr(misc_output_base, 8);
+ x.time64_secs = sr_addr(misc_output_base, x.sr_time64 + 0);
+ x.time64_ticks = sr_addr(misc_output_base, x.sr_time64 + 1);
+ x.time64_flags = sr_addr(misc_output_base, x.sr_time64 + 2);
+ x.time64_imm = sr_addr(misc_output_base, x.sr_time64 + 3);
+ x.time64_tps = sr_addr(misc_output_base, x.sr_time64 + 4);
+ x.time64_secs_rb = bp_base + 4*10;
+ x.time64_ticks_rb = bp_base + 4*11;
+ x.dsp_tx_freq = sr_addr(misc_output_base, x.sr_tx_dsp + 0);
+ x.dsp_tx_scale_iq = sr_addr(misc_output_base, x.sr_tx_dsp + 1);
+ x.dsp_tx_interp_rate = sr_addr(misc_output_base, x.sr_tx_dsp + 2);
+ x.dsp_tx_mux = sr_addr(misc_output_base, x.sr_tx_dsp + 4);
+ x.dsp_rx_freq = sr_addr(misc_output_base, x.sr_rx_dsp + 0);
+ x.dsp_rx_scale_iq = sr_addr(misc_output_base, x.sr_rx_dsp + 1);
+ x.dsp_rx_decim_rate = sr_addr(misc_output_base, x.sr_rx_dsp + 2);
+ x.dsp_rx_dcoffset_i = sr_addr(misc_output_base, x.sr_rx_dsp + 3);
+ x.dsp_rx_dcoffset_q = sr_addr(misc_output_base, x.sr_rx_dsp + 4);
+ x.dsp_rx_mux = sr_addr(misc_output_base, x.sr_rx_dsp + 5);
+ x.gpio_io = gpio_base + 0;
+ x.gpio_ddr = gpio_base + 4;
+ x.gpio_tx_sel = gpio_base + 8;
+ x.gpio_rx_sel = gpio_base + 12;
+ x.atr_idle_txside = atr_base + 0;
+ x.atr_idle_rxside = atr_base + 2;
+ x.atr_intx_txside = atr_base + 4;
+ x.atr_intx_rxside = atr_base + 6;
+ x.atr_inrx_txside = atr_base + 8;
+ x.atr_inrx_rxside = atr_base + 10;
+ x.atr_full_txside = atr_base + 12;
+ x.atr_full_rxside = atr_base + 14;
+ x.rx_ctrl_stream_cmd = sr_addr(misc_output_base, x.sr_rx_ctrl + 0);
+ x.rx_ctrl_time_secs = sr_addr(misc_output_base, x.sr_rx_ctrl + 1);
+ x.rx_ctrl_time_ticks = sr_addr(misc_output_base, x.sr_rx_ctrl + 2);
+ x.rx_ctrl_clear_overrun = sr_addr(misc_output_base, x.sr_rx_ctrl + 3);
+ x.rx_ctrl_vrt_header = sr_addr(misc_output_base, x.sr_rx_ctrl + 4);
+ x.rx_ctrl_vrt_stream_id = sr_addr(misc_output_base, x.sr_rx_ctrl + 5);
+ x.rx_ctrl_vrt_trailer = sr_addr(misc_output_base, x.sr_rx_ctrl + 6);
+ x.rx_ctrl_nsamps_per_pkt = sr_addr(misc_output_base, x.sr_rx_ctrl + 7);
+ x.rx_ctrl_nchannels = sr_addr(misc_output_base, x.sr_rx_ctrl + 8);
+ x.tx_ctrl_num_chan = sr_addr(misc_output_base, x.sr_tx_ctrl + 0);
+ x.tx_ctrl_clear_state = sr_addr(misc_output_base, x.sr_tx_ctrl + 1);
+ x.tx_ctrl_report_sid = sr_addr(misc_output_base, x.sr_tx_ctrl + 2);
+ x.tx_ctrl_policy = sr_addr(misc_output_base, x.sr_tx_ctrl + 3);
+
+ return x;
+}
diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp
index cc9094ae7..c12098c8e 100644
--- a/host/lib/usrp/usrp2/usrp2_regs.hpp
+++ b/host/lib/usrp/usrp2/usrp2_regs.hpp
@@ -18,6 +18,92 @@
#ifndef INCLUDED_USRP2_REGS_HPP
#define INCLUDED_USRP2_REGS_HPP
+//these are used to set the
+
+#define USRP2_MISC_OUTPUT_BASE 0xD400
+#define USRP2_GPIO_BASE 0xC800
+#define USRP2_ATR_BASE 0xE400
+#define USRP2_BP_STATUS_BASE 0xCC00
+
+#define USRP2P_MISC_OUTPUT_BASE 0x2000
+#define USRP2P_GPIO_BASE 0x3200
+#define USRP2P_ATR_BASE 0x3800
+#define USRP2P_BP_STATUS_BASE 0x3300
+
+#define USRP2P_FIRST_HW_REV 0x0A00
+
+typedef struct {
+ int sr_misc;
+ int sr_tx_prot_eng;
+ int sr_rx_prot_eng;
+ int sr_buffer_pool_ctrl;
+ int sr_udp_sm;
+ int sr_tx_dsp;
+ int sr_tx_ctrl;
+ int sr_rx_dsp;
+ int sr_rx_ctrl;
+ int sr_time64;
+ int sr_simtimer;
+ int sr_last;
+ int misc_ctrl_clock;
+ int misc_ctrl_serdes;
+ int misc_ctrl_adc;
+ int misc_ctrl_leds;
+ int misc_ctrl_phy;
+ int misc_ctrl_dbg_mux;
+ int misc_ctrl_ram_page;
+ int misc_ctrl_flush_icache;
+ int misc_ctrl_led_src;
+ int time64_secs; // value to set absolute secs to on next PPS
+ int time64_ticks; // value to set absolute ticks to on next PPS
+ int time64_flags; // flags -- see chart below
+ int time64_imm; // set immediate (0=latch on next pps, 1=latch immediate, default=0)
+ int time64_tps; // ticks per second rollover count
+ int time64_secs_rb;
+ int time64_ticks_rb;
+ int dsp_tx_freq;
+ int dsp_tx_scale_iq;
+ int dsp_tx_interp_rate;
+ int dsp_tx_mux;
+ int dsp_rx_freq;
+ int dsp_rx_scale_iq;
+ int dsp_rx_decim_rate;
+ int dsp_rx_dcoffset_i;
+ int dsp_rx_dcoffset_q;
+ int dsp_rx_mux;
+ int gpio_base;
+ int gpio_io;
+ int gpio_ddr;
+ int gpio_tx_sel;
+ int gpio_rx_sel;
+ int atr_base;
+ int atr_idle_txside;
+ int atr_idle_rxside;
+ int atr_intx_txside;
+ int atr_intx_rxside;
+ int atr_inrx_txside;
+ int atr_inrx_rxside;
+ int atr_full_txside;
+ int atr_full_rxside;
+ int rx_ctrl_stream_cmd;
+ int rx_ctrl_time_secs;
+ int rx_ctrl_time_ticks;
+ int rx_ctrl_clear_overrun;
+ int rx_ctrl_vrt_header;
+ int rx_ctrl_vrt_stream_id;
+ int rx_ctrl_vrt_trailer;
+ int rx_ctrl_nsamps_per_pkt;
+ int rx_ctrl_nchannels;
+ int tx_ctrl_num_chan;
+ int tx_ctrl_clear_state;
+ int tx_ctrl_report_sid;
+ int tx_ctrl_policy;
+} usrp2_regs_t;
+
+extern const usrp2_regs_t usrp2_regs; //the register definitions, set in usrp2_regs.cpp and usrp2p_regs.cpp
+
+usrp2_regs_t usrp2_get_regs(int hw_rev);
+
////////////////////////////////////////////////////
// Settings Bus, Slave #7, Not Byte Addressable!
//
@@ -25,27 +111,12 @@
// 1KB of address space (== 256 32-bit write-only regs)
-#define MISC_OUTPUT_BASE 0xD400
+//#define MISC_OUTPUT_BASE 0xD400
//#define TX_PROTOCOL_ENGINE_BASE 0xD480
//#define RX_PROTOCOL_ENGINE_BASE 0xD4C0
//#define BUFFER_POOL_CTRL_BASE 0xD500
//#define LAST_SETTING_REG 0xD7FC // last valid setting register
-#define SR_MISC 0
-#define SR_TX_PROT_ENG 32
-#define SR_RX_PROT_ENG 48
-#define SR_BUFFER_POOL_CTRL 64
-#define SR_UDP_SM 96
-#define SR_TX_DSP 208
-#define SR_TX_CTRL 224
-#define SR_RX_DSP 160
-#define SR_RX_CTRL 176
-#define SR_TIME64 192
-#define SR_SIMTIMER 198
-#define SR_LAST 255
-
-#define _SR_ADDR(sr) ((MISC_OUTPUT_BASE) + (4*(sr)))
-
/////////////////////////////////////////////////
// SPI Slave Constants
////////////////////////////////////////////////
@@ -58,20 +129,11 @@
#define SPI_SS_TX_DAC 32
#define SPI_SS_TX_ADC 64
#define SPI_SS_TX_DB 128
+#define SPI_SS_ADS62P44 256 //for usrp2p
/////////////////////////////////////////////////
// Misc Control
////////////////////////////////////////////////
-#define U2_REG_MISC_CTRL_CLOCK _SR_ADDR(0)
-#define U2_REG_MISC_CTRL_SERDES _SR_ADDR(1)
-#define U2_REG_MISC_CTRL_ADC _SR_ADDR(2)
-#define U2_REG_MISC_CTRL_LEDS _SR_ADDR(3)
-#define U2_REG_MISC_CTRL_PHY _SR_ADDR(4) // LSB is reset line to eth phy
-#define U2_REG_MISC_CTRL_DBG_MUX _SR_ADDR(5)
-#define U2_REG_MISC_CTRL_RAM_PAGE _SR_ADDR(6) // FIXME should go somewhere else...
-#define U2_REG_MISC_CTRL_FLUSH_ICACHE _SR_ADDR(7) // Flush the icache
-#define U2_REG_MISC_CTRL_LED_SRC _SR_ADDR(8) // HW or SW control for LEDs
-
#define U2_FLAG_MISC_CTRL_SERDES_ENABLE 8
#define U2_FLAG_MISC_CTRL_SERDES_PRBSEN 4
#define U2_FLAG_MISC_CTRL_SERDES_LOOPEN 2
@@ -99,14 +161,6 @@
*
* </pre>
*/
-#define U2_REG_TIME64_SECS _SR_ADDR(SR_TIME64 + 0) // value to set absolute secs to on next PPS
-#define U2_REG_TIME64_TICKS _SR_ADDR(SR_TIME64 + 1) // value to set absolute ticks to on next PPS
-#define U2_REG_TIME64_FLAGS _SR_ADDR(SR_TIME64 + 2) // flags - see chart above
-#define U2_REG_TIME64_IMM _SR_ADDR(SR_TIME64 + 3) // set immediate (0=latch on next pps, 1=latch immediate, default=0)
-#define U2_REG_TIME64_TPS _SR_ADDR(SR_TIME64 + 4) // the ticks per second rollover count
-
-#define U2_REG_TIME64_SECS_RB (0xCC00 + 4*10)
-#define U2_REG_TIME64_TICKS_RB (0xCC00 + 4*11)
//pps flags (see above)
#define U2_FLAG_TIME64_PPS_NEGEDGE (0 << 0)
@@ -120,9 +174,6 @@
/////////////////////////////////////////////////
// DSP TX Regs
////////////////////////////////////////////////
-#define U2_REG_DSP_TX_FREQ _SR_ADDR(SR_TX_DSP + 0)
-#define U2_REG_DSP_TX_SCALE_IQ _SR_ADDR(SR_TX_DSP + 1) // {scale_i,scale_q}
-#define U2_REG_DSP_TX_INTERP_RATE _SR_ADDR(SR_TX_DSP + 2)
/*!
* \brief output mux configuration.
@@ -158,17 +209,11 @@
* The default value is 0x10
* </pre>
*/
-#define U2_REG_DSP_TX_MUX _SR_ADDR(SR_TX_DSP + 4)
/////////////////////////////////////////////////
// DSP RX Regs
////////////////////////////////////////////////
-#define U2_REG_DSP_RX_FREQ _SR_ADDR(SR_RX_DSP + 0)
-#define U2_REG_DSP_RX_SCALE_IQ _SR_ADDR(SR_RX_DSP + 1) // {scale_i,scale_q}
-#define U2_REG_DSP_RX_DECIM_RATE _SR_ADDR(SR_RX_DSP + 2)
-#define U2_REG_DSP_RX_DCOFFSET_I _SR_ADDR(SR_RX_DSP + 3) // Bit 31 high sets fixed offset mode, using lower 14 bits,
- // otherwise it is automatic
-#define U2_REG_DSP_RX_DCOFFSET_Q _SR_ADDR(SR_RX_DSP + 4) // Bit 31 high sets fixed offset mode, using lower 14 bits
+
/*!
* \brief input mux configuration.
*
@@ -190,20 +235,10 @@
* The default value is 0x4
* </pre>
*/
-#define U2_REG_DSP_RX_MUX _SR_ADDR(SR_RX_DSP + 5) // called adc_mux in dsp_core_rx.v
////////////////////////////////////////////////
// GPIO, Slave 4
////////////////////////////////////////////////
-//
-// These go to the daughterboard i/o pins
-//
-#define U2_REG_GPIO_BASE 0xC800
-
-#define U2_REG_GPIO_IO U2_REG_GPIO_BASE + 0 // 32 bits, gpio io pins (tx high 16 bits, rx low 16 bits)
-#define U2_REG_GPIO_DDR U2_REG_GPIO_BASE + 4 // 32 bits, gpio ddr, 1 means output (tx high 16 bits, rx low 16 bits)
-#define U2_REG_GPIO_TX_SEL U2_REG_GPIO_BASE + 8 // 16 2-bit fields select which source goes to TX DB
-#define U2_REG_GPIO_RX_SEL U2_REG_GPIO_BASE + 12 // 16 2-bit fields select which source goes to RX DB
// each 2-bit sel field is layed out this way
#define U2_FLAG_GPIO_SEL_GPIO 0 // if pin is an output, set by GPIO register
@@ -214,40 +249,20 @@
///////////////////////////////////////////////////
// ATR Controller, Slave 11
////////////////////////////////////////////////
-#define U2_REG_ATR_BASE 0xE400
-#define U2_REG_ATR_IDLE_TXSIDE U2_REG_ATR_BASE + 0
-#define U2_REG_ATR_IDLE_RXSIDE U2_REG_ATR_BASE + 2
-#define U2_REG_ATR_INTX_TXSIDE U2_REG_ATR_BASE + 4
-#define U2_REG_ATR_INTX_RXSIDE U2_REG_ATR_BASE + 6
-#define U2_REG_ATR_INRX_TXSIDE U2_REG_ATR_BASE + 8
-#define U2_REG_ATR_INRX_RXSIDE U2_REG_ATR_BASE + 10
-#define U2_REG_ATR_FULL_TXSIDE U2_REG_ATR_BASE + 12
-#define U2_REG_ATR_FULL_RXSIDE U2_REG_ATR_BASE + 14
///////////////////////////////////////////////////
// RX CTRL regs
///////////////////////////////////////////////////
-// The following 3 are logically a single command register.
-// They are clocked into the underlying fifo when time_ticks is written.
-#define U2_REG_RX_CTRL_STREAM_CMD _SR_ADDR(SR_RX_CTRL + 0) // {now, chain, num_samples(30)
-#define U2_REG_RX_CTRL_TIME_SECS _SR_ADDR(SR_RX_CTRL + 1)
-#define U2_REG_RX_CTRL_TIME_TICKS _SR_ADDR(SR_RX_CTRL + 2)
-#define U2_REG_RX_CTRL_CLEAR_OVERRUN _SR_ADDR(SR_RX_CTRL + 3) // write anything to clear overrun
-#define U2_REG_RX_CTRL_VRT_HEADER _SR_ADDR(SR_RX_CTRL + 4) // word 0 of packet. FPGA fills in packet counter
-#define U2_REG_RX_CTRL_VRT_STREAM_ID _SR_ADDR(SR_RX_CTRL + 5) // word 1 of packet.
-#define U2_REG_RX_CTRL_VRT_TRAILER _SR_ADDR(SR_RX_CTRL + 6)
-#define U2_REG_RX_CTRL_NSAMPS_PER_PKT _SR_ADDR(SR_RX_CTRL + 7)
-#define U2_REG_RX_CTRL_NCHANNELS _SR_ADDR(SR_RX_CTRL + 8) // 1 in basic case, up to 4 for vector sources
///////////////////////////////////////////////////
// TX CTRL regs
///////////////////////////////////////////////////
-#define U2_REG_TX_CTRL_NUM_CHAN _SR_ADDR(SR_TX_CTRL + 0)
-#define U2_REG_TX_CTRL_CLEAR_STATE _SR_ADDR(SR_TX_CTRL + 1)
-#define U2_REG_TX_CTRL_REPORT_SID _SR_ADDR(SR_TX_CTRL + 2)
-#define U2_REG_TX_CTRL_POLICY _SR_ADDR(SR_TX_CTRL + 3)
+//#define U2_REG_TX_CTRL_NUM_CHAN _SR_ADDR(SR_TX_CTRL + 0)
+//#define U2_REG_TX_CTRL_CLEAR_STATE _SR_ADDR(SR_TX_CTRL + 1)
+//#define U2_REG_TX_CTRL_REPORT_SID _SR_ADDR(SR_TX_CTRL + 2)
+//#define U2_REG_TX_CTRL_POLICY _SR_ADDR(SR_TX_CTRL + 3)
#define U2_FLAG_TX_CTRL_POLICY_WAIT (0x1 << 0)
#define U2_FLAG_TX_CTRL_POLICY_NEXT_PACKET (0x1 << 1)