From: Johnathan Corgan Date: Wed, 7 Oct 2009 01:17:18 +0000 (-0700) Subject: Merge branch 'wip/wbxng' of git@gnuradio.org:jcorgan X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=fc6d4f39ca65a6b7db7ac8c521df43afab0d362d;p=debian%2Fgnuradio Merge branch 'wip/wbxng' of git@gnuradio.org:jcorgan * 'wip/wbxng' of git@gnuradio.org:jcorgan: Clean up for work-in-progress Integrated gain control for TX and RX of wbxng Enabled RX Baseband First Functional TX modulator Locking, controllable synthesizer on TX and RX Able to tune RX VCO, observe R and N divider output on MUXOUT twiddling gpio successfully Clean build Initial compile of wbxng, properly sets db IDs --- fc6d4f39ca65a6b7db7ac8c521df43afab0d362d diff --cc usrp/host/include/usrp/db_wbxng.h index 00000000,2158face..8611d478 mode 000000,100644..100644 --- a/usrp/host/include/usrp/db_wbxng.h +++ b/usrp/host/include/usrp/db_wbxng.h @@@ -1,0 -1,121 +1,115 @@@ + /* -*- c++ -*- */ + // + // 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_DB_WBXNG_H + #define INCLUDED_DB_WBXNG_H + + #include + #include + + class adf4350; + + class wbxng_base : public db_base + { + public: + wbxng_base(usrp_basic_sptr usrp, int which, int _power_on=0); + ~wbxng_base(); + + struct freq_result_t set_freq(double freq); + + bool is_quadrature(); + double freq_min(); + double freq_max(); + + protected: + bool _lock_detect(); - - //virtual bool _compute_regs(double freq, int &retR, int &retcontrol, int &retN, double &retfreq); - int _compute_control_reg(); - int _refclk_divisor(); - double _refclk_freq(); - + bool _set_pga(float pga_gain); + + int power_on() { return d_power_on; } + int power_off() { return 0; } + + bool d_first; + int d_spi_format; + int d_spi_enable; + int d_power_on; + int d_PD; + + adf4350 *d_common; + }; + + // ---------------------------------------------------------------- + + class wbxng_base_tx : public wbxng_base + { + protected: + void shutdown(); + + public: + wbxng_base_tx(usrp_basic_sptr usrp, int which, int _power_on=0); + ~wbxng_base_tx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + + bool set_auto_tr(bool on); + bool set_enable(bool on); + bool set_gain(float gain); + }; + + class wbxng_base_rx : public wbxng_base + { + protected: + void shutdown(); + bool _set_attn(float attn); + + public: + wbxng_base_rx(usrp_basic_sptr usrp, int which, int _power_on=0); + ~wbxng_base_rx(); + + bool set_auto_tr(bool on); + bool select_rx_antenna(int which_antenna); + bool select_rx_antenna(const std::string &which_antenna); + bool set_gain(float gain); + }; + + // ---------------------------------------------------------------- + + class db_wbxng_tx : public wbxng_base_tx + { + public: + db_wbxng_tx(usrp_basic_sptr usrp, int which); + ~db_wbxng_tx(); + }; + + class db_wbxng_rx : public wbxng_base_rx + { + public: + db_wbxng_rx(usrp_basic_sptr usrp, int which); + ~db_wbxng_rx(); + + float gain_min(); + float gain_max(); + float gain_db_per_step(); + bool i_and_q_swapped(); + }; + + #endif /* INCLUDED_DB_WBXNG_H */ diff --cc usrp/host/lib/db_wbxng.cc index 00000000,c23fc47e..38c3a288 mode 000000,100644..100644 --- a/usrp/host/lib/db_wbxng.cc +++ b/usrp/host/lib/db_wbxng.cc @@@ -1,0 -1,499 +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 + #include "db_wbxng_adf4350.h" + #include + #include + + // 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, _lock_detect()); ++ 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; + }