summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Blum <josh@joshknows.com>2010-04-23 16:05:57 -0700
committerJosh Blum <josh@joshknows.com>2010-04-23 16:05:57 -0700
commit0c3af59014f1ef3f03c099a15e74d3cdc629ef7e (patch)
tree6917a51f266d848d0b57856836912744ab22b321
parent19a2f02768e03ced30a32dfc0a703068a8d99176 (diff)
parenta29b30fdf17b5703c9b5c5dd015f11ecd44fbdfe (diff)
downloaduhd-0c3af59014f1ef3f03c099a15e74d3cdc629ef7e.tar.gz
uhd-0c3af59014f1ef3f03c099a15e74d3cdc629ef7e.tar.bz2
uhd-0c3af59014f1ef3f03c099a15e74d3cdc629ef7e.zip
Merge branch 'xcvr' of git@ettus.sourcerepo.com:ettus/uhdpriv
-rw-r--r--host/README1
-rw-r--r--host/lib/CMakeLists.txt16
-rw-r--r--host/lib/ic_reg_maps/common.py23
-rwxr-xr-xhost/lib/ic_reg_maps/gen_ad5624_regs.py23
-rwxr-xr-xhost/lib/ic_reg_maps/gen_ad7922_regs.py23
-rwxr-xr-xhost/lib/ic_reg_maps/gen_ad9510_regs.py23
-rwxr-xr-xhost/lib/ic_reg_maps/gen_ad9777_regs.py23
-rwxr-xr-xhost/lib/ic_reg_maps/gen_adf4360_regs.py23
-rwxr-xr-xhost/lib/ic_reg_maps/gen_max2829_regs.py166
-rw-r--r--host/lib/usrp/dboard/db_rfx.cpp2
-rw-r--r--host/lib/usrp/dboard/db_xcvr2450.cpp593
-rw-r--r--host/lib/usrp/usrp2/dboard_impl.cpp2
12 files changed, 836 insertions, 82 deletions
diff --git a/host/README b/host/README
index 05a53b197..e67bb25f8 100644
--- a/host/README
+++ b/host/README
@@ -16,6 +16,7 @@ Basic TX
LF RX
LF TX
RFX Series
+XCVR 2450
########################################################################
# Documentation
diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt
index 7cb74d30a..5495620ec 100644
--- a/host/lib/CMakeLists.txt
+++ b/host/lib/CMakeLists.txt
@@ -54,8 +54,6 @@ SET(libuhd_sources
transport/convert_types.cpp
transport/if_addrs.cpp
transport/udp_simple.cpp
- usrp/dboard/db_basic_and_lf.cpp
- usrp/dboard/db_rfx.cpp
usrp/dboard_base.cpp
usrp/simple_usrp.cpp
usrp/dboard_manager.cpp
@@ -113,6 +111,20 @@ UHD_PYTHON_GEN_SOURCE_FILE(
${CMAKE_CURRENT_BINARY_DIR}/ic_reg_maps/ad7922_regs.hpp
)
+UHD_PYTHON_GEN_SOURCE_FILE(
+ ${CMAKE_CURRENT_SOURCE_DIR}/ic_reg_maps/gen_max2829_regs.py
+ ${CMAKE_CURRENT_BINARY_DIR}/ic_reg_maps/max2829_regs.hpp
+)
+
+########################################################################
+# Add dboard sources
+########################################################################
+LIST(APPEND libuhd_sources
+ usrp/dboard/db_basic_and_lf.cpp
+ usrp/dboard/db_rfx.cpp
+ usrp/dboard/db_xcvr2450.cpp
+)
+
########################################################################
# Add usrp2 sources
########################################################################
diff --git a/host/lib/ic_reg_maps/common.py b/host/lib/ic_reg_maps/common.py
index bf51073ae..d05470706 100644
--- a/host/lib/ic_reg_maps/common.py
+++ b/host/lib/ic_reg_maps/common.py
@@ -1,22 +1,19 @@
#
-# Copyright 2008,2009 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
+# 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 asversion 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
+# 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 GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
import re
import math
diff --git a/host/lib/ic_reg_maps/gen_ad5624_regs.py b/host/lib/ic_reg_maps/gen_ad5624_regs.py
index a809d2f47..9e8ae5be5 100755
--- a/host/lib/ic_reg_maps/gen_ad5624_regs.py
+++ b/host/lib/ic_reg_maps/gen_ad5624_regs.py
@@ -1,23 +1,20 @@
#!/usr/bin/env python
#
-# Copyright 2008,2009 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
+# 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 asversion 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
+# 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 GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
import sys
from common import *
diff --git a/host/lib/ic_reg_maps/gen_ad7922_regs.py b/host/lib/ic_reg_maps/gen_ad7922_regs.py
index 512dcdc46..23f28c0da 100755
--- a/host/lib/ic_reg_maps/gen_ad7922_regs.py
+++ b/host/lib/ic_reg_maps/gen_ad7922_regs.py
@@ -1,23 +1,20 @@
#!/usr/bin/env python
#
-# Copyright 2008,2009 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
+# 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 asversion 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
+# 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 GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
import sys
from common import *
diff --git a/host/lib/ic_reg_maps/gen_ad9510_regs.py b/host/lib/ic_reg_maps/gen_ad9510_regs.py
index 4f28d5597..2dc19c691 100755
--- a/host/lib/ic_reg_maps/gen_ad9510_regs.py
+++ b/host/lib/ic_reg_maps/gen_ad9510_regs.py
@@ -1,23 +1,20 @@
#!/usr/bin/env python
#
-# Copyright 2008,2009 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
+# 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 asversion 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
+# 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 GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
import sys
from common import *
diff --git a/host/lib/ic_reg_maps/gen_ad9777_regs.py b/host/lib/ic_reg_maps/gen_ad9777_regs.py
index 65a9657a4..2ac73efcf 100755
--- a/host/lib/ic_reg_maps/gen_ad9777_regs.py
+++ b/host/lib/ic_reg_maps/gen_ad9777_regs.py
@@ -1,23 +1,20 @@
#!/usr/bin/env python
#
-# Copyright 2008,2009 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
+# 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 asversion 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
+# 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 GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
import sys
from common import *
diff --git a/host/lib/ic_reg_maps/gen_adf4360_regs.py b/host/lib/ic_reg_maps/gen_adf4360_regs.py
index c659766dc..478e471a3 100755
--- a/host/lib/ic_reg_maps/gen_adf4360_regs.py
+++ b/host/lib/ic_reg_maps/gen_adf4360_regs.py
@@ -1,23 +1,20 @@
#!/usr/bin/env python
#
-# Copyright 2008,2009 Free Software Foundation, Inc.
-#
-# This file is part of GNU Radio
-#
-# GNU Radio is free software; you can redistribute it and/or modify
+# 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 asversion 3, or (at your option)
-# any later version.
-#
-# GNU Radio is distributed in the hope that it will be useful,
+# 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 GNU Radio; see the file COPYING. If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
import sys
from common import *
diff --git a/host/lib/ic_reg_maps/gen_max2829_regs.py b/host/lib/ic_reg_maps/gen_max2829_regs.py
new file mode 100755
index 000000000..7fef302a8
--- /dev/null
+++ b/host/lib/ic_reg_maps/gen_max2829_regs.py
@@ -0,0 +1,166 @@
+#!/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/>.
+#
+
+import sys
+from common import *
+
+########################################################################
+# Template for raw text data describing registers
+# name addr[bit range inclusive] default optional enums
+########################################################################
+REGS_DATA_TMPL="""\
+########################################################################
+## Note: offsets given from perspective of data bits (excludes address)
+########################################################################
+##
+########################################################################
+## Standby (2)
+########################################################################
+_set_to_1_2_0 2[0] 1
+_set_to_1_2_1 2[1] 1
+_set_to_1_2_2 2[2] 1
+pa_bias_dac 2[10] 0
+voltage_ref 2[11] 0
+_set_to_1_2_12 2[12] 1
+mimo_select 2[13] 0 normal, mimo
+########################################################################
+## Integer Divider Ratio (3)
+########################################################################
+int_div_ratio_word 3[0:7] a2
+frac_div_ratio_lsb 3[12:13] 0
+########################################################################
+## Fractional Divider Ratio (4)
+########################################################################
+frac_div_ratio_msb 4[0:13] 0
+########################################################################
+## Band Select and PLL (5)
+########################################################################
+band_select 5[0] 0 2_4ghz, 5ghz
+ref_divider 5[1:3] 1
+pll_cp_select 5[5] 1 2ma, 4ma
+band_select_802_11a 5[6] 0 4_9ghz_to_5_35ghz, 5_47ghz_to_5_875ghz
+vco_bandswitch 5[7] 0 disable, automatic
+vco_spi_bandswitch 5[8] 0 fsm, spi
+vco_sub_band 5[9:10] 0
+_set_to_1_5_11 5[11] 1
+_set_to_1_5_12 5[12] 1
+band_sel_mimo 5[13] 0 normal, mimo
+########################################################################
+## Calibration (6)
+########################################################################
+rx_cal_mode 6[0] 0 dis, enb
+tx_cal_mode 6[1] 0 dis, enb
+_set_to_1_6_10 6[10] 1
+iq_cal_gain 6[11:12] 3 8db, 18db, 24db, 34db
+########################################################################
+## Lowpass Filter (7)
+########################################################################
+rx_lpf_fine_adj 7[0:2] 2 90, 95, 100, 105, 110
+rx_lpf_coarse_adj 7[3:4] 1 7_5mhz, 9_5mhz, 14mhz, 18mhz
+tx_lpf_coarse_adj 7[5:6] 1 12mhz=1, 18mhz=2, 24mhz=3
+rssi_high_bw 7[11] 0 2mhz, 6mhz
+########################################################################
+## Rx Control/RSSI (8)
+########################################################################
+_set_to_1_8_0 8[0] 1
+rx_highpass 8[2] 1 100hz, 30khz
+_set_to_1_8_5 8[5] 1
+rssi_pin_fcn 8[8] 0 rssi, temp
+rssi_op_mode 8[10] 0 rssi_rxhp, enabled
+rssi_output_range 8[11] 0 low, high
+rx_vga_gain_spi 8[12] 0 io, spi
+########################################################################
+## Tx Linearity/Baseband Gain (9)
+########################################################################
+tx_baseband_gain 9[0:1] 0 0db, 2db, 3_5db, 5db
+tx_upconv_linearity 9[2:3] 0 50, 63, 78, 100
+tx_vga_linearity 9[6:7] 0 50, 63, 78, 100
+pa_driver_linearity 9[8:9] 2 50, 63, 78, 100
+tx_vga_gain_spi 9[10] 0 io, spi
+########################################################################
+## PA Bias DAC (10)
+########################################################################
+pa_bias_dac_out_curr a[0:5] 0
+pa_bias_dac_delay a[6:9] f
+########################################################################
+## Rx Gain (11)
+########################################################################
+rx_vga_gain b[0:4] 1f
+rx_lna_gain b[5:6] 3
+########################################################################
+## Tx VGA Gain (12)
+########################################################################
+tx_vga_gain c[0:5] 0
+"""
+
+########################################################################
+# Header and Source templates below
+########################################################################
+HEADER_TEXT="""
+#import time
+
+/***********************************************************************
+ * This file was generated by $file on $time.strftime("%c")
+ **********************************************************************/
+
+\#ifndef INCLUDED_MAX2829_REGS_HPP
+\#define INCLUDED_MAX2829_REGS_HPP
+
+\#include <boost/cstdint.hpp>
+
+struct max2829_regs_t{
+#for $reg in $regs
+ #if $reg.get_enums()
+ enum $(reg.get_name())_t{
+ #for $i, $enum in enumerate($reg.get_enums())
+ #set $end_comma = ',' if $i < len($reg.get_enums())-1 else ''
+ $(reg.get_name().upper())_$(enum[0].upper()) = $enum[1]$end_comma
+ #end for
+ } $reg.get_name();
+ #else
+ boost::$reg.get_stdint_type() $reg.get_name();
+ #end if
+#end for
+
+ max2829_regs_t(void){
+#for $reg in $regs
+ $reg.get_name() = $reg.get_default();
+#end for
+ }
+
+ boost::uint32_t get_reg(boost::uint8_t addr){
+ boost::uint16_t reg = 0;
+ switch(addr){
+ #for $addr in range(2, 12+1)
+ case $addr:
+ #for $reg in filter(lambda r: r.get_addr() == addr, $regs)
+ reg |= (boost::uint16_t($reg.get_name()) & $reg.get_mask()) << $reg.get_shift();
+ #end for
+ break;
+ #end for
+ }
+ return (boost::uint32_t(reg) << 4) | (addr & 0xf);
+ }
+};
+
+\#endif /* INCLUDED_MAX2829_REGS_HPP */
+"""
+
+if __name__ == '__main__':
+ regs = map(reg, parse_tmpl(REGS_DATA_TMPL).splitlines())
+ open(sys.argv[1], 'w').write(parse_tmpl(HEADER_TEXT, regs=regs, file=__file__))
diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp
index cd5b8447b..76b2c6d7a 100644
--- a/host/lib/usrp/dboard/db_rfx.cpp
+++ b/host/lib/usrp/dboard/db_rfx.cpp
@@ -430,7 +430,7 @@ void rfx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){
* TX Get and Set
**********************************************************************/
void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){
- wax::obj key; std::string name;
+ wax::obj key; std::string name;
boost::tie(key, name) = extract_named_prop(key_);
//handle the get request conditioned on the key
diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp
new file mode 100644
index 000000000..2c2843d3a
--- /dev/null
+++ b/host/lib/usrp/dboard/db_xcvr2450.cpp
@@ -0,0 +1,593 @@
+//
+// 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/>.
+//
+
+// TX IO Pins
+#define HB_PA_OFF_TXIO (1 << 15) // 5GHz PA, 1 = off, 0 = on
+#define LB_PA_OFF_TXIO (1 << 14) // 2.4GHz PA, 1 = off, 0 = on
+#define ANTSEL_TX1_RX2_TXIO (1 << 13) // 1 = Ant 1 to TX, Ant 2 to RX
+#define ANTSEL_TX2_RX1_TXIO (1 << 12) // 1 = Ant 2 to TX, Ant 1 to RX
+#define TX_EN_TXIO (1 << 11) // 1 = TX on, 0 = TX off
+#define AD9515DIV_TXIO (1 << 4) // 1 = Div by 3, 0 = Div by 2
+
+#define TXIO_MASK (HB_PA_OFF_TXIO | LB_PA_OFF_TXIO | ANTSEL_TX1_RX2_TXIO | ANTSEL_TX2_RX1_TXIO | TX_EN_TXIO | AD9515DIV_TXIO)
+
+// TX IO Functions
+#define HB_PA_TXIO LB_PA_OFF_TXIO
+#define LB_PA_TXIO HB_PA_OFF_TXIO
+#define TX_ENB_TXIO TX_EN_TXIO
+#define TX_DIS_TXIO 0
+#define AD9515DIV_3_TXIO AD9515DIV_TXIO
+#define AD9515DIV_2_TXIO 0
+
+// RX IO Pins
+#define LOCKDET_RXIO (1 << 15) // This is an INPUT!!!
+#define POWER_RXIO (1 << 14) // 1 = power on, 0 = shutdown
+#define RX_EN_RXIO (1 << 13) // 1 = RX on, 0 = RX off
+#define RX_HP_RXIO (1 << 12) // 0 = Fc set by rx_hpf, 1 = 600 KHz
+
+#define RXIO_MASK (POWER_RXIO | RX_EN_RXIO | RX_HP_RXIO)
+
+// RX IO Functions
+#define POWER_UP_RXIO POWER_RXIO
+#define POWER_DOWN_RXIO 0
+#define RX_ENB_RXIO RX_EN_RXIO
+#define RX_DIS_RXIO 0
+
+#include "max2829_regs.hpp"
+#include <uhd/utils/static.hpp>
+#include <uhd/utils/assert.hpp>
+#include <uhd/utils/algorithm.hpp>
+#include <uhd/types/ranges.hpp>
+#include <uhd/types/dict.hpp>
+#include <uhd/usrp/subdev_props.hpp>
+#include <uhd/usrp/dboard_base.hpp>
+#include <uhd/usrp/dboard_manager.hpp>
+#include <boost/assign/list_of.hpp>
+#include <boost/format.hpp>
+#include <boost/thread.hpp>
+#include <boost/math/special_functions/round.hpp>
+#include <utility>
+
+using namespace uhd;
+using namespace uhd::usrp;
+using namespace boost::assign;
+
+/***********************************************************************
+ * The XCVR 2450 constants
+ **********************************************************************/
+static const bool xcvr2450_debug = false;
+
+static const freq_range_t xcvr_freq_range(2.4e9, 6.0e9);
+
+static const prop_names_t xcvr_antennas = list_of("J1")("J2");
+
+static const uhd::dict<std::string, gain_range_t> xcvr_tx_gain_ranges = map_list_of
+ ("VGA", gain_range_t(0, 30, 0.5))
+ ("BB", gain_range_t(0, 5, 1.5))
+;
+static const uhd::dict<std::string, gain_range_t> xcvr_rx_gain_ranges = map_list_of
+ ("LNA", gain_range_t(0, 30.5, 15))
+ ("VGA", gain_range_t(0, 62, 2.0))
+;
+
+/***********************************************************************
+ * The XCVR 2450 dboard class
+ **********************************************************************/
+class xcvr2450 : public xcvr_dboard_base{
+public:
+ xcvr2450(ctor_args_t const& args);
+ ~xcvr2450(void);
+
+ void rx_get(const wax::obj &key, wax::obj &val);
+ void rx_set(const wax::obj &key, const wax::obj &val);
+
+ void tx_get(const wax::obj &key, wax::obj &val);
+ void tx_set(const wax::obj &key, const wax::obj &val);
+
+private:
+ double _lo_freq;
+ uhd::dict<std::string, float> _tx_gains, _rx_gains;
+ std::string _tx_ant, _rx_ant;
+ int _ad9515div;
+ max2829_regs_t _max2829_regs;
+
+ void set_lo_freq(double target_freq);
+ void set_tx_ant(const std::string &ant);
+ void set_rx_ant(const std::string &ant);
+ void set_tx_gain(float gain, const std::string &name);
+ void set_rx_gain(float gain, const std::string &name);
+
+ void update_atr(void);
+ void spi_reset(void);
+ void send_reg(boost::uint8_t addr){
+ boost::uint32_t value = _max2829_regs.get_reg(addr);
+ if(xcvr2450_debug) std::cerr << boost::format(
+ "XCVR2450: send reg 0x%02x, value 0x%05x"
+ ) % int(addr) % value << std::endl;
+ this->get_iface()->write_spi(
+ dboard_iface::UNIT_RX,
+ spi_config_t::EDGE_RISE,
+ value, 24
+ );
+ }
+
+ static bool is_highband(double freq){return freq > 3e9;}
+};
+
+/***********************************************************************
+ * Register the XCVR 2450 dboard
+ **********************************************************************/
+static dboard_base::sptr make_xcvr2450(dboard_base::ctor_args_t const& args){
+ return dboard_base::sptr(new xcvr2450(args));
+}
+
+UHD_STATIC_BLOCK(reg_xcvr2450_dboard){
+ //register the factory function for the rx and tx dbids
+ dboard_manager::register_dboard(0x0060, &make_xcvr2450, "XCVR2450 TX");
+ dboard_manager::register_dboard(0x0061, &make_xcvr2450, "XCVR2450 RX");
+}
+
+/***********************************************************************
+ * Structors
+ **********************************************************************/
+xcvr2450::xcvr2450(ctor_args_t const& args) : xcvr_dboard_base(args){
+ //enable only the clocks we need
+ this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true);
+
+ //set the gpio directions
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, TXIO_MASK);
+ this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, RXIO_MASK);
+
+ spi_reset(); //prepare the spi
+
+ //setup the misc max2829 registers
+ _max2829_regs.mimo_select = max2829_regs_t::MIMO_SELECT_MIMO;
+ _max2829_regs.band_sel_mimo = max2829_regs_t::BAND_SEL_MIMO_MIMO;
+ _max2829_regs.pll_cp_select = max2829_regs_t::PLL_CP_SELECT_4MA;
+ _max2829_regs.rssi_high_bw = max2829_regs_t::RSSI_HIGH_BW_6MHZ;
+ _max2829_regs.tx_lpf_coarse_adj = max2829_regs_t::TX_LPF_COARSE_ADJ_12MHZ;
+ _max2829_regs.rx_lpf_coarse_adj = max2829_regs_t::RX_LPF_COARSE_ADJ_9_5MHZ;
+ _max2829_regs.rx_lpf_fine_adj = max2829_regs_t::RX_LPF_FINE_ADJ_95;
+ _max2829_regs.rx_vga_gain_spi = max2829_regs_t::RX_VGA_GAIN_SPI_SPI;
+ _max2829_regs.rssi_output_range = max2829_regs_t::RSSI_OUTPUT_RANGE_HIGH;
+ _max2829_regs.rssi_op_mode = max2829_regs_t::RSSI_OP_MODE_ENABLED;
+ _max2829_regs.rssi_pin_fcn = max2829_regs_t::RSSI_PIN_FCN_RSSI;
+ _max2829_regs.rx_highpass = max2829_regs_t::RX_HIGHPASS_100HZ;
+ _max2829_regs.tx_vga_gain_spi = max2829_regs_t::TX_VGA_GAIN_SPI_SPI;
+ _max2829_regs.pa_driver_linearity = max2829_regs_t::PA_DRIVER_LINEARITY_78;
+ _max2829_regs.tx_vga_linearity = max2829_regs_t::TX_VGA_LINEARITY_78;
+ _max2829_regs.tx_upconv_linearity = max2829_regs_t::TX_UPCONV_LINEARITY_78;
+
+ //send initial register settings
+ for(boost::uint8_t reg = 0x2; reg <= 0xC; reg++){
+ this->send_reg(reg);
+ }
+
+ //set defaults for LO, gains, antennas
+ set_lo_freq(2.45e9);
+ set_rx_ant(xcvr_antennas.at(0));
+ set_tx_ant(xcvr_antennas.at(1));
+ BOOST_FOREACH(const std::string &name, xcvr_tx_gain_ranges.keys()){
+ set_tx_gain(xcvr_tx_gain_ranges[name].min, name);
+ }
+ BOOST_FOREACH(const std::string &name, xcvr_rx_gain_ranges.keys()){
+ set_rx_gain(xcvr_rx_gain_ranges[name].min, name);
+ }
+}
+
+xcvr2450::~xcvr2450(void){
+ spi_reset();
+}
+
+void xcvr2450::spi_reset(void){
+ //spi reset mode: global enable = off, tx and rx enable = on
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE, TX_ENB_TXIO);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, RX_ENB_RXIO | POWER_DOWN_RXIO);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+
+ //take it back out of spi reset mode and wait a bit
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, RX_DIS_RXIO | POWER_UP_RXIO);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+}
+
+void xcvr2450::update_atr(void){
+ //calculate tx atr pins
+ int band_sel = (xcvr2450::is_highband(_lo_freq))? HB_PA_TXIO : LB_PA_TXIO;
+ int tx_ant_sel = (_tx_ant == "J1")? ANTSEL_TX1_RX2_TXIO : ANTSEL_TX2_RX1_TXIO;
+ int rx_ant_sel = (_rx_ant == "J2")? ANTSEL_TX1_RX2_TXIO : ANTSEL_TX2_RX1_TXIO;
+ int xx_ant_sel = tx_ant_sel; //prefer the tx antenna selection for full duplex (rx will get the other antenna)
+ int ad9515div = (_ad9515div == 3)? AD9515DIV_3_TXIO : AD9515DIV_2_TXIO;
+
+ //set the tx registers
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE, band_sel | ad9515div | TX_DIS_TXIO);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY, band_sel | ad9515div | TX_DIS_TXIO | rx_ant_sel);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY, band_sel | ad9515div | TX_ENB_TXIO | tx_ant_sel);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, band_sel | ad9515div | TX_ENB_TXIO | xx_ant_sel);
+
+ //set the rx registers
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, POWER_UP_RXIO | RX_DIS_RXIO);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, POWER_UP_RXIO | RX_ENB_RXIO);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, POWER_UP_RXIO | RX_DIS_RXIO);
+ this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, POWER_UP_RXIO | RX_ENB_RXIO);
+}
+
+/***********************************************************************
+ * Tuning
+ **********************************************************************/
+void xcvr2450::set_lo_freq(double target_freq){
+ target_freq = std::clip(target_freq, xcvr_freq_range.min, xcvr_freq_range.max);
+ //TODO: clip for highband and lowband
+
+ //variables used in the calculation below
+ double scaler = xcvr2450::is_highband(target_freq)? (4.0/5.0) : (4.0/3.0);
+ double ref_freq = this->get_iface()->get_clock_rate(dboard_iface::UNIT_TX);
+ int R, intdiv, fracdiv;
+
+ //loop through values until we get a match
+ for(_ad9515div = 2; _ad9515div <= 3; _ad9515div++){
+ for(R = 1; R <= 7; R++){
+ double N = (target_freq*scaler*R*_ad9515div)/ref_freq;
+ intdiv = int(std::floor(N));
+ fracdiv = (N - intdiv)*double(1 << 16);
+ //actual minimum is 128, but most chips seems to require higher to lock
+ if (intdiv < 131 or intdiv > 255) continue;
+ //constraints met: exit loop
+ goto done_loop;
+ }
+ } done_loop:
+
+ //calculate the actual freq from the values above
+ double N = double(intdiv) + double(fracdiv)/double(1 << 16);
+ _lo_freq = (N*ref_freq)/(scaler*R*_ad9515div);
+
+ if (xcvr2450_debug) std::cerr
+ << boost::format("XCVR2450 tune:\n")
+ << boost::format(" R=%d, N=%f, ad9515=%d, scaler=%f\n") % R % N % _ad9515div % scaler
+ << boost::format(" Ref Freq=%fMHz\n") % (ref_freq/1e6)
+ << boost::format(" Target Freq=%fMHz\n") % (target_freq/1e6)
+ << boost::format(" Actual Freq=%fMHz\n") % (_lo_freq/1e6)
+ << std::endl;
+
+ //high-high band or low-high band?
+ if(_lo_freq > (5.35e9 + 5.47e9)/2.0){
+ if (xcvr2450_debug) std::cerr << "XCVR2450 tune: Using high-high band" << std::endl;
+ _max2829_regs.band_select_802_11a = max2829_regs_t::BAND_SELECT_802_11A_5_47GHZ_TO_5_875GHZ;
+ }else{
+ if (xcvr2450_debug) std::cerr << "XCVR2450 tune: Using low-high band" << std::endl;
+ _max2829_regs.band_select_802_11a = max2829_regs_t::BAND_SELECT_802_11A_4_9GHZ_TO_5_35GHZ;
+ }
+
+ //new band select settings and ad9515 divider
+ this->update_atr();
+
+ //load new counters into registers
+ _max2829_regs.int_div_ratio_word = intdiv;
+ _max2829_regs.frac_div_ratio_lsb = fracdiv & 0x3;
+ _max2829_regs.frac_div_ratio_msb = fracdiv >> 2;
+ this->send_reg(0x3); //integer
+ this->send_reg(0x4); //fractional
+
+ //load the reference divider and band select into registers
+ //toggle the bandswitch from off to automatic (which really means start)
+ _max2829_regs.ref_divider = R;
+ _max2829_regs.band_select = (xcvr2450::is_highband(_lo_freq))?
+ max2829_regs_t::BAND_SELECT_5GHZ :
+ max2829_regs_t::BAND_SELECT_2_4GHZ ;
+ _max2829_regs.vco_bandswitch = max2829_regs_t::VCO_BANDSWITCH_DISABLE;
+ this->send_reg(0x5);
+ _max2829_regs.vco_bandswitch = max2829_regs_t::VCO_BANDSWITCH_AUTOMATIC;;
+ this->send_reg(0x5);
+}
+
+/***********************************************************************
+ * Antenna Handling
+ **********************************************************************/
+void xcvr2450::set_tx_ant(const std::string &ant){
+ assert_has(xcvr_antennas, ant, "xcvr antenna name");
+ _tx_ant = ant;
+ this->update_atr(); //sets the atr to the new antenna setting
+}
+
+void xcvr2450::set_rx_ant(const std::string &ant){
+ assert_has(xcvr_antennas, ant, "xcvr antenna name");
+ _rx_ant = ant;
+ this->update_atr(); //sets the atr to the new antenna setting
+}
+
+/***********************************************************************
+ * Gain Handling
+ **********************************************************************/
+/*!
+ * Convert a requested gain for the tx vga into the integer register value.
+ * The gain passed into the function will be set to the actual value.
+ * \param gain the requested gain in dB
+ * \return 6 bit the register value
+ */
+static int gain_to_tx_vga_reg(float &gain){
+ //calculate the register value
+ int reg = std::clip(boost::math::iround(gain*60/30.0) + 3, 0, 63);
+
+ //calculate the actual gain value
+ if (reg < 4) gain = 0;
+ else if (reg < 48) gain = reg/2 - 1;
+ else gain = reg/2.0 - 1.5;
+
+ //return register value
+ return reg;
+}
+
+/*!
+ * Convert a requested gain for the tx bb into the integer register value.
+ * The gain passed into the function will be set to the actual value.
+ * \param gain the requested gain in dB
+ * \return gain enum value
+ */
+static max2829_regs_t::tx_baseband_gain_t gain_to_tx_bb_reg(float &gain){
+ int reg = std::clip(boost::math::iround(gain*3/5.0), 0, 3);
+ switch(reg){
+ case 0:
+ gain = 0;
+ return max2829_regs_t::TX_BASEBAND_GAIN_0DB;
+ case 1:
+ gain = 2;
+ return max2829_regs_t::TX_BASEBAND_GAIN_2DB;
+ case 2:
+ gain = 3.5;
+ return max2829_regs_t::TX_BASEBAND_GAIN_3_5DB;
+ case 3:
+ gain = 5;
+ return max2829_regs_t::TX_BASEBAND_GAIN_5DB;
+ }
+ ASSERT_THROW(false);
+}
+
+/*!
+ * Convert a requested gain for the rx vga into the integer register value.
+ * The gain passed into the function will be set to the actual value.
+ * \param gain the requested gain in dB
+ * \return 5 bit the register value
+ */
+static int gain_to_rx_vga_reg(float &gain){
+ int reg = std::clip(boost::math::iround(gain/2.0), 0, 31);
+ gain = reg*2;
+ return reg;
+}
+
+/*!
+ * Convert a requested gain for the rx lna into the integer register value.
+ * The gain passed into the function will be set to the actual value.
+ * \param gain the requested gain in dB
+ * \return 2 bit the register value
+ */
+static int gain_to_rx_lna_reg(float &gain){
+ int reg = std::clip(boost::math::iround(gain*2/30.5) + 1, 0, 3);
+ switch(reg){
+ case 0:
+ case 1: gain = 0; break;
+ case 2: gain = 15; break;
+ case 3: gain = 30.5; break;
+ }
+ return reg;
+}
+
+void xcvr2450::set_tx_gain(float gain, const std::string &name){
+ assert_has(xcvr_tx_gain_ranges.keys(), name, "xcvr tx gain name");
+ if (name == "VGA"){
+ _max2829_regs.tx_vga_gain = gain_to_tx_vga_reg(gain);
+ send_reg(0xC);
+ }
+ else if(name == "BB"){
+ _max2829_regs.tx_baseband_gain = gain_to_tx_bb_reg(gain);
+ send_reg(0x9);
+ }
+ else ASSERT_THROW(false);
+ _tx_gains[name] = gain;
+}
+
+void xcvr2450::set_rx_gain(float gain, const std::string &name){
+ assert_has(xcvr_rx_gain_ranges.keys(), name, "xcvr rx gain name");
+ if (name == "VGA"){
+ _max2829_regs.rx_vga_gain = gain_to_rx_vga_reg(gain);
+ send_reg(0xB);
+ }
+ else if(name == "LNA"){
+ _max2829_regs.rx_lna_gain = gain_to_rx_lna_reg(gain);
+ send_reg(0xB);
+ }
+ else ASSERT_THROW(false);
+ _rx_gains[name] = gain;
+}
+
+/***********************************************************************
+ * RX Get and Set
+ **********************************************************************/
+void xcvr2450::rx_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<subdev_prop_t>()){
+ case SUBDEV_PROP_NAME:
+ val = dboard_id::to_string(get_rx_id());
+ return;
+
+ case SUBDEV_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ assert_has(_rx_gains.keys(), name, "xcvr rx gain name");
+ val = _rx_gains[name];
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ assert_has(xcvr_rx_gain_ranges.keys(), name, "xcvr rx gain name");
+ val = xcvr_rx_gain_ranges[name];
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(xcvr_rx_gain_ranges.keys());
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = _lo_freq;
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = xcvr_freq_range;
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = _rx_ant;
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ val = xcvr_antennas;
+ return;
+
+ case SUBDEV_PROP_QUADRATURE:
+ val = true;
+ return;
+
+ case SUBDEV_PROP_IQ_SWAPPED:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_SPECTRUM_INVERTED:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_USE_LO_OFFSET:
+ val = false;
+ return;
+ }
+}
+
+void xcvr2450::rx_set(const wax::obj &key_, const 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<subdev_prop_t>()){
+
+ case SUBDEV_PROP_FREQ:
+ this->set_lo_freq(val.as<double>());
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ this->set_rx_gain(val.as<float>(), name);
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ this->set_rx_ant(val.as<std::string>());
+ return;
+
+ default: throw std::runtime_error(str(boost::format(
+ "Error: trying to set read-only property on %s subdev"
+ ) % dboard_id::to_string(get_rx_id())));
+ }
+}
+
+/***********************************************************************
+ * TX Get and Set
+ **********************************************************************/
+void xcvr2450::tx_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<subdev_prop_t>()){
+ case SUBDEV_PROP_NAME:
+ val = dboard_id::to_string(get_tx_id());
+ return;
+
+ case SUBDEV_PROP_OTHERS:
+ val = prop_names_t(); //empty
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ assert_has(_tx_gains.keys(), name, "xcvr tx gain name");
+ val = _tx_gains[name];
+ return;
+
+ case SUBDEV_PROP_GAIN_RANGE:
+ assert_has(xcvr_tx_gain_ranges.keys(), name, "xcvr tx gain name");
+ val = xcvr_tx_gain_ranges[name];
+ return;
+
+ case SUBDEV_PROP_GAIN_NAMES:
+ val = prop_names_t(xcvr_tx_gain_ranges.keys());
+ return;
+
+ case SUBDEV_PROP_FREQ:
+ val = _lo_freq;
+ return;
+
+ case SUBDEV_PROP_FREQ_RANGE:
+ val = xcvr_freq_range;
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ val = _tx_ant;
+ return;
+
+ case SUBDEV_PROP_ANTENNA_NAMES:
+ val = xcvr_antennas;
+ return;
+
+ case SUBDEV_PROP_QUADRATURE:
+ val = true;
+ return;
+
+ case SUBDEV_PROP_IQ_SWAPPED:
+ val = true;
+ return;
+
+ case SUBDEV_PROP_SPECTRUM_INVERTED:
+ val = false;
+ return;
+
+ case SUBDEV_PROP_USE_LO_OFFSET:
+ val = false;
+ return;
+ }
+}
+
+void xcvr2450::tx_set(const wax::obj &key_, const 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<subdev_prop_t>()){
+
+ case SUBDEV_PROP_FREQ:
+ set_lo_freq(val.as<double>());
+ return;
+
+ case SUBDEV_PROP_GAIN:
+ this->set_tx_gain(val.as<float>(), name);
+ return;
+
+ case SUBDEV_PROP_ANTENNA:
+ this->set_tx_ant(val.as<std::string>());
+ return;
+
+ default: throw std::runtime_error(str(boost::format(
+ "Error: trying to set read-only property on %s subdev"
+ ) % dboard_id::to_string(get_tx_id())));
+ }
+}
diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp
index fe74219d6..ee23dc83a 100644
--- a/host/lib/usrp/usrp2/dboard_impl.cpp
+++ b/host/lib/usrp/usrp2/dboard_impl.cpp
@@ -94,7 +94,7 @@ void usrp2_impl::update_tx_mux_config(void){
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;
if (tx_subdev[SUBDEV_PROP_IQ_SWAPPED].as<bool>()){
- tx_mux = (((tx_mux >> 0) & 0x1) << 1) | (((tx_mux >> 1) & 0x1) << 0);
+ tx_mux = (((tx_mux >> 0) & 0xf) << 4) | (((tx_mux >> 4) & 0xf) << 0);
}
_iface->poke32(FR_DSP_TX_MUX, tx_mux);