diff options
Diffstat (limited to 'usrp/host/lib')
-rw-r--r-- | usrp/host/lib/Makefile.am | 15 | ||||
-rw-r--r-- | usrp/host/lib/db_boards.cc | 22 | ||||
-rw-r--r-- | usrp/host/lib/db_wbxng.cc | 499 | ||||
-rw-r--r-- | usrp/host/lib/db_wbxng_adf4350.cc | 199 | ||||
-rw-r--r-- | usrp/host/lib/db_wbxng_adf4350.h | 53 | ||||
-rw-r--r-- | usrp/host/lib/db_wbxng_adf4350_regs.cc | 114 | ||||
-rw-r--r-- | usrp/host/lib/db_wbxng_adf4350_regs.h | 64 | ||||
-rw-r--r-- | usrp/host/lib/usrp_dbid.dat | 11 |
8 files changed, 961 insertions, 16 deletions
diff --git a/usrp/host/lib/Makefile.am b/usrp/host/lib/Makefile.am index 2f8cbe6de..72312ebbb 100644 --- a/usrp/host/lib/Makefile.am +++ b/usrp/host/lib/Makefile.am @@ -1,22 +1,22 @@ # # USRP - Universal Software Radio Peripheral -# +# # Copyright (C) 2003,2004,2006,2007,2008,2009 Free Software Foundation, Inc. -# +# # 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, write to the Free Software # Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA -# +# include $(top_srcdir)/Makefile.common @@ -122,6 +122,8 @@ libusrp_la_common_SOURCES = \ usrp_local_sighandler.cc \ usrp_prims_common.cc \ usrp_standard.cc \ + db_wbxng_adf4350.cc \ + db_wbxng_adf4350_regs.cc \ db_boards.cc \ db_base.cc \ db_basic.cc \ @@ -130,6 +132,7 @@ libusrp_la_common_SOURCES = \ db_flexrf.cc \ db_flexrf_mimo.cc \ db_dbs_rx.cc \ + db_wbxng.cc \ db_xcvr2450.cc \ db_dtt754.cc \ db_dtt768.cc \ @@ -165,6 +168,8 @@ noinst_HEADERS = \ db_base_impl.h \ db_boards.h \ db_util.h \ + db_wbxng_adf4350.h \ + db_wbxng_adf4350_regs.h \ fusb.h \ fusb_darwin.h \ fusb_generic.h \ diff --git a/usrp/host/lib/db_boards.cc b/usrp/host/lib/db_boards.cc index 8ef5bac8b..590d8132d 100644 --- a/usrp/host/lib/db_boards.cc +++ b/usrp/host/lib/db_boards.cc @@ -1,19 +1,19 @@ /* -*- c++ -*- */ // // 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 // 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, // 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, @@ -32,6 +32,7 @@ #include <usrp/db_dbs_rx.h> #include <usrp/db_flexrf.h> #include <usrp/db_flexrf_mimo.h> +#include <usrp/db_wbxng.h> #include <usrp/db_xcvr2450.h> #include <usrp/db_dtt754.h> #include <usrp/db_dtt768.h> @@ -63,7 +64,7 @@ instantiate_dbs(int dbid, usrp_basic_sptr usrp, int which_side) db.push_back(db_base_sptr(new db_lf_rx(usrp, which_side, 1))); db.push_back(db_base_sptr(new db_lf_rx(usrp, which_side, 2))); break; - + case(USRP_DBID_DBS_RX): db.push_back(db_base_sptr(new db_dbs_rx(usrp, which_side))); break; @@ -184,7 +185,7 @@ instantiate_dbs(int dbid, usrp_basic_sptr usrp, int which_side) case(USRP_DBID_XCVR2450_RX): db.push_back(db_base_sptr(new db_xcvr2450_rx(usrp, which_side))); break; - + #if 0 // FIXME wbx doesn't compile case(USRP_DBID_WBX_LO_TX): db.push_back(db_base_sptr(new db_wbx_lo_tx(usrp, which_side))); @@ -194,6 +195,13 @@ instantiate_dbs(int dbid, usrp_basic_sptr usrp, int which_side) break; #endif + case(USRP_DBID_WBX_NG_TX): + db.push_back(db_base_sptr(new db_wbxng_tx(usrp, which_side))); + break; + case(USRP_DBID_WBX_NG_RX): + db.push_back(db_base_sptr(new db_wbxng_rx(usrp, which_side))); + break; + case(USRP_DBID_DTT754): db.push_back(db_base_sptr(new db_dtt754(usrp, which_side))); break; @@ -210,7 +218,7 @@ instantiate_dbs(int dbid, usrp_basic_sptr usrp, int which_side) db.push_back(db_base_sptr(new db_basic_rx(usrp, which_side, 1))); } break; - + case(-2): default: if (boost::dynamic_pointer_cast<usrp_basic_tx>(usrp)){ diff --git a/usrp/host/lib/db_wbxng.cc b/usrp/host/lib/db_wbxng.cc new file mode 100644 index 000000000..38c3a2886 --- /dev/null +++ b/usrp/host/lib/db_wbxng.cc @@ -0,0 +1,499 @@ +// +// 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 +// 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, +// 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. + +#include <usrp/db_wbxng.h> +#include "db_wbxng_adf4350.h" +#include <db_base_impl.h> +#include <stdio.h> + +// d'board i/o pin defs +// Tx and Rx have shared defs, but different i/o regs +#define ENABLE_5 (1 << 7) // enables 5.0V power supply +#define ENABLE_33 (1 << 6) // enables 3.3V supply +#define RX_TXN (1 << 5) // Tx only: T/R antenna switch for TX/RX port +#define RX2_RX1N (1 << 5) // Rx only: antenna switch between RX2 and TX/RX port +#define RXBB_EN (1 << 4) +#define TXMOD_EN (1 << 4) +#define PLL_CE (1 << 3) +#define PLL_PDBRF (1 << 2) +#define PLL_MUXOUT (1 << 1) +#define PLL_LOCK_DETECT (1 << 0) + +// RX Attenuator constants +#define ATTN_SHIFT 8 +#define ATTN_MASK (63 << ATTN_SHIFT) + +wbxng_base::wbxng_base(usrp_basic_sptr _usrp, int which, int _power_on) + : db_base(_usrp, which), d_power_on(_power_on) +{ + /* + @param usrp: instance of usrp.source_c + @param which: which side: 0 or 1 corresponding to side A or B respectively + @type which: int + */ + + usrp()->_write_oe(d_which, 0, 0xffff); // turn off all outputs + + d_first = true; + d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0; + + _enable_refclk(false); // disable refclk + + set_auto_tr(false); +} + +wbxng_base::~wbxng_base() +{ + if (d_common) + delete d_common; +} + +struct freq_result_t +wbxng_base::set_freq(double freq) +{ + /* + @returns (ok, actual_baseband_freq) where: + ok is True or False and indicates success or failure, + actual_baseband_freq is the RF frequency that corresponds to DC in the IF. + */ + + freq_t int_freq = freq_t(freq); + bool ok = d_common->_set_freq(int_freq*2); + double freq_result = (double) d_common->_get_freq()/2.0; + struct freq_result_t args = {ok, freq_result}; + + /* Wait before reading Lock Detect*/ + timespec t; + t.tv_sec = 0; + t.tv_nsec = 10000000; + nanosleep(&t, NULL); + + fprintf(stderr,"Setting WBXNG frequency, requested %d, obtained %f, lock_detect %d\n", + int_freq, freq_result, d_common->_get_locked()); + + // FIXME + // Offsetting the LO helps get the Tx carrier leakage out of the way. + // This also ensures that on Rx, we're not getting hosed by the + // FPGA's DC removal loop's time constant. We were seeing a + // problem when running with discontinuous transmission. + // Offsetting the LO made the problem go away. + //freq += d_lo_offset; + + return args; +} + +bool +wbxng_base::_set_pga(float pga_gain) +{ + if(d_which == 0) { + usrp()->set_pga(0, pga_gain); + usrp()->set_pga(1, pga_gain); + } + else { + usrp()->set_pga(2, pga_gain); + usrp()->set_pga(3, pga_gain); + } + return true; +} + +bool +wbxng_base::is_quadrature() +{ + /* + Return True if this board requires both I & Q analog channels. + + This bit of info is useful when setting up the USRP Rx mux register. + */ + return true; +} + +double +wbxng_base::freq_min() +{ + return (double) d_common->_get_min_freq()/2.0; +} + +double +wbxng_base::freq_max() +{ + return (double) d_common->_get_max_freq()/2.0; +} + +// ---------------------------------------------------------------- + +wbxng_base_tx::wbxng_base_tx(usrp_basic_sptr _usrp, int which, int _power_on) + : wbxng_base(_usrp, which, _power_on) +{ + /* + @param usrp: instance of usrp.sink_c + @param which: 0 or 1 corresponding to side TX_A or TX_B respectively. + */ + + if(which == 0) { + d_spi_enable = SPI_ENABLE_TX_A; + } + else { + d_spi_enable = SPI_ENABLE_TX_B; + } + + d_common = new adf4350(_usrp, d_which, d_spi_enable); + + // FIXME: power up the transmit side, but don't enable the mixer + usrp()->_write_oe(d_which,(RX_TXN|TXMOD_EN|ENABLE_33|ENABLE_5), (RX_TXN|TXMOD_EN|ENABLE_33|ENABLE_5)); + usrp()->write_io(d_which, (power_on()|RX_TXN|TXMOD_EN|ENABLE_33|ENABLE_5), (RX_TXN|TXMOD_EN|ENABLE_33|ENABLE_5)); + fprintf(stderr,"Setting WBXNG TXMOD on"); + //set_lo_offset(4e6); + + set_gain((gain_min() + gain_max()) / 2.0); // initialize gain +} + +wbxng_base_tx::~wbxng_base_tx() +{ + shutdown(); +} + + +void +wbxng_base_tx::shutdown() +{ + // fprintf(stderr, "wbxng_base_tx::shutdown d_is_shutdown = %d\n", d_is_shutdown); + + if (!d_is_shutdown){ + d_is_shutdown = true; + // do whatever there is to do to shutdown + + // Power down and leave the T/R switch in the R position + usrp()->write_io(d_which, (power_off()|RX_TXN), (RX_TXN|ENABLE_33|ENABLE_5)); + + // Power down VCO/PLL + d_common->_enable(false); + + /* + _write_control(_compute_control_reg()); + */ + _enable_refclk(false); // turn off refclk + set_auto_tr(false); + } +} + +bool +wbxng_base_tx::set_auto_tr(bool on) +{ + bool ok = true; + if(on) { + ok &= set_atr_mask (RX_TXN | ENABLE_33 | ENABLE_5); + ok &= set_atr_txval(0 | ENABLE_33 | ENABLE_5); + ok &= set_atr_rxval(RX_TXN | 0); + } + else { + ok &= set_atr_mask (0); + ok &= set_atr_txval(0); + ok &= set_atr_rxval(0); + } + return ok; +} + +bool +wbxng_base_tx::set_enable(bool on) +{ + /* + Enable transmitter if on is true + */ + + int v; + int mask = RX_TXN | ENABLE_5 | ENABLE_33; + if(on) { + v = ENABLE_5 | ENABLE_33; + } + else { + v = RX_TXN; + } + return usrp()->write_io(d_which, v, mask); +} + +float +wbxng_base_tx::gain_min() +{ + return usrp()->pga_max(); +} + +float +wbxng_base_tx::gain_max() +{ + return usrp()->pga_max() + 25.0; +} + +float +wbxng_base_tx::gain_db_per_step() +{ + return 1; +} + +bool +wbxng_base_tx::set_gain(float gain) +{ + /* + Set the gain. + + @param gain: gain in decibels + @returns True/False + */ + + // clamp gain + gain = std::max(gain_min(), std::min(gain, gain_max())); + + float pga_gain, agc_gain; + float V_maxgain, V_mingain, V_fullscale, dac_value; + + float maxgain = gain_max() - usrp()->pga_max(); + float mingain = gain_min(); + if(gain > maxgain) { + pga_gain = gain-maxgain; + assert(pga_gain <= usrp()->pga_max()); + agc_gain = maxgain; + } + else { + pga_gain = 0; + agc_gain = gain; + } + + V_maxgain = 0.7; + V_mingain = 1.4; + V_fullscale = 3.3; + dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale; + + fprintf(stderr, "TXGAIN: %f dB, Dac Code: %d, Voltage: %f\n", gain, int(dac_value), float((dac_value/4096.0)*V_fullscale)); + assert(dac_value>=0 && dac_value<4096); + + return (usrp()->write_aux_dac(d_which, 0, int(dac_value)) + && _set_pga(int(pga_gain))); +} + + +/**************************************************************************/ + + +wbxng_base_rx::wbxng_base_rx(usrp_basic_sptr _usrp, int which, int _power_on) + : wbxng_base(_usrp, which, _power_on) +{ + /* + @param usrp: instance of usrp.source_c + @param which: 0 or 1 corresponding to side RX_A or RX_B respectively. + */ + + if(which == 0) { + d_spi_enable = SPI_ENABLE_RX_A; + } + else { + d_spi_enable = SPI_ENABLE_RX_B; + } + + d_common = new adf4350(_usrp, d_which, d_spi_enable); + + usrp()->_write_oe(d_which, (RX2_RX1N|RXBB_EN|ATTN_MASK|ENABLE_33|ENABLE_5), (RX2_RX1N|RXBB_EN|ATTN_MASK|ENABLE_33|ENABLE_5)); + usrp()->write_io(d_which, (power_on()|RX2_RX1N|RXBB_EN|ENABLE_33|ENABLE_5), (RX2_RX1N|RXBB_EN|ATTN_MASK|ENABLE_33|ENABLE_5)); + fprintf(stderr,"Setting WBXNG RXBB on"); + + // set up for RX on TX/RX port + select_rx_antenna("TX/RX"); + + bypass_adc_buffers(true); + + /* + set_lo_offset(-4e6); + */ +} + +wbxng_base_rx::~wbxng_base_rx() +{ + shutdown(); +} + +void +wbxng_base_rx::shutdown() +{ + // fprintf(stderr, "wbxng_base_rx::shutdown d_is_shutdown = %d\n", d_is_shutdown); + + if (!d_is_shutdown){ + d_is_shutdown = true; + // do whatever there is to do to shutdown + + // Power down + usrp()->common_write_io(C_RX, d_which, power_off(), (ENABLE_33|ENABLE_5)); + + // Power down VCO/PLL + d_common->_enable(false); + + // fprintf(stderr, "wbxng_base_rx::shutdown before _write_control\n"); + //_write_control(_compute_control_reg()); + + // fprintf(stderr, "wbxng_base_rx::shutdown before _enable_refclk\n"); + _enable_refclk(false); // turn off refclk + + // fprintf(stderr, "wbxng_base_rx::shutdown before set_auto_tr\n"); + set_auto_tr(false); + + // fprintf(stderr, "wbxng_base_rx::shutdown after set_auto_tr\n"); + } +} + +bool +wbxng_base_rx::set_auto_tr(bool on) +{ + bool ok = true; + if(on) { + ok &= set_atr_mask (ENABLE_33|ENABLE_5); + ok &= set_atr_txval( 0); + ok &= set_atr_rxval(ENABLE_33|ENABLE_5); + } + else { + ok &= set_atr_mask (0); + ok &= set_atr_txval(0); + ok &= set_atr_rxval(0); + } + return true; +} + +bool +wbxng_base_rx::select_rx_antenna(int which_antenna) +{ + /* + Specify which antenna port to use for reception. + @param which_antenna: either 'TX/RX' or 'RX2' + */ + + if(which_antenna == 0) { + usrp()->write_io(d_which, 0,RX2_RX1N); + } + else if(which_antenna == 1) { + usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N); + } + else { + return false; + } + return true; +} + +bool +wbxng_base_rx::select_rx_antenna(const std::string &which_antenna) +{ + /* + Specify which antenna port to use for reception. + @param which_antenna: either 'TX/RX' or 'RX2' + */ + + + if(which_antenna == "TX/RX") { + usrp()->write_io(d_which, 0, RX2_RX1N); + } + else if(which_antenna == "RX2") { + usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N); + } + else { + return false; + } + + return true; +} + +bool +wbxng_base_rx::set_gain(float gain) +{ + /* + Set the gain. + + @param gain: gain in decibels + @returns True/False + */ + + // clamp gain + gain = std::max(gain_min(), std::min(gain, gain_max())); + + float pga_gain, agc_gain; + + float maxgain = gain_max() - usrp()->pga_max(); + float mingain = gain_min(); + if(gain > maxgain) { + pga_gain = gain-maxgain; + assert(pga_gain <= usrp()->pga_max()); + agc_gain = maxgain; + } + else { + pga_gain = 0; + agc_gain = gain; + } + + return _set_attn(maxgain-agc_gain) && _set_pga(int(pga_gain)); +} + +bool +wbxng_base_rx::_set_attn(float attn) +{ + int attn_code = int(floor(attn/0.5)); + unsigned int iobits = (~attn_code) << ATTN_SHIFT; + fprintf(stderr, "Attenuation: %f dB, Code: %d, IO Bits %x, Mask: %x \n", attn, attn_code, iobits & ATTN_MASK, ATTN_MASK); + return usrp()->write_io(d_which, iobits, ATTN_MASK); +} + +// ---------------------------------------------------------------- + +db_wbxng_tx::db_wbxng_tx(usrp_basic_sptr usrp, int which) + : wbxng_base_tx(usrp, which) +{ +} + +db_wbxng_tx::~db_wbxng_tx() +{ +} + +db_wbxng_rx::db_wbxng_rx(usrp_basic_sptr usrp, int which) + : wbxng_base_rx(usrp, which) +{ + set_gain((gain_min() + gain_max()) / 2.0); // initialize gain +} + +db_wbxng_rx::~db_wbxng_rx() +{ +} + +float +db_wbxng_rx::gain_min() +{ + return usrp()->pga_min(); +} + +float +db_wbxng_rx::gain_max() +{ + return usrp()->pga_max()+30.5; +} + +float +db_wbxng_rx::gain_db_per_step() +{ + return 0.05; +} + + +bool +db_wbxng_rx::i_and_q_swapped() +{ + return false; +} diff --git a/usrp/host/lib/db_wbxng_adf4350.cc b/usrp/host/lib/db_wbxng_adf4350.cc new file mode 100644 index 000000000..af4eac573 --- /dev/null +++ b/usrp/host/lib/db_wbxng_adf4350.cc @@ -0,0 +1,199 @@ +// +// Copyright 2009 Free Software Foundation, Inc. +// +// This file is part of GNU Radio +// +// GNU Radio 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, +// 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. + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "db_wbxng_adf4350.h" +#include <db_base_impl.h> +#include <stdio.h> + +#define INPUT_REF_FREQ FREQ_C(64e6) +#define DIV_ROUND(num, denom) (((num) + ((denom)/2))/(denom)) +#define FREQ_C(freq) uint64_t(freq) +#define INPUT_REF_FREQ_2X (2*INPUT_REF_FREQ) /* input ref freq with doubler turned on */ +#define MIN_INT_DIV uint16_t(23) /* minimum int divider, prescaler 4/5 only */ +#define MAX_RF_DIV uint8_t(16) /* max rf divider, divides rf output */ +#define MIN_VCO_FREQ FREQ_C(2.2e9) /* minimum vco freq */ +#define MAX_VCO_FREQ FREQ_C(4.4e9) /* minimum vco freq */ +#define MAX_FREQ MAX_VCO_FREQ /* upper bound freq (rf div = 1) */ +#define MIN_FREQ DIV_ROUND(MIN_VCO_FREQ, MAX_RF_DIV) /* calculated lower bound freq */ + +#define CE_PIN (1 << 3) +#define PDB_RF_PIN (1 << 2) +#define MUX_PIN (1 << 1) +#define LD_PIN (1 << 0) + +adf4350::adf4350(usrp_basic_sptr _usrp, int _which, int _spi_enable) +{ + /* Initialize the pin directions. */ + + d_usrp = _usrp; + d_which = _which; + d_spi_enable = _spi_enable; + d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0; + + d_regs = new adf4350_regs(this); + + /* Outputs */ + d_usrp->_write_oe(d_which, (CE_PIN | PDB_RF_PIN), (CE_PIN | PDB_RF_PIN)); + d_usrp->write_io(d_which, (0), (CE_PIN | PDB_RF_PIN)); + + /* Initialize the pin levels. */ + _enable(true); + /* Initialize the registers. */ + d_regs->_load_register(5); + d_regs->_load_register(4); + d_regs->_load_register(3); + d_regs->_load_register(2); + d_regs->_load_register(1); + d_regs->_load_register(0); +} + +adf4350::~adf4350() +{ + delete d_regs; +} + +freq_t +adf4350::_get_max_freq(void) +{ + return MAX_FREQ; +} + +freq_t +adf4350::_get_min_freq(void) +{ + return MIN_FREQ; +} + +bool +adf4350::_get_locked(void) +{ + return d_usrp->read_io(d_which) & LD_PIN; +} + +void +adf4350::_enable(bool enable) +{ + if (enable){ /* chip enable */ + d_usrp->write_io(d_which, (CE_PIN | PDB_RF_PIN), (CE_PIN | PDB_RF_PIN)); + }else{ + d_usrp->write_io(d_which, 0, (CE_PIN | PDB_RF_PIN)); + } +} + +void +adf4350::_write(uint8_t addr, uint32_t data) +{ + data |= addr; + + // create str from data here + char s[4]; + s[0] = (char)((data >> 24) & 0xff); + s[1] = (char)((data >> 16) & 0xff); + s[2] = (char)((data >> 8) & 0xff); + s[3] = (char)(data & 0xff); + std::string str(s, 4); + + timespec t; + t.tv_sec = 0; + t.tv_nsec = 5e6; + + nanosleep(&t, NULL); + d_usrp->_write_spi(0, d_spi_enable, d_spi_format, str); + nanosleep(&t, NULL); + + //fprintf(stderr, "Wrote to WBXNG SPI address %d with data %8x\n", addr, data); + /* pulse latch */ + //d_usrp->write_io(d_which, 1, LE_PIN); + //d_usrp->write_io(d_which, 0, LE_PIN); +} + +bool +adf4350::_set_freq(freq_t freq) +{ + /* Set the frequency by setting int, frac, mod, r, div */ + if (freq > MAX_FREQ || freq < MIN_FREQ) return false; + /* Ramp up the RF divider until the VCO is within range. */ + d_regs->d_divider_select = 0; + while (freq < MIN_VCO_FREQ){ + freq <<= 1; //double the freq + d_regs->d_divider_select++; //double the divider + } + /* Ramp up the R divider until the N divider is at least the minimum. */ + //d_regs->d_10_bit_r_counter = INPUT_REF_FREQ*MIN_INT_DIV/freq; + d_regs->d_10_bit_r_counter = 2; + uint64_t n_mod; + do{ + d_regs->d_10_bit_r_counter++; + n_mod = freq; + n_mod *= d_regs->d_10_bit_r_counter; + n_mod *= d_regs->d_mod; + n_mod /= INPUT_REF_FREQ; + /* calculate int and frac */ + d_regs->d_int = n_mod/d_regs->d_mod; + d_regs->d_frac = (n_mod - (freq_t)d_regs->d_int*d_regs->d_mod) & uint16_t(0xfff); + /* + fprintf(stderr, + "VCO %lu KHz, Int %u, Frac %u, Mod %u, R %u, Div %u\n", + freq, d_regs->d_int, d_regs->d_frac, + d_regs->d_mod, d_regs->d_10_bit_r_counter, (1 << d_regs->d_divider_select) + ); + */ + }while(d_regs->d_int < MIN_INT_DIV); + /* calculate the band select so PFD is under 125 KHz */ + d_regs->d_8_bit_band_select_clock_divider_value = \ + INPUT_REF_FREQ/(FREQ_C(30e3)*d_regs->d_10_bit_r_counter) + 1; + /* + fprintf(stderr, "Band Selection: Div %u, Freq %lu\n", + d_regs->d_8_bit_band_select_clock_divider_value, + INPUT_REF_FREQ/(d_regs->d_8_bit_band_select_clock_divider_value * d_regs->d_10_bit_r_counter) + 1 + ); + */ + d_regs->_load_register(5); + d_regs->_load_register(3); + d_regs->_load_register(1); + /* load involved registers */ + d_regs->_load_register(2); + d_regs->_load_register(4); + d_regs->_load_register(0); /* register 0 must be last */ + return true; +} + +freq_t +adf4350::_get_freq(void) +{ + /* Calculate the freq from int, frac, mod, ref, r, div: + * freq = (int + frac/mod) * (ref/r) + * Keep precision by doing multiplies first: + * freq = (((((((int)*mod) + frac)*ref)/mod)/r)/div) + */ + uint64_t temp; + temp = d_regs->d_int; + temp *= d_regs->d_mod; + temp += d_regs->d_frac; + temp *= INPUT_REF_FREQ; + temp /= d_regs->d_mod; + temp /= d_regs->d_10_bit_r_counter; + temp /= (1 << d_regs->d_divider_select); + return temp; +} diff --git a/usrp/host/lib/db_wbxng_adf4350.h b/usrp/host/lib/db_wbxng_adf4350.h new file mode 100644 index 000000000..2b0783c20 --- /dev/null +++ b/usrp/host/lib/db_wbxng_adf4350.h @@ -0,0 +1,53 @@ +// +// Copyright 2009 Free Software Foundation, Inc. +// +// This file is part of GNU Radio +// +// GNU Radio 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, +// 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. + +#ifndef INCLUDED_ADF4350_H +#define INCLUDED_ADF4350_H + +#include "db_wbxng_adf4350_regs.h" +#include <usrp/db_base.h> +#include <stdint.h> + +typedef uint64_t freq_t; +class adf4350_regs; + +class adf4350 +{ +public: + adf4350(usrp_basic_sptr _usrp, int _which, int _spi_enable); + ~adf4350(); + void _update(); + bool _get_locked(); + void _enable(bool enable); + void _write(uint8_t addr, uint32_t data); + bool _set_freq(freq_t freq); + freq_t _get_freq(); + freq_t _get_max_freq(); + freq_t _get_min_freq(); + +protected: + usrp_basic_sptr d_usrp; + int d_which; + int d_spi_enable; + int d_spi_format; + adf4350_regs *d_regs; +}; + +#endif /* INCLUDED_ADF4350_H */ diff --git a/usrp/host/lib/db_wbxng_adf4350_regs.cc b/usrp/host/lib/db_wbxng_adf4350_regs.cc new file mode 100644 index 000000000..11dcf8816 --- /dev/null +++ b/usrp/host/lib/db_wbxng_adf4350_regs.cc @@ -0,0 +1,114 @@ +/* + * Copyright 2009 Ettus Research LLC + */ + +#include "db_wbxng_adf4350_regs.h" +#include "db_wbxng_adf4350.h" + +//#include "cal_div.h" + +/* reg 0 */ +/* reg 1 */ +const uint8_t adf4350_regs::s_prescaler = 0; +const uint16_t adf4350_regs::s_phase = 0; +/* reg 2 */ +const uint8_t adf4350_regs::s_low_noise_and_low_spur_modes = 0; +const uint8_t adf4350_regs::s_muxout = 6; +const uint8_t adf4350_regs::s_reference_doubler = 0; +const uint8_t adf4350_regs::s_rdiv2 = 0; +const uint8_t adf4350_regs::s_double_buff = 0; +const uint8_t adf4350_regs::s_charge_pump_setting = 5; +const uint8_t adf4350_regs::s_ldf = 0; +const uint8_t adf4350_regs::s_ldp = 0; +const uint8_t adf4350_regs::s_pd_polarity = 1; +const uint8_t adf4350_regs::s_power_down = 0; +const uint8_t adf4350_regs::s_cp_three_state = 0; +const uint8_t adf4350_regs::s_counter_reset = 0; +/* reg 3 */ +const uint8_t adf4350_regs::s_csr = 0; +const uint8_t adf4350_regs::s_clk_div_mode = 0; +const uint16_t adf4350_regs::s_12_bit_clock_divider_value = 0; +/* reg 4 */ +const uint8_t adf4350_regs::s_feedback_select = 1; +const uint8_t adf4350_regs::s_vco_power_down = 0; +const uint8_t adf4350_regs::s_mtld = 0; +const uint8_t adf4350_regs::s_aux_output_select = 0; +const uint8_t adf4350_regs::s_aux_output_enable = 1; +const uint8_t adf4350_regs::s_aux_output_power = 3; +const uint8_t adf4350_regs::s_rf_output_enable = 1; +const uint8_t adf4350_regs::s_output_power = 3; +/* reg 5 */ +const uint8_t adf4350_regs::s_ld_pin_mode = 1; + +adf4350_regs::adf4350_regs(adf4350* _adf4350){ + d_adf4350 = _adf4350; + + /* reg 0 */ + d_int = uint16_t(100); + d_frac = 0; + /* reg 1 */ + d_mod = uint16_t(0xfff); /* max fractional accuracy */ + /* reg 2 */ + d_10_bit_r_counter = uint16_t(2); + /* reg 3 */ + /* reg 4 */ + d_divider_select = 0; + d_8_bit_band_select_clock_divider_value = 0; + /* reg 5 */ +} + +adf4350_regs::~adf4350_regs(void){ +} + +uint32_t +adf4350_regs::_reg_shift(uint32_t data, uint32_t shift){ + return data << shift; + } + +void +adf4350_regs::_load_register(uint8_t addr){ + uint32_t data; + switch (addr){ + case 0: data = ( + _reg_shift(d_int, 15) | + _reg_shift(d_frac, 3)); break; + case 1: data = ( + _reg_shift(s_prescaler, 27) | + _reg_shift(s_phase, 15) | + _reg_shift(d_mod, 3)); break; + case 2: data = ( + _reg_shift(s_low_noise_and_low_spur_modes, 29) | + _reg_shift(s_muxout, 26) | + _reg_shift(s_reference_doubler, 25) | + _reg_shift(s_rdiv2, 24) | + _reg_shift(d_10_bit_r_counter, 14) | + _reg_shift(s_double_buff, 13) | + _reg_shift(s_charge_pump_setting, 9) | + _reg_shift(s_ldf, 8) | + _reg_shift(s_ldp, 7) | + _reg_shift(s_pd_polarity, 6) | + _reg_shift(s_power_down, 5) | + _reg_shift(s_cp_three_state, 4) | + _reg_shift(s_counter_reset, 3)); break; + case 3: data = ( + _reg_shift(s_csr, 18) | + _reg_shift(s_clk_div_mode, 15) | + _reg_shift(s_12_bit_clock_divider_value, 3)); break; + case 4: data = ( + _reg_shift(s_feedback_select, 23) | + _reg_shift(d_divider_select, 20) | + _reg_shift(d_8_bit_band_select_clock_divider_value, 12) | + _reg_shift(s_vco_power_down, 11) | + _reg_shift(s_mtld, 10) | + _reg_shift(s_aux_output_select, 9) | + _reg_shift(s_aux_output_enable, 8) | + _reg_shift(s_aux_output_power, 6) | + _reg_shift(s_rf_output_enable, 5) | + _reg_shift(s_output_power, 3)); break; + case 5: data = ( + _reg_shift(s_ld_pin_mode, 22)); break; + default: return; + } + /* write the data out to spi */ + d_adf4350->_write(addr, data); +} diff --git a/usrp/host/lib/db_wbxng_adf4350_regs.h b/usrp/host/lib/db_wbxng_adf4350_regs.h new file mode 100644 index 000000000..dc941ee87 --- /dev/null +++ b/usrp/host/lib/db_wbxng_adf4350_regs.h @@ -0,0 +1,64 @@ +/* + * Copyright 2009 Ettus Research LLC + */ + +#ifndef ADF4350_REGS_H +#define ADF4350_REGS_H + +#include <usrp/db_base.h> +#include <stdint.h> + +class adf4350; + +class adf4350_regs +{ +public: + adf4350_regs(adf4350* _adf4350); + ~adf4350_regs(); + + adf4350* d_adf4350; + + uint32_t _reg_shift(uint32_t data, uint32_t shift); + void _load_register(uint8_t addr); + + /* reg 0 */ + uint16_t d_int; + uint16_t d_frac; + /* reg 1 */ + static const uint8_t s_prescaler; + static const uint16_t s_phase; + uint16_t d_mod; + /* reg 2 */ + static const uint8_t s_low_noise_and_low_spur_modes; + static const uint8_t s_muxout; + static const uint8_t s_reference_doubler; + static const uint8_t s_rdiv2; + uint16_t d_10_bit_r_counter; + static const uint8_t s_double_buff; + static const uint8_t s_charge_pump_setting; + static const uint8_t s_ldf; + static const uint8_t s_ldp; + static const uint8_t s_pd_polarity; + static const uint8_t s_power_down; + static const uint8_t s_cp_three_state; + static const uint8_t s_counter_reset; + /* reg 3 */ + static const uint8_t s_csr; + static const uint8_t s_clk_div_mode; + static const uint16_t s_12_bit_clock_divider_value; + /* reg 4 */ + static const uint8_t s_feedback_select; + uint8_t d_divider_select; + uint8_t d_8_bit_band_select_clock_divider_value; + static const uint8_t s_vco_power_down; + static const uint8_t s_mtld; + static const uint8_t s_aux_output_select; + static const uint8_t s_aux_output_enable; + static const uint8_t s_aux_output_power; + static const uint8_t s_rf_output_enable; + static const uint8_t s_output_power; + /* reg 5 */ + static const uint8_t s_ld_pin_mode; +}; + +#endif /* ADF4350_REGS_H */ diff --git a/usrp/host/lib/usrp_dbid.dat b/usrp/host/lib/usrp_dbid.dat index 6bad9a298..7d1e18714 100644 --- a/usrp/host/lib/usrp_dbid.dat +++ b/usrp/host/lib/usrp_dbid.dat @@ -1,18 +1,18 @@ # # Copyright 2005,2009 Free Software Foundation, Inc. -# +# # This file is part of GNU Radio -# +# # GNU Radio 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, or (at your option) # any later version. -# +# # GNU Radio 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, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. @@ -78,6 +78,9 @@ "WBX LO TX" 0x0050 "WBX LO RX" 0x0051 +"WBX NG TX" 0x0052 +"WBX NG RX" 0x0053 + "XCVR2450 Tx" 0x0060 "XCVR2450 Rx" 0x0061 |