diff options
| -rw-r--r-- | host/README | 1 | ||||
| -rw-r--r-- | host/lib/CMakeLists.txt | 16 | ||||
| -rw-r--r-- | host/lib/ic_reg_maps/common.py | 23 | ||||
| -rwxr-xr-x | host/lib/ic_reg_maps/gen_ad5624_regs.py | 23 | ||||
| -rwxr-xr-x | host/lib/ic_reg_maps/gen_ad7922_regs.py | 23 | ||||
| -rwxr-xr-x | host/lib/ic_reg_maps/gen_ad9510_regs.py | 23 | ||||
| -rwxr-xr-x | host/lib/ic_reg_maps/gen_ad9777_regs.py | 23 | ||||
| -rwxr-xr-x | host/lib/ic_reg_maps/gen_adf4360_regs.py | 23 | ||||
| -rwxr-xr-x | host/lib/ic_reg_maps/gen_max2829_regs.py | 166 | ||||
| -rw-r--r-- | host/lib/usrp/dboard/db_rfx.cpp | 2 | ||||
| -rw-r--r-- | host/lib/usrp/dboard/db_xcvr2450.cpp | 593 | ||||
| -rw-r--r-- | host/lib/usrp/usrp2/dboard_impl.cpp | 2 | 
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); | 
