2 // Copyright 2008 Free Software Foundation, Inc.
4 // This file is part of GNU Radio
6 // GNU Radio is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either asversion 3, or (at your option)
11 // GNU Radio is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with GNU Radio; see the file COPYING. If not, write to
18 // the Free Software Foundation, Inc., 51 Franklin Street,
19 // Boston, MA 02110-1301, USA.
21 #include <usrp/db_wbxng.h>
22 #include <usrp/db_wbxng_adf4350.h>
23 #include <db_base_impl.h>
26 // d'board i/o pin defs
27 // Tx and Rx have shared defs, but different i/o regs
28 #define ENABLE_5 (1 << 7) // enables 5.0V power supply
29 #define ENABLE_33 (1 << 6) // enables 3.3V supply
30 #define RX_TXN (1 << 5) // Tx only: T/R antenna switch for TX/RX port
31 #define RX2_RX1N (1 << 5) // Rx only: antenna switch between RX2 and TX/RX port
32 #define TXMOD_EN (1 << 4)
33 #define PLL_CE (1 << 3)
34 #define PLL_PDBRF (1 << 2)
35 #define PLL_MUXOUT (1 << 1)
36 #define PLL_LOCK_DETECT (1 << 0)
38 wbxng_base::wbxng_base(usrp_basic_sptr _usrp, int which, int _power_on)
39 : db_base(_usrp, which), d_power_on(_power_on)
42 @param usrp: instance of usrp.source_c
43 @param which: which side: 0 or 1 corresponding to side A or B respectively
47 usrp()->_write_oe(d_which, 0, 0xffff); // turn off all outputs
50 d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0;
52 _enable_refclk(false); // disable refclk
57 wbxng_base::~wbxng_base()
63 wbxng_base::_write_all(int R, int control, int N)
66 Write R counter latch, control latch and N counter latch to VCO.
68 Adds 10ms delay between writing control and N if this is first call.
69 This is the required power-up sequence.
71 @param R: 24-bit R counter latch
73 @param control: 24-bit control latch
75 @param N: 24-bit N counter latch
84 _write_control(control);
95 wbxng_base::_write_control(int control)
97 //_write_it((control & ~0x3) | 0);
101 wbxng_base::_write_R(int R)
103 //_write_it((R & ~0x3) | 1);
107 wbxng_base::_write_N(int N)
109 //_write_it((N & ~0x3) | 2);
113 wbxng_base::_write_it(int v)
116 s[0] = (char)((v >> 16) & 0xff);
117 s[1] = (char)((v >> 8) & 0xff);
118 s[2] = (char)(v & 0xff);
119 std::string str(s, 3);
120 //usrp()->_write_spi(0, d_spi_enable, d_spi_format, str);
124 wbxng_base::_lock_detect()
127 @returns: the value of the VCO/PLL lock detect bit.
131 if(d_common->_get_locked()){
134 else { // Give it a second chance
137 // FIXME: make portable sleep
140 t.tv_nsec = 100000000;
143 if(usrp()->read_io(d_which) & PLL_LOCK_DETECT) {
152 throw std::runtime_error("_lock_detect called from wbxng_base\n");
157 wbxng_base::_compute_regs(double freq, int &retR, int &retcontrol,
158 int &retN, double &retfreq)
161 Determine values of R, control, and N registers, along with actual freq.
163 @param freq: target frequency in Hz
165 @returns: (R, control, N, actual_freq)
166 @rtype: tuple(int, int, int, float)
168 Override this in derived classes.
171 //raise NotImplementedError;
172 throw std::runtime_error("_compute_regs called from wbxng_base\n");
177 wbxng_base::_compute_control_reg()
179 throw std::runtime_error("_compute_control_reg called from wbxng_base\n");
180 //return d_common->_compute_control_reg();
184 wbxng_base::_refclk_divisor()
186 throw std::runtime_error("_refclk_divisor called from wbxng_base\n");
187 //return d_common->_refclk_divisor();
191 wbxng_base::_refclk_freq()
193 throw std::runtime_error("_refclk_divisor called from wbxng_base\n");
194 // *** TODO *** Magic Number 64e6?
195 //return 64e6/_refclk_divisor();
199 wbxng_base::set_freq(double freq)
202 @returns (ok, actual_baseband_freq) where:
203 ok is True or False and indicates success or failure,
204 actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
207 freq_t int_freq = freq_t(freq);
208 bool ok = d_common->_set_freq(int_freq*2);
209 double freq_result = (double) d_common->_get_freq()/2.0;
210 struct freq_result_t args = {ok, freq_result};
212 /* Wait before reading Lock Detect*/
215 t.tv_nsec = 10000000;
218 fprintf(stderr,"Setting WBXNG frequency, requested %d, obtained %f, lock_detect %d\n",
219 int_freq, freq_result, _lock_detect());
221 // Offsetting the LO helps get the Tx carrier leakage out of the way.
222 // This also ensures that on Rx, we're not getting hosed by the
223 // FPGA's DC removal loop's time constant. We were seeing a
224 // problem when running with discontinuous transmission.
225 // Offsetting the LO made the problem go away.
226 //freq += d_lo_offset;
229 //double actual_freq;
230 //_compute_regs(freq, R, control, N, actual_freq);
236 //_write_all(R, control, N);
237 //args.ok = _lock_detect();
238 //args.baseband_freq = actual_freq;
243 wbxng_base::_set_pga(float pga_gain)
247 usrp()->set_pga(0, pga_gain);
248 usrp()->set_pga(1, pga_gain);
251 usrp()->set_pga(2, pga_gain);
252 usrp()->set_pga(3, pga_gain);
259 wbxng_base::is_quadrature()
262 Return True if this board requires both I & Q analog channels.
264 This bit of info is useful when setting up the USRP Rx mux register.
270 wbxng_base::freq_min()
272 return (double) d_common->_get_min_freq()/2.0;
276 wbxng_base::freq_max()
278 return (double) d_common->_get_max_freq()/2.0;
281 // ----------------------------------------------------------------
283 wbxng_base_tx::wbxng_base_tx(usrp_basic_sptr _usrp, int which, int _power_on)
284 : wbxng_base(_usrp, which, _power_on)
287 @param usrp: instance of usrp.sink_c
288 @param which: 0 or 1 corresponding to side TX_A or TX_B respectively.
292 d_spi_enable = SPI_ENABLE_TX_A;
295 d_spi_enable = SPI_ENABLE_TX_B;
298 d_common = new adf4350(_usrp, d_which, d_spi_enable);
300 // power up the transmit side, but don't enable the mixer
301 usrp()->_write_oe(d_which,(RX_TXN|TXMOD_EN|ENABLE_33|ENABLE_5), (RX_TXN|TXMOD_EN|ENABLE_33|ENABLE_5));
302 usrp()->write_io(d_which, (power_on()|RX_TXN|TXMOD_EN|ENABLE_33|ENABLE_5), (RX_TXN|TXMOD_EN|ENABLE_33|ENABLE_5));
303 fprintf(stderr,"Setting WBXNG TXMOD on");
304 //set_lo_offset(4e6);
306 //set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
309 wbxng_base_tx::~wbxng_base_tx()
316 wbxng_base_tx::shutdown()
318 // fprintf(stderr, "wbxng_base_tx::shutdown d_is_shutdown = %d\n", d_is_shutdown);
321 d_is_shutdown = true;
322 // do whatever there is to do to shutdown
324 // Power down and leave the T/R switch in the R position
325 usrp()->write_io(d_which, (power_off()|RX_TXN), (RX_TXN|ENABLE_33|ENABLE_5));
327 // Power down VCO/PLL
328 d_common->_enable(false);
331 _write_control(_compute_control_reg());
333 _enable_refclk(false); // turn off refclk
339 wbxng_base_tx::set_auto_tr(bool on)
343 ok &= set_atr_mask (RX_TXN | ENABLE_33 | ENABLE_5);
344 ok &= set_atr_txval(0 | ENABLE_33 | ENABLE_5);
345 ok &= set_atr_rxval(RX_TXN | 0);
348 ok &= set_atr_mask (0);
349 ok &= set_atr_txval(0);
350 ok &= set_atr_rxval(0);
356 wbxng_base_tx::set_enable(bool on)
359 Enable transmitter if on is true
363 int mask = RX_TXN | ENABLE_5 | ENABLE_33;
365 v = ENABLE_5 | ENABLE_33;
370 return usrp()->write_io(d_which, v, mask);
374 wbxng_base_tx::gain_min()
376 return usrp()->pga_max();
380 wbxng_base_tx::gain_max()
382 return usrp()->pga_max();
386 wbxng_base_tx::gain_db_per_step()
392 wbxng_base_tx::set_gain(float gain)
397 @param gain: gain in decibels
400 return _set_pga(usrp()->pga_max());
404 /**************************************************************************/
407 wbxng_base_rx::wbxng_base_rx(usrp_basic_sptr _usrp, int which, int _power_on)
408 : wbxng_base(_usrp, which, _power_on)
411 @param usrp: instance of usrp.source_c
412 @param which: 0 or 1 corresponding to side RX_A or RX_B respectively.
416 d_spi_enable = SPI_ENABLE_RX_A;
419 d_spi_enable = SPI_ENABLE_RX_B;
422 d_common = new adf4350(_usrp, d_which, d_spi_enable);
424 usrp()->_write_oe(d_which, (RX2_RX1N|ENABLE_33|ENABLE_5), (RX2_RX1N|ENABLE_33|ENABLE_5));
425 usrp()->write_io(d_which, (power_on()|RX2_RX1N|ENABLE_33|ENABLE_5), (RX2_RX1N|ENABLE_33|ENABLE_5));
427 // set up for RX on TX/RX port
428 select_rx_antenna("TX/RX");
430 bypass_adc_buffers(true);
437 wbxng_base_rx::~wbxng_base_rx()
443 wbxng_base_rx::shutdown()
445 // fprintf(stderr, "wbxng_base_rx::shutdown d_is_shutdown = %d\n", d_is_shutdown);
448 d_is_shutdown = true;
449 // do whatever there is to do to shutdown
452 usrp()->common_write_io(C_RX, d_which, power_off(), (ENABLE_33|ENABLE_5));
454 // Power down VCO/PLL
455 d_common->_enable(false);
457 // fprintf(stderr, "wbxng_base_rx::shutdown before _write_control\n");
458 //_write_control(_compute_control_reg());
460 // fprintf(stderr, "wbxng_base_rx::shutdown before _enable_refclk\n");
461 _enable_refclk(false); // turn off refclk
463 // fprintf(stderr, "wbxng_base_rx::shutdown before set_auto_tr\n");
466 // fprintf(stderr, "wbxng_base_rx::shutdown after set_auto_tr\n");
471 wbxng_base_rx::set_auto_tr(bool on)
475 ok &= set_atr_mask (ENABLE_33|ENABLE_5);
476 ok &= set_atr_txval( 0);
477 ok &= set_atr_rxval(ENABLE_33|ENABLE_5);
480 ok &= set_atr_mask (0);
481 ok &= set_atr_txval(0);
482 ok &= set_atr_rxval(0);
488 wbxng_base_rx::select_rx_antenna(int which_antenna)
491 Specify which antenna port to use for reception.
492 @param which_antenna: either 'TX/RX' or 'RX2'
495 if(which_antenna == 0) {
496 usrp()->write_io(d_which, 0,RX2_RX1N);
498 else if(which_antenna == 1) {
499 usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N);
503 // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n");
509 wbxng_base_rx::select_rx_antenna(const std::string &which_antenna)
512 Specify which antenna port to use for reception.
513 @param which_antenna: either 'TX/RX' or 'RX2'
517 if(which_antenna == "TX/RX") {
518 usrp()->write_io(d_which, 0, RX2_RX1N);
520 else if(which_antenna == "RX2") {
521 usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N);
524 // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n");
532 wbxng_base_rx::set_gain(float gain)
537 @param gain: gain in decibels
543 gain = std::max(gain_min(), std::min(gain, gain_max()));
545 float pga_gain, agc_gain;
546 float V_maxgain, V_mingain, V_fullscale, dac_value;
548 float maxgain = gain_max() - usrp()->pga_max();
549 float mingain = gain_min();
551 pga_gain = gain-maxgain;
552 assert(pga_gain <= usrp()->pga_max());
563 dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale;
565 assert(dac_value>=0 && dac_value<4096);
567 return (usrp()->write_aux_dac(d_which, 0, int(dac_value))
568 && _set_pga(int(pga_gain)));
573 // ----------------------------------------------------------------
575 db_wbxng_tx::db_wbxng_tx(usrp_basic_sptr usrp, int which)
576 : wbxng_base_tx(usrp, which)
580 db_wbxng_tx::~db_wbxng_tx()
586 db_wbxng_tx::_compute_regs(double freq, int &retR, int &retcontrol,
587 int &retN, double &retfreq)
589 return d_common->_compute_regs(_refclk_freq(), freq, retR,
590 retcontrol, retN, retfreq);
595 db_wbxng_rx::db_wbxng_rx(usrp_basic_sptr usrp, int which)
596 : wbxng_base_rx(usrp, which)
598 set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
601 db_wbxng_rx::~db_wbxng_rx()
606 db_wbxng_rx::gain_min()
608 return usrp()->pga_min();
612 db_wbxng_rx::gain_max()
614 return usrp()->pga_max()+70;
618 db_wbxng_rx::gain_db_per_step()
625 db_wbxng_rx::i_and_q_swapped()
632 db_wbxng_rx::_compute_regs(double freq, int &retR, int &retcontrol,
633 int &retN, double &retfreq)
635 return d_common->_compute_regs(_refclk_freq(), freq, retR,
636 retcontrol, retN, retfreq);