diff options
Diffstat (limited to 'usrp')
-rw-r--r-- | usrp/host/include/usrp/Makefile.am | 2 | ||||
-rw-r--r-- | usrp/host/include/usrp/db_wbxng.h | 108 | ||||
-rw-r--r-- | usrp/host/include/usrp/db_wbxng_adf4350.h | 37 | ||||
-rw-r--r-- | usrp/host/include/usrp/db_wbxng_adf4350_regs.h | 65 | ||||
-rw-r--r-- | usrp/host/lib/Makefile.am | 2 | ||||
-rw-r--r-- | usrp/host/lib/db_wbxng.cc | 1061 | ||||
-rw-r--r-- | usrp/host/lib/db_wbxng_adf4350.cc | 156 | ||||
-rw-r--r-- | usrp/host/lib/db_wbxng_adf4350_regs.cc | 106 |
8 files changed, 888 insertions, 649 deletions
diff --git a/usrp/host/include/usrp/Makefile.am b/usrp/host/include/usrp/Makefile.am index 83e86da7e..7c868e061 100644 --- a/usrp/host/include/usrp/Makefile.am +++ b/usrp/host/include/usrp/Makefile.am @@ -33,6 +33,8 @@ usrpinclude_HEADERS = \ db_flexrf_mimo.h \ db_tv_rx.h \ db_tv_rx_mimo.h \ + db_wbxng_adf4350.h \ + db_wbxng_adf4350_regs.h \ db_wbxng.h \ db_xcvr2450.h \ libusb_types.h \ diff --git a/usrp/host/include/usrp/db_wbxng.h b/usrp/host/include/usrp/db_wbxng.h index b255cf91c..1ded1b5dc 100644 --- a/usrp/host/include/usrp/db_wbxng.h +++ b/usrp/host/include/usrp/db_wbxng.h @@ -23,70 +23,118 @@ #define DB_WBXNG_H #include <usrp/db_base.h> -#include <boost/shared_ptr.hpp> +#include <cmath> -class wbxng; -typedef boost::shared_ptr<wbxng> wbxng_sptr; +//debug_using_gui = true // Must be set to True or False +#define debug_using_gui false // Must be set to True or False +class adf4350; -/******************************************************************************/ - - -class db_wbxng_base: public db_base +class wbxng_base : public db_base { - /* - * Abstract base class for all wbxng boards. - * - * Derive board specific subclasses from db_wbxng_base_{tx,rx} - */ public: - db_wbxng_base(usrp_basic_sptr usrp, int which); - ~db_wbxng_base(); - struct freq_result_t set_freq(double target_freq); - bool is_quadrature(); + 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: - wbxng_sptr d_wbxng; - void shutdown_common(); + void _write_all(int R, int control, int N); + void _write_control(int control); + void _write_R(int R); + void _write_N(int N); + void _write_it(int v); + 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 db_wbxng_tx : public db_wbxng_base +class wbxng_base_tx : public wbxng_base { protected: void shutdown(); public: - db_wbxng_tx(usrp_basic_sptr usrp, int which); - ~db_wbxng_tx(); + wbxng_base_tx(usrp_basic_sptr usrp, int which, int _power_on=0); + ~wbxng_base_tx(); + //*** TODO *** Fix comment + // All RFX tx d'boards have fixed gain float gain_min(); float gain_max(); float gain_db_per_step(); - bool set_gain(float gain); - bool i_and_q_swapped(); + + bool set_auto_tr(bool on); + bool set_enable(bool on); + bool set_gain(float gain); }; -class db_wbxng_rx : public db_wbxng_base +class wbxng_base_rx : public wbxng_base { protected: void shutdown(); 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(); + + // Wrapper calls to d_common functions + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; + +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 set_gain(float gain); -}; + bool i_and_q_swapped(); + bool _compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq); +}; #endif diff --git a/usrp/host/include/usrp/db_wbxng_adf4350.h b/usrp/host/include/usrp/db_wbxng_adf4350.h new file mode 100644 index 000000000..a5ebe646e --- /dev/null +++ b/usrp/host/include/usrp/db_wbxng_adf4350.h @@ -0,0 +1,37 @@ +/* + * Copyright 2009 Ettus Research LLC + */ + +#ifndef ADF4350_H +#define ADF4350_H + +#include <usrp/db_wbxng_adf4350_regs.h> +#include <usrp/db_base.h> +#include <stdint.h> + +typedef uint32_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 /* ADF4350_H */ diff --git a/usrp/host/include/usrp/db_wbxng_adf4350_regs.h b/usrp/host/include/usrp/db_wbxng_adf4350_regs.h new file mode 100644 index 000000000..ec78a9fa5 --- /dev/null +++ b/usrp/host/include/usrp/db_wbxng_adf4350_regs.h @@ -0,0 +1,65 @@ +/* + * Copyright 2009 Ettus Research LLC + */ + +#ifndef ADF4350_REGS_H +#define ADF4350_REGS_H + +#include <usrp/db_wbxng_adf4350.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 _int; + uint16_t _frac; + /* reg 1 */ + static uint8_t _prescaler; + static uint16_t _phase; + uint16_t _mod; + /* reg 2 */ + static uint8_t _low_noise_and_low_spur_modes; + static uint8_t _muxout; + static uint8_t _reference_doubler; + static uint8_t _rdiv2; + uint16_t _10_bit_r_counter; + static uint8_t _double_buff; + static uint8_t _charge_pump_setting; + static uint8_t _ldf; + static uint8_t _ldp; + static uint8_t _pd_polarity; + static uint8_t _power_down; + static uint8_t _cp_three_state; + static uint8_t _counter_reset; + /* reg 3 */ + static uint8_t _csr; + static uint8_t _clk_div_mode; + static uint16_t _12_bit_clock_divider_value; + /* reg 4 */ + static uint8_t _feedback_select; + uint8_t _divider_select; + uint8_t _8_bit_band_select_clock_divider_value; + static uint8_t _vco_power_down; + static uint8_t _mtld; + static uint8_t _aux_output_select; + static uint8_t _aux_output_enable; + static uint8_t _aux_output_power; + static uint8_t _rf_output_enable; + static uint8_t _output_power; + /* reg 5 */ + static uint8_t _ld_pin_mode; +}; + +#endif /* ADF4350_REGS_H */ diff --git a/usrp/host/lib/Makefile.am b/usrp/host/lib/Makefile.am index 4b889993b..13f25d69b 100644 --- a/usrp/host/lib/Makefile.am +++ b/usrp/host/lib/Makefile.am @@ -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 \ diff --git a/usrp/host/lib/db_wbxng.cc b/usrp/host/lib/db_wbxng.cc index 53ec27afc..e911c9d03 100644 --- a/usrp/host/lib/db_wbxng.cc +++ b/usrp/host/lib/db_wbxng.cc @@ -1,5 +1,5 @@ // -// Copyright 2008,2009 Free Software Foundation, Inc. +// Copyright 2008 Free Software Foundation, Inc. // // This file is part of GNU Radio // @@ -19,791 +19,614 @@ // Boston, MA 02110-1301, USA. #include <usrp/db_wbxng.h> +#include <usrp/db_wbxng_adf4350.h> #include <db_base_impl.h> -#include <cmath> -#include <boost/thread.hpp> -#include <boost/weak_ptr.hpp> -#include <cstdio> - -#if 0 -#define LO_OFFSET 4.25e6 -#else -#define LO_OFFSET 0 -#define NO_LO_OFFSET -#endif - - -/* ------------------------------------------------------------------------ - * **** TODO **** - * Fix the comment below to reflect WBX NG - */ - -/* ------------------------------------------------------------------------ - * A few comments about the XCVR2450: - * - * It is half-duplex. I.e., transmit and receive are mutually exclusive. - * There is a single LO for both the Tx and Rx sides. - * For our purposes the board is always either receiving or transmitting. - * - * Each board is uniquely identified by the *USRP hardware* instance and side - * This dictionary holds a weak reference to existing board controller so it - * can be created or retrieved as needed. - */ - - - -// TX IO Pins -#define HB_PA_OFF (1 << 15) // 5GHz PA, 1 = off, 0 = on -#define LB_PA_OFF (1 << 14) // 2.4GHz PA, 1 = off, 0 = on -#define ANTSEL_TX1_RX2 (1 << 13) // 1 = Ant 1 to TX, Ant 2 to RX -#define ANTSEL_TX2_RX1 (1 << 12) // 1 = Ant 2 to TX, Ant 1 to RX -#define TX_EN (1 << 11) // 1 = TX on, 0 = TX off -#define AD9515DIV (1 << 4) // 1 = Div by 3, 0 = Div by 2 - -#define TX_OE_MASK HB_PA_OFF|LB_PA_OFF|ANTSEL_TX1_RX2|ANTSEL_TX2_RX1|TX_EN|AD9515DIV -#define TX_SAFE_IO HB_PA_OFF|LB_PA_OFF|ANTSEL_TX1_RX2|AD9515DIV - -// RX IO Pins -#define LOCKDET (1 << 15) // This is an INPUT!!! -#define EN (1 << 14) -#define RX_EN (1 << 13) // 1 = RX on, 0 = RX off -#define RX_HP (1 << 12) -#define RX_OE_MASK EN|RX_EN|RX_HP -#define RX_SAFE_IO EN - -struct wbxng_key { - std::string serial_no; - int which; - - bool operator==(const wbxng_key &x){ - return x.serial_no ==serial_no && x.which == which; - } -}; - -class wbxng -{ -private: - usrp_basic *d_raw_usrp; - int d_which; - - bool d_is_shutdown; - int d_spi_format, d_spi_enable; - - int d_mimo, d_int_div, d_frac_div, d_highband, d_five_gig; - int d_cp_current, d_ref_div, d_rssi_hbw; - int d_txlpf_bw, d_rxlpf_bw, d_rxlpf_fine, d_rxvga_ser; - int d_rssi_range, d_rssi_mode, d_rssi_mux; - int d_rx_hp_pin, d_rx_hpf, d_rx_ant; - int d_tx_ant, d_txvga_ser, d_tx_driver_lin; - int d_tx_vga_lin, d_tx_upconv_lin, d_tx_bb_gain; - int d_pabias_delay, d_pabias, rx_rf_gain, rx_bb_gain, d_txgain; - int d_rx_rf_gain, d_rx_bb_gain; - - int d_reg_standby, d_reg_int_divider, d_reg_frac_divider, d_reg_bandselpll; - int d_reg_cal, dsend_reg, d_reg_lpf, d_reg_rxrssi_ctrl, d_reg_txlin_gain; - int d_reg_pabias, d_reg_rxgain, d_reg_txgain; - - int d_ad9515_div; - - void _set_rfagc(float gain); - void _set_ifagc(float gain); - void _set_pga(float pga_gain); - -public: - usrp_basic *usrp(){ - return d_raw_usrp; - } - - wbxng(usrp_basic_sptr usrp, int which); - ~wbxng(); - void shutdown(); - - void set_reg_standby(); - - // Integer-Divider Ratio (3) - void set_reg_int_divider(); - - // Fractional-Divider Ratio (4) - void set_reg_frac_divider(); - - // Band Select and PLL (5) - void set_reg_bandselpll(); - - // Calibration (6) - void set_reg_cal(); - - // Lowpass Filter (7) - void set_reg_lpf(); - - // Rx Control/RSSI (8) - void set_reg_rxrssi_ctrl(); - - // Tx Linearity/Baseband Gain (9) - void set_reg_txlin_gain(); - - // PA Bias DAC (10) - void set_reg_pabias(); - - // Rx Gain (11) - void set_reg_rxgain(); - - // Tx Gain (12) - void set_reg_txgain(); - - // Send register write to SPI - void send_reg(int v); - - void set_gpio(); - bool lock_detect(); - bool set_rx_gain(float gain); - bool set_tx_gain(float gain); - - struct freq_result_t set_freq(double target_freq); -}; - - -/*****************************************************************************/ - -wbxng::wbxng(usrp_basic_sptr _usrp, int which) - : d_raw_usrp(_usrp.get()), d_which(which), d_is_shutdown(false) +// 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 BBAMP_EN (1 << 4) +#define PLL_CE (1 << 3) +#define PLL_PDBRF (1 << 2) +#define PLL_MUXOUT (1 << 1) +#define PLL_LOCK_DETECT (1 << 0) + +wbxng_base::wbxng_base(usrp_basic_sptr _usrp, int which, int _power_on) + : db_base(_usrp, which), d_power_on(_power_on) { - // Handler for WBX NG daughterboards. - // - // @param usrp: instance of usrp.source_c - // @param which: which side: 0, 1 corresponding to RX_A or RX_B respectively + /* + @param usrp: instance of usrp.source_c + @param which: which side: 0 or 1 corresponding to side A or B respectively + @type which: int + */ - // Use MSB with no header + d_first = true; d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0; - if(which == 0) { - d_spi_enable = SPI_ENABLE_RX_A; - } - else { - d_spi_enable = SPI_ENABLE_RX_B; - } - - // Sane defaults - d_mimo = 1; // 0 = OFF, 1 = ON - d_int_div = 192; // 128 = min, 255 = max - d_frac_div = 0; // 0 = min, 65535 = max - d_highband = 0; // 0 = freq <= 5.4e9, 1 = freq > 5.4e9 - d_five_gig = 0; // 0 = freq <= 3.e9, 1 = freq > 3e9 - d_cp_current = 1; // 0 = 2mA, 1 = 4mA - d_ref_div = 1; // 1 to 7 - d_rssi_hbw = 0; // 0 = 2 MHz, 1 = 6 MHz - d_txlpf_bw = 1; // 1 = 12 MHz, 2 = 18 MHz, 3 = 24 MHz - d_rxlpf_bw = 1; // 0 = 7.5 MHz, 1 = 9.5 MHz, 2 = 14 MHz, 3 = 18 MHz - d_rxlpf_fine = 2; // 0 = 90%, 1 = 95%, 2 = 100%, 3 = 105%, 4 = 110% - d_rxvga_ser = 1; // 0 = RXVGA controlled by B7:1, 1=controlled serially - d_rssi_range = 1; // 0 = low range (datasheet typo), 1=high range (0.5V - 2.0V) - d_rssi_mode = 1; // 0 = enable follows RXHP, 1 = enabled - d_rssi_mux = 0; // 0 = RSSI, 1 = TEMP - d_rx_hp_pin = 0; // 0 = Fc set by rx_hpf, 1 = 600 KHz - d_rx_hpf = 0; // 0 = 100Hz, 1 = 30KHz - d_rx_ant = 0; // 0 = Ant. #1, 1 = Ant. #2 - d_tx_ant = 0; // 0 = Ant. #1, 1 = Ant. #2 - d_txvga_ser = 1; // 0 = TXVGA controlled by B6:1, 1=controlled serially - d_tx_driver_lin = 2; // 0=50% (worst linearity), 1=63%, 2=78%, 3=100% (best lin) - d_tx_vga_lin = 2; // 0=50% (worst linearity), 1=63%, 2=78%, 3=100% (best lin) - d_tx_upconv_lin = 2; // 0=50% (worst linearity), 1=63%, 2=78%, 3=100% (best lin) - d_tx_bb_gain = 3; // 0=maxgain-5dB, 1=max-3dB, 2=max-1.5dB, 3=max - d_pabias_delay = 15; // 0 = 0, 15 = 7uS - d_pabias = 0; // 0 = 0 uA, 63 = 315uA - d_rx_rf_gain = 0; // 0 = 0dB, 1 = 0dB, 2 = 15dB, 3 = 30dB - d_rx_bb_gain = 16; // 0 = min, 31 = max (0 - 62 dB) - - d_txgain = 63; // 0 = min, 63 = max + usrp()->_write_oe(d_which, 0, 0xffff); // turn off all outputs + _enable_refclk(false); // disable refclk - /* - // Initialize GPIO and ATR - usrp()->common_write_io(C_TX, d_which, TX_SAFE_IO, TX_OE_MASK); - usrp()->_common_write_oe(C_TX, d_which, TX_OE_MASK, 0xffff); - usrp()->common_write_atr_txval(C_TX, d_which, TX_SAFE_IO); - usrp()->common_write_atr_rxval(C_TX, d_which, TX_SAFE_IO); - usrp()->common_write_atr_mask(C_TX, d_which, TX_OE_MASK); - - usrp()->common_write_io(C_RX, d_which, RX_SAFE_IO, RX_OE_MASK); - usrp()->_common_write_oe(C_RX, d_which, RX_OE_MASK, 0xffff); - usrp()->common_write_atr_txval(C_RX, d_which, RX_SAFE_IO); - usrp()->common_write_atr_rxval(C_RX, d_which, RX_SAFE_IO); - usrp()->common_write_atr_mask(C_RX, d_which, RX_OE_MASK); - - // Initialize chipset - // TODO: perform reset sequence to ensure power up defaults - set_reg_standby(); - set_reg_bandselpll(); - set_reg_cal(); - set_reg_lpf(); - set_reg_rxrssi_ctrl(); - set_reg_txlin_gain(); - set_reg_pabias(); - set_reg_rxgain(); - set_reg_txgain(); - //FIXME: set_freq(2.45e9); - */ + set_auto_tr(false); } -wbxng::~wbxng() +wbxng_base::~wbxng_base() { - //printf("wbxng::destructor\n"); - shutdown(); + delete d_common; } void -wbxng::shutdown() +wbxng_base::_write_all(int R, int control, int N) { - if (!d_is_shutdown){ - d_is_shutdown = true; - /* - usrp()->common_write_atr_txval(C_TX, d_which, TX_SAFE_IO); - usrp()->common_write_atr_rxval(C_TX, d_which, TX_SAFE_IO); - usrp()->common_write_atr_txval(C_RX, d_which, RX_SAFE_IO); - usrp()->common_write_atr_rxval(C_RX, d_which, RX_SAFE_IO); - */ + /* + Write R counter latch, control latch and N counter latch to VCO. + + Adds 10ms delay between writing control and N if this is first call. + This is the required power-up sequence. + + @param R: 24-bit R counter latch + @type R: int + @param control: 24-bit control latch + @type control: int + @param N: 24-bit N counter latch + @type N: int + */ + timespec t; + t.tv_sec = 0; + t.tv_nsec = 10000000; + + /* + _write_R(R); + _write_control(control); + if(d_first) { + //time.sleep(0.010); + nanosleep(&t, NULL); + d_first = false; } + _write_N(N); + */ } - void -wbxng::set_reg_standby() +wbxng_base::_write_control(int control) { - d_reg_standby = ((d_mimo<<17) | - (1<<16) | - (1<<6) | - (1<<5) | - (1<<4) | 2); - //send_reg(d_reg_standby); + //_write_it((control & ~0x3) | 0); } void -wbxng::set_reg_int_divider() +wbxng_base::_write_R(int R) { - d_reg_int_divider = (((d_frac_div & 0x03)<<16) | - (d_int_div<<4) | 3); - //send_reg(d_reg_int_divider); + //_write_it((R & ~0x3) | 1); } void -wbxng::set_reg_frac_divider() -{ - d_reg_frac_divider = ((d_frac_div & 0xfffc)<<2) | 4; - //send_reg(d_reg_frac_divider); -} - -void -wbxng::set_reg_bandselpll() -{ - d_reg_bandselpll = ((d_mimo<<17) | - (1<<16) | - (1<<15) | - (0<<11) | - (d_highband<<10) | - (d_cp_current<<9) | - (d_ref_div<<5) | - (d_five_gig<<4) | 5); - //send_reg(d_reg_bandselpll); - d_reg_bandselpll = ((d_mimo<<17) | - (1<<16) | - (1<<15) | - (1<<11) | - (d_highband<<10) | - (d_cp_current<<9) | - (d_ref_div<<5) | - (d_five_gig<<4) | 5); - //send_reg(d_reg_bandselpll); -} - -void -wbxng::set_reg_cal() +wbxng_base::_write_N(int N) { - // FIXME do calibration - d_reg_cal = (1<<14)|6; - //send_reg(d_reg_cal); + //_write_it((N & ~0x3) | 2); } void -wbxng::set_reg_lpf() +wbxng_base::_write_it(int v) { - d_reg_lpf = ( - (d_rssi_hbw<<15) | - (d_txlpf_bw<<10) | - (d_rxlpf_bw<<9) | - (d_rxlpf_fine<<4) | 7); - //send_reg(d_reg_lpf); + char s[3]; + s[0] = (char)((v >> 16) & 0xff); + s[1] = (char)((v >> 8) & 0xff); + s[2] = (char)(v & 0xff); + std::string str(s, 3); + //usrp()->_write_spi(0, d_spi_enable, d_spi_format, str); } - -void -wbxng::set_reg_rxrssi_ctrl() + +bool +wbxng_base::_lock_detect() { - d_reg_rxrssi_ctrl = ((d_rxvga_ser<<16) | - (d_rssi_range<<15) | - (d_rssi_mode<<14) | - (d_rssi_mux<<12) | - (1<<9) | - (d_rx_hpf<<6) | - (1<<4) | 8); - //send_reg(d_reg_rxrssi_ctrl); + /* + @returns: the value of the VCO/PLL lock detect bit. + @rtype: 0 or 1 + */ + /* + if(usrp()->read_io(d_which) & PLL_LOCK_DETECT) { + return true; + } + else { // Give it a second chance + // FIXME: make portable sleep + timespec t; + t.tv_sec = 0; + t.tv_nsec = 100000000; + nanosleep(&t, NULL); + + if(usrp()->read_io(d_which) & PLL_LOCK_DETECT) { + return true; + } + else { + return false; + } + } + */ + throw std::runtime_error("_lock_detect called from wbxng_base\n"); } -void -wbxng::set_reg_txlin_gain() -{ - d_reg_txlin_gain = ((d_txvga_ser<<14) | - (d_tx_driver_lin<<12) | - (d_tx_vga_lin<<10) | - (d_tx_upconv_lin<<6) | - (d_tx_bb_gain<<4) | 9); - //send_reg(d_reg_txlin_gain); +/* +bool +wbxng_base::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) +{ + **COMMENT** + Determine values of R, control, and N registers, along with actual freq. + + @param freq: target frequency in Hz + @type freq: float + @returns: (R, control, N, actual_freq) + @rtype: tuple(int, int, int, float) + + Override this in derived classes. + **COMMENT** + + //raise NotImplementedError; + throw std::runtime_error("_compute_regs called from wbxng_base\n"); } +*/ -void -wbxng::set_reg_pabias() +int +wbxng_base::_compute_control_reg() { - d_reg_pabias = ( - (d_pabias_delay<<10) | - (d_pabias<<4) | 10); - //send_reg(d_reg_pabias); + throw std::runtime_error("_compute_control_reg called from wbxng_base\n"); + //return d_common->_compute_control_reg(); } -void -wbxng::set_reg_rxgain() +int +wbxng_base::_refclk_divisor() { - d_reg_rxgain = ( - (d_rx_rf_gain<<9) | - (d_rx_bb_gain<<4) | 11); - //send_reg(d_reg_rxgain); + throw std::runtime_error("_refclk_divisor called from wbxng_base\n"); + //return d_common->_refclk_divisor(); } -void -wbxng::set_reg_txgain() +double +wbxng_base::_refclk_freq() { - d_reg_txgain = (d_txgain<<4) | 12; - //send_reg(d_reg_txgain); -} - -void -wbxng::send_reg(int v) -{ - // Send 24 bits, it keeps last 18 clocked in - char c[3]; - c[0] = (char)((v >> 16) & 0xff); - c[1] = (char)((v >> 8) & 0xff); - c[2] = (char)((v & 0xff)); - std::string s(c, 3); - - //usrp()->_write_spi(0, d_spi_enable, d_spi_format, s); - //printf("wbxng: Setting reg %d to %X\n", (v&15), v); + throw std::runtime_error("_refclk_divisor called from wbxng_base\n"); + // *** TODO *** Magic Number 64e6? + //return 64e6/_refclk_divisor(); } -// ---------------------------------------------------------------- - -void -wbxng::set_gpio() -{ - // We calculate four values: - // - // io_rx_while_rx: what to drive onto io_rx_* when receiving - // io_rx_while_tx: what to drive onto io_rx_* when transmitting - // io_tx_while_rx: what to drive onto io_tx_* when receiving - // io_tx_while_tx: what to drive onto io_tx_* when transmitting - // - // B1-B7 is ignored as gain is set serially for now. - - int rx_hp, tx_antsel, rx_antsel, tx_pa_sel; - if(d_rx_hp_pin) - rx_hp = RX_HP; - else - rx_hp = 0; - - if(d_tx_ant) - tx_antsel = ANTSEL_TX2_RX1; - else - tx_antsel = ANTSEL_TX1_RX2; - - if(d_rx_ant) - rx_antsel = ANTSEL_TX2_RX1; - else - rx_antsel = ANTSEL_TX1_RX2; - - if(d_five_gig) - tx_pa_sel = LB_PA_OFF; - else - tx_pa_sel = HB_PA_OFF; - +struct freq_result_t +wbxng_base::set_freq(double freq) +{ /* - // Reset GPIO and ATR - // FIXME: dont set io, oe, atr mask once basic code stops overriding our settings - usrp()->common_write_io(C_TX, d_which, TX_SAFE_IO, TX_OE_MASK); - usrp()->_common_write_oe(C_TX, d_which, TX_OE_MASK, 0xffff); - usrp()->common_write_atr_txval(C_TX, d_which, tx_pa_sel|tx_antsel|TX_EN|AD9515DIV); - usrp()->common_write_atr_rxval(C_TX, d_which, HB_PA_OFF|LB_PA_OFF|rx_antsel|AD9515DIV); - usrp()->common_write_atr_mask(C_TX, d_which, TX_OE_MASK); - - usrp()->common_write_io(C_RX, d_which, RX_SAFE_IO, RX_OE_MASK); - usrp()->_common_write_oe(C_RX, d_which, RX_OE_MASK, 0xffff); - usrp()->common_write_atr_txval(C_RX, d_which, EN|rx_hp); - usrp()->common_write_atr_rxval(C_RX, d_which, EN|rx_hp|RX_EN); - usrp()->common_write_atr_mask(C_RX, d_which, RX_OE_MASK); + @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. */ - //printf("GPIO: RXRX=%04X RXTX=%04X TXRX=%04X TXTX=%04X\n", - // io_rx_while_rx, io_rx_while_tx, io_tx_while_rx, io_tx_while_tx); -} - - -struct freq_result_t -wbxng::set_freq(double target_freq) -{ struct freq_result_t args = {false, 0}; - double scaler; - - if(target_freq > 3e9) { - d_five_gig = 1; - d_ad9515_div = 3; - scaler = 4.0/5.0; - } - else { - d_five_gig = 0; - d_ad9515_div = 3; - scaler = 4.0/3.0; - } - - if(target_freq > 5.408e9) { - d_highband = 1; - } - else { - d_highband = 0; - } - - double vco_freq = target_freq*scaler; - double sys_clk = usrp()->fpga_master_clock_freq(); // Usually 64e6 - double ref_clk = sys_clk / d_ad9515_div; - - double phdet_freq = ref_clk/d_ref_div; - double div = vco_freq/phdet_freq; - d_int_div = int(floor(div)); - d_frac_div = int((div-d_int_div)*65536.0); - // double actual_freq = phdet_freq*(d_int_div+(d_frac_div/65536.0))/scaler; + // 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; - //printf("RF=%f VCO=%f R=%d PHD=%f DIV=%3.5f I=%3d F=%5d ACT=%f\n", - // target_freq, vco_freq, d_ref_div, phdet_freq, - // div, d_int_div, d_frac_div, actual_freq); - - args.ok = lock_detect(); - - /* - set_gpio(); - set_reg_int_divider(); - set_reg_frac_divider(); - set_reg_bandselpll(); - - args.ok = lock_detect(); -#ifdef NO_LO_OFFSET - args.baseband_freq = target_freq; -#else - args.baseband_freq = actual_freq; -#endif - */ - - if(!args.ok){ - printf("Fail %f\n", target_freq); - } + //int R, control, N; + //double actual_freq; + //_compute_regs(freq, R, control, N, actual_freq); + + //if(R==0) { + // return args; + //} + + //_write_all(R, control, N); + //args.ok = _lock_detect(); + //args.baseband_freq = actual_freq; return args; } bool -wbxng::lock_detect() +wbxng_base::_set_pga(float pga_gain) { /* - @returns: the value of the VCO/PLL lock detect bit. - @rtype: 0 or 1 - */ - /* - if(usrp()->common_read_io(C_RX, d_which) & LOCKDET) { - return true; + if(d_which == 0) { + usrp()->set_pga(0, pga_gain); + usrp()->set_pga(1, pga_gain); } - else { // Give it a second chance - if(usrp()->common_read_io(C_RX, d_which) & LOCKDET) - return true; - else - return false; + else { + usrp()->set_pga(2, pga_gain); + usrp()->set_pga(3, pga_gain); } */ return true; } bool -wbxng::set_rx_gain(float gain) -{ - if(gain < 0.0) - gain = 0.0; - if(gain > 92.0) - gain = 92.0; - - // Split the gain between RF and baseband - // This is experimental, not prescribed - if(gain < 31.0) { - d_rx_rf_gain = 0; // 0 dB RF gain - rx_bb_gain = int(gain/2.0); - } - - if(gain >= 30.0 and gain < 60.5) { - d_rx_rf_gain = 2; // 15 dB RF gain - d_rx_bb_gain = int((gain-15.0)/2.0); - } - - if(gain >= 60.5) { - d_rx_rf_gain = 3; // 30.5 dB RF gain - d_rx_bb_gain = int((gain-30.5)/2.0); - } - - //set_reg_rxgain(); - +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; } -bool -wbxng::set_tx_gain(float gain) +double +wbxng_base::freq_min() { - if(gain < 0.0) { - gain = 0.0; - } - if(gain > 30.0) { - gain = 30.0; - } - - d_txgain = int((gain/30.0)*63); - //set_reg_txgain(); - - return true; + throw std::runtime_error("freq_min called from wbxng_base\n"); + //return d_common->freq_min(); } - -/*****************************************************************************/ - - -struct wbxng_table_entry { - wbxng_key key; - boost::weak_ptr<wbxng> value; - - wbxng_table_entry(const wbxng_key &_key, boost::weak_ptr<wbxng> _value) - : key(_key), value(_value) {} -}; - -typedef std::vector<wbxng_table_entry> wbxng_table; - -static boost::mutex s_table_mutex; -static wbxng_table s_table; - -static wbxng_sptr -_get_or_make_wbxng(usrp_basic_sptr usrp, int which) +double +wbxng_base::freq_max() { - wbxng_key key = {usrp->serial_number(), which}; + throw std::runtime_error("freq_max called from wbxng_base\n"); + //return d_common->freq_max(); +} - boost::mutex::scoped_lock guard(s_table_mutex); +// ---------------------------------------------------------------- - for (wbxng_table::iterator p = s_table.begin(); p != s_table.end();){ - if (p->value.expired()) // weak pointer is now dead - p = s_table.erase(p); // erase it - else { - if (key == p->key){ // found it - return wbxng_sptr(p->value); - } - else - ++p; // keep looking - } +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; } - // We don't have the wbxng we're looking for + d_common = new adf4350(_usrp, d_which, d_spi_enable); + + // power up the transmit side, but don't enable the mixer + /* + usrp()->_write_oe(d_which,(POWER_UP|RX_TXN|ENABLE), 0xffff); + usrp()->write_io(d_which, (power_on()|RX_TXN), (POWER_UP|RX_TXN|ENABLE)); + set_lo_offset(4e6); - // create a new one and stick it in the table. - wbxng_sptr r(new wbxng(usrp, which)); - wbxng_table_entry t(key, r); - s_table.push_back(t); + set_gain((gain_min() + gain_max()) / 2.0); // initialize gain + */ +} - return r; +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 -db_wbxng_base::db_wbxng_base(usrp_basic_sptr usrp, int which) - : db_base(usrp, which) -{ - /* - * Abstract base class for all wbxng boards. - * - * Derive board specific subclasses from db_wbxng_base_{tx,rx} - * - * @param usrp: instance of usrp.source_c - * @param which: which side: 0 or 1 corresponding to side A or B respectively - * @type which: int - */ + // Power down and leave the T/R switch in the R position + //usrp()->write_io(d_which, (power_off()|RX_TXN), (POWER_UP|RX_TXN|ENABLE)); + + // Power down VCO/PLL + d_PD = 3; - d_wbxng = _get_or_make_wbxng(usrp, which); + _write_control(_compute_control_reg()); + _enable_refclk(false); // turn off refclk + set_auto_tr(false); + } } -db_wbxng_base::~db_wbxng_base() +bool +wbxng_base_tx::set_auto_tr(bool on) { + bool ok = true; + /* + if(on) { + ok &= set_atr_mask (RX_TXN | ENABLE); + ok &= set_atr_txval(0 | ENABLE); + 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; } -void -db_wbxng_base::shutdown_common() +bool +wbxng_base_tx::set_enable(bool on) { - // If the usrp_basic in the wbxng is the same as the usrp_basic - // in the daughterboard, shutdown the wbxng now (when only one of Tx - // and Rx is open, this is always true). + /* + Enable transmitter if on is true + */ - if (d_wbxng->usrp() == usrp()){ - //std::cerr << "db_wbxng_base::shutdown_common: same -> shutting down\n"; - d_wbxng->shutdown(); + int v; + //int mask = RX_TXN | ENABLE_5 | ENABLE_33; + if(on) { + v = ENABLE_5 | ENABLE_33; } else { - //std::cerr << "db_wbxng_base::shutdown_common: different -> ignoring\n"; + v = RX_TXN; } + throw std::runtime_error("set_enable called from wbxng_base_tx\n"); + //return usrp()->write_io(d_which, v, mask); } -struct freq_result_t -db_wbxng_base::set_freq(double target_freq) +float +wbxng_base_tx::gain_min() { - /* - * @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. - */ - return d_wbxng->set_freq(target_freq+d_lo_offset); + return usrp()->pga_max(); } -bool -db_wbxng_base::is_quadrature() +float +wbxng_base_tx::gain_max() { - /* - * 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; + return usrp()->pga_max(); } -double -db_wbxng_base::freq_min() +float +wbxng_base_tx::gain_db_per_step() { - return 2.4e9; + return 1; } -double -db_wbxng_base::freq_max() +bool +wbxng_base_tx::set_gain(float gain) { - return 6.0e9; + /* + Set the gain. + + @param gain: gain in decibels + @returns True/False + */ + return _set_pga(usrp()->pga_max()); } -/******************************************************************************/ +/**************************************************************************/ -db_wbxng_tx::db_wbxng_tx(usrp_basic_sptr usrp, int which) - : db_wbxng_base(usrp, which) +wbxng_base_rx::wbxng_base_rx(usrp_basic_sptr _usrp, int which, int _power_on) + : wbxng_base(_usrp, which, _power_on) { - set_lo_offset(LO_OFFSET); - //printf("db_wbxng_tx::db_wbxng_tx\n"); + /* + @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, (POWER_UP|RX2_RX1N|ENABLE), 0xffff); + usrp()->write_io(d_which, (power_on()|RX2_RX1N|ENABLE), + (POWER_UP|RX2_RX1N|ENABLE)); + + // set up for RX on TX/RX port + select_rx_antenna("TX/RX"); + + bypass_adc_buffers(true); + + set_lo_offset(-4e6); + */ } -db_wbxng_tx::~db_wbxng_tx() +wbxng_base_rx::~wbxng_base_rx() { shutdown(); } void -db_wbxng_tx::shutdown() +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; - shutdown_common(); + // do whatever there is to do to shutdown + + // Power down + //usrp()->common_write_io(C_RX, d_which, power_off(), (POWER_UP|ENABLE)); + + // Power down VCO/PLL + d_PD = 3; + + + // 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"); } } -float -db_wbxng_tx::gain_min() +bool +wbxng_base_rx::set_auto_tr(bool on) { - return 0; + //bool ok = true; + /* + if(on) { + ok &= set_atr_mask (ENABLE); + ok &= set_atr_txval( 0); + ok &= set_atr_rxval(ENABLE); + } + else { + ok &= set_atr_mask (0); + ok &= set_atr_txval(0); + ok &= set_atr_rxval(0); + } + */ + return true; } -float -db_wbxng_tx::gain_max() +/* *** TODO *** Defined select_rx_antenna twice? +bool +wbxng_base_rx::select_rx_antenna(int which_antenna) { - return 30; -} + **COMMENT** + Specify which antenna port to use for reception. + @param which_antenna: either 'TX/RX' or 'RX2' + **COMMENT** -float -db_wbxng_tx::gain_db_per_step() -{ - return (30.0/63.0); + 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; + // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n"); + } + return true; } +*/ bool -db_wbxng_tx::set_gain(float gain) +wbxng_base_rx::select_rx_antenna(const std::string &which_antenna) { - return d_wbxng->set_tx_gain(gain); + /* + 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 { + // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n"); + return false; + } + */ + return true; } bool -db_wbxng_tx::i_and_q_swapped() +wbxng_base_rx::set_gain(float gain) { - return true; + /* + 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 = .2; + V_mingain = 1.2; + V_fullscale = 3.3; + dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/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))); + */ + return false; } +// ---------------------------------------------------------------- -/******************************************************************************/ +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) - : db_wbxng_base(usrp, which) +/* +bool +db_wbxng_tx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) { - /* - * @param usrp: instance of usrp.source_c - * @param which: 0 or 1 corresponding to side RX_A or RX_B respectively. - */ - set_lo_offset(LO_OFFSET); - //printf("db_wbxng_rx:d_wbxng_rx\n"); + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); } +*/ -db_wbxng_rx::~db_wbxng_rx() + +db_wbxng_rx::db_wbxng_rx(usrp_basic_sptr usrp, int which) + : wbxng_base_rx(usrp, which) { - shutdown(); + set_gain((gain_min() + gain_max()) / 2.0); // initialize gain } -void -db_wbxng_rx::shutdown() +db_wbxng_rx::~db_wbxng_rx() { - if (!d_is_shutdown){ - d_is_shutdown = true; - shutdown_common(); - } } float db_wbxng_rx::gain_min() { - return 0.0; + return usrp()->pga_min(); } float db_wbxng_rx::gain_max() { - return 92.0; + return usrp()->pga_max()+70; } float db_wbxng_rx::gain_db_per_step() { - return 1; + return 0.05; +} + + +bool +db_wbxng_rx::i_and_q_swapped() +{ + return true; } +/* bool -db_wbxng_rx::set_gain(float gain) +db_wbxng_rx::_compute_regs(double freq, int &retR, int &retcontrol, + int &retN, double &retfreq) { - return d_wbxng->set_rx_gain(gain); + return d_common->_compute_regs(_refclk_freq(), freq, retR, + retcontrol, retN, retfreq); } +*/ + diff --git a/usrp/host/lib/db_wbxng_adf4350.cc b/usrp/host/lib/db_wbxng_adf4350.cc new file mode 100644 index 000000000..22262be33 --- /dev/null +++ b/usrp/host/lib/db_wbxng_adf4350.cc @@ -0,0 +1,156 @@ +/* + * Copyright 2009 Ettus Research LLC + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <usrp/db_wbxng_adf4350.h> +#include <usrp/db_wbxng_adf4350_regs.h> +#include <db_base_impl.h> +#include <stdio.h> +//#include "io.h" +//#include "spi.h" + +#define INPUT_REF_FREQ FREQ_C(10e6) +#define DIV_ROUND(num, denom) (((num) + ((denom)/2))/(denom)) +#define FREQ_C(freq) ((uint32_t)DIV_ROUND(freq, (uint32_t)1000)) +#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), 0xffff); + + /* 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, 1, CE_PIN); + }else{ + d_usrp->write_io(d_which, 0, CE_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, 3); + + d_usrp->_write_spi(0, d_spi_enable, d_spi_format, str); + /* 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->_divider_select = 0; + while (freq < MIN_VCO_FREQ){ + freq <<= 1; //double the freq + d_regs->_divider_select++; //double the divider + } + /* Ramp up the R divider until the N divider is at least the minimum. */ + d_regs->_10_bit_r_counter = INPUT_REF_FREQ_2X*MIN_INT_DIV/freq; + uint64_t n_mod; + do{ + d_regs->_10_bit_r_counter++; + n_mod = freq; + n_mod *= d_regs->_10_bit_r_counter; + n_mod *= d_regs->_mod; + n_mod /= INPUT_REF_FREQ_2X; + /* calculate int and frac */ + d_regs->_int = n_mod/d_regs->_mod; + d_regs->_frac = (n_mod - (freq_t)d_regs->_int*d_regs->_mod) & uint16_t(0xfff); + /*printf( + "VCO %lu KHz, Int %u, Frac %u, Mod %u, R %u, Div %u\n", + freq, d_regs->_int, d_regs->_frac, + d_regs->_mod, d_regs->_10_bit_r_counter, (1 << d_regs->_divider_select) + );*/ + }while(d_regs->_int < MIN_INT_DIV); + /* calculate the band select so PFD is under 125 KHz */ + d_regs->_8_bit_band_select_clock_divider_value = \ + INPUT_REF_FREQ_2X/(FREQ_C(125e3)*d_regs->_10_bit_r_counter) + 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->_int; + temp *= d_regs->_mod; + temp += d_regs->_frac; + temp *= INPUT_REF_FREQ_2X; + temp /= d_regs->_mod; + temp /= d_regs->_10_bit_r_counter; + temp /= (1 << d_regs->_divider_select); + return temp; +} 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..b320e8bbf --- /dev/null +++ b/usrp/host/lib/db_wbxng_adf4350_regs.cc @@ -0,0 +1,106 @@ +/* + * Copyright 2009 Ettus Research LLC + */ + +#include <usrp/db_wbxng_adf4350_regs.h> +#include <usrp/db_wbxng_adf4350.h> +//#include "cal_div.h" + +adf4350_regs::adf4350_regs(adf4350* _adf4350){ + d_adf4350 = _adf4350; + + /* reg 0 */ + _int = uint16_t(100); + _frac = 0; + /* reg 1 */ + _prescaler = 1; /* 8/9 */ + _phase = 0; /* 0 */ + _mod = uint16_t(0xfff); /* max fractional accuracy */ + /* reg 2 */ + _low_noise_and_low_spur_modes = 0; /* low noise mode */ + _muxout = 6; /* digital lock detect */ + _reference_doubler = 1; /* enabled */ + _rdiv2 = 0; /* disabled */ + _10_bit_r_counter = uint16_t(1); + _double_buff = 0; /* disabled */ + _charge_pump_setting = 7; /* 2.50 mA */ + _ldf = 0; /* frac-n */ + _ldp = 0; /* 10 ns */ + _pd_polarity = 1; /* positive */ + _power_down = 0; /* disabled */ + _cp_three_state = 0; /* disabled */ + _counter_reset = 0; /* disabled */ + /* reg 3 */ + _csr = 0; /* disabled */ + _clk_div_mode = 0; /* clock divider off */ + _12_bit_clock_divider_value = 0; /* 0 */ + /* reg 4 */ + _feedback_select = 1; /* fundamental */ + _divider_select = 0; + _8_bit_band_select_clock_divider_value = 0; + _vco_power_down = 0; /* vco powered up */ + _mtld = 0; /* mute disabled */ + _aux_output_select = 0; /* divided output */ + _aux_output_enable = 0; /* disabled */ + _aux_output_power = 0; /* -4 */ + _rf_output_enable = 1; /* enabled */ + _output_power = 1; /* -1 */ + /* reg 5 */ + _ld_pin_mode = 1; /* digital lock detect */ +} + +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(_int, 15) | + _reg_shift(_frac, 3)); break; + case 1: data = ( + _reg_shift(_prescaler, 27) | + _reg_shift(_phase, 15) | + _reg_shift(_mod, 3)); break; + case 2: data = ( + _reg_shift(_low_noise_and_low_spur_modes, 29) | + _reg_shift(_muxout, 26) | + _reg_shift(_reference_doubler, 25) | + _reg_shift(_rdiv2, 24) | + _reg_shift(_10_bit_r_counter, 14) | + _reg_shift(_double_buff, 13) | + _reg_shift(_charge_pump_setting, 9) | + _reg_shift(_ldf, 8) | + _reg_shift(_ldp, 7) | + _reg_shift(_pd_polarity, 6) | + _reg_shift(_power_down, 5) | + _reg_shift(_cp_three_state, 4) | + _reg_shift(_counter_reset, 3)); break; + case 3: data = ( + _reg_shift(_csr, 18) | + _reg_shift(_clk_div_mode, 15) | + _reg_shift(_12_bit_clock_divider_value, 3)); break; + case 4: data = ( + _reg_shift(_feedback_select, 23) | + _reg_shift(_divider_select, 20) | + _reg_shift(_8_bit_band_select_clock_divider_value, 12) | + _reg_shift(_vco_power_down, 11) | + _reg_shift(_mtld, 10) | + _reg_shift(_aux_output_select, 9) | + _reg_shift(_aux_output_enable, 8) | + _reg_shift(_aux_output_power, 6) | + _reg_shift(_rf_output_enable, 5) | + _reg_shift(_output_power, 3)); break; + case 5: data = ( + _reg_shift(_ld_pin_mode, 22)); break; + default: return; + } + /* write the data out to spi */ + d_adf4350->_write(addr, data); +} |