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>
25 // d'board i/o pin defs
26 // Tx and Rx have shared defs, but different i/o regs
27 #define ENABLE_5 (1 << 7) // enables 5.0V power supply
28 #define ENABLE_33 (1 << 6) // enables 3.3V supply
29 #define RX_TXN (1 << 5) // Tx only: T/R antenna switch for TX/RX port
30 #define RX2_RX1N (1 << 5) // Rx only: antenna switch between RX2 and TX/RX port
31 #define BBAMP_EN (1 << 4)
32 #define PLL_CE (1 << 3)
33 #define PLL_PDBRF (1 << 2)
34 #define PLL_MUXOUT (1 << 1)
35 #define PLL_LOCK_DETECT (1 << 0)
37 wbxng_base::wbxng_base(usrp_basic_sptr _usrp, int which, int _power_on)
38 : db_base(_usrp, which), d_power_on(_power_on)
41 @param usrp: instance of usrp.source_c
42 @param which: which side: 0 or 1 corresponding to side A or B respectively
47 d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0;
49 usrp()->_write_oe(d_which, 0, 0xffff); // turn off all outputs
50 _enable_refclk(false); // disable refclk
55 wbxng_base::~wbxng_base()
61 wbxng_base::_write_all(int R, int control, int N)
64 Write R counter latch, control latch and N counter latch to VCO.
66 Adds 10ms delay between writing control and N if this is first call.
67 This is the required power-up sequence.
69 @param R: 24-bit R counter latch
71 @param control: 24-bit control latch
73 @param N: 24-bit N counter latch
82 _write_control(control);
93 wbxng_base::_write_control(int control)
95 //_write_it((control & ~0x3) | 0);
99 wbxng_base::_write_R(int R)
101 //_write_it((R & ~0x3) | 1);
105 wbxng_base::_write_N(int N)
107 //_write_it((N & ~0x3) | 2);
111 wbxng_base::_write_it(int v)
114 s[0] = (char)((v >> 16) & 0xff);
115 s[1] = (char)((v >> 8) & 0xff);
116 s[2] = (char)(v & 0xff);
117 std::string str(s, 3);
118 //usrp()->_write_spi(0, d_spi_enable, d_spi_format, str);
122 wbxng_base::_lock_detect()
125 @returns: the value of the VCO/PLL lock detect bit.
129 if(usrp()->read_io(d_which) & PLL_LOCK_DETECT) {
132 else { // Give it a second chance
133 // FIXME: make portable sleep
136 t.tv_nsec = 100000000;
139 if(usrp()->read_io(d_which) & PLL_LOCK_DETECT) {
147 throw std::runtime_error("_lock_detect called from wbxng_base\n");
152 wbxng_base::_compute_regs(double freq, int &retR, int &retcontrol,
153 int &retN, double &retfreq)
156 Determine values of R, control, and N registers, along with actual freq.
158 @param freq: target frequency in Hz
160 @returns: (R, control, N, actual_freq)
161 @rtype: tuple(int, int, int, float)
163 Override this in derived classes.
166 //raise NotImplementedError;
167 throw std::runtime_error("_compute_regs called from wbxng_base\n");
172 wbxng_base::_compute_control_reg()
174 throw std::runtime_error("_compute_control_reg called from wbxng_base\n");
175 //return d_common->_compute_control_reg();
179 wbxng_base::_refclk_divisor()
181 throw std::runtime_error("_refclk_divisor called from wbxng_base\n");
182 //return d_common->_refclk_divisor();
186 wbxng_base::_refclk_freq()
188 throw std::runtime_error("_refclk_divisor called from wbxng_base\n");
189 // *** TODO *** Magic Number 64e6?
190 //return 64e6/_refclk_divisor();
194 wbxng_base::set_freq(double freq)
197 @returns (ok, actual_baseband_freq) where:
198 ok is True or False and indicates success or failure,
199 actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
202 struct freq_result_t args = {false, 0};
204 // Offsetting the LO helps get the Tx carrier leakage out of the way.
205 // This also ensures that on Rx, we're not getting hosed by the
206 // FPGA's DC removal loop's time constant. We were seeing a
207 // problem when running with discontinuous transmission.
208 // Offsetting the LO made the problem go away.
212 //double actual_freq;
213 //_compute_regs(freq, R, control, N, actual_freq);
219 //_write_all(R, control, N);
220 //args.ok = _lock_detect();
221 //args.baseband_freq = actual_freq;
226 wbxng_base::_set_pga(float pga_gain)
230 usrp()->set_pga(0, pga_gain);
231 usrp()->set_pga(1, pga_gain);
234 usrp()->set_pga(2, pga_gain);
235 usrp()->set_pga(3, pga_gain);
242 wbxng_base::is_quadrature()
245 Return True if this board requires both I & Q analog channels.
247 This bit of info is useful when setting up the USRP Rx mux register.
253 wbxng_base::freq_min()
255 throw std::runtime_error("freq_min called from wbxng_base\n");
256 //return d_common->freq_min();
260 wbxng_base::freq_max()
262 throw std::runtime_error("freq_max called from wbxng_base\n");
263 //return d_common->freq_max();
266 // ----------------------------------------------------------------
268 wbxng_base_tx::wbxng_base_tx(usrp_basic_sptr _usrp, int which, int _power_on)
269 : wbxng_base(_usrp, which, _power_on)
272 @param usrp: instance of usrp.sink_c
273 @param which: 0 or 1 corresponding to side TX_A or TX_B respectively.
277 d_spi_enable = SPI_ENABLE_TX_A;
280 d_spi_enable = SPI_ENABLE_TX_B;
283 d_common = new adf4350(_usrp, d_which, d_spi_enable);
285 // power up the transmit side, but don't enable the mixer
287 usrp()->_write_oe(d_which,(POWER_UP|RX_TXN|ENABLE), 0xffff);
288 usrp()->write_io(d_which, (power_on()|RX_TXN), (POWER_UP|RX_TXN|ENABLE));
291 set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
295 wbxng_base_tx::~wbxng_base_tx()
302 wbxng_base_tx::shutdown()
304 // fprintf(stderr, "wbxng_base_tx::shutdown d_is_shutdown = %d\n", d_is_shutdown);
307 d_is_shutdown = true;
308 // do whatever there is to do to shutdown
310 // Power down and leave the T/R switch in the R position
311 //usrp()->write_io(d_which, (power_off()|RX_TXN), (POWER_UP|RX_TXN|ENABLE));
313 // Power down VCO/PLL
316 _write_control(_compute_control_reg());
317 _enable_refclk(false); // turn off refclk
323 wbxng_base_tx::set_auto_tr(bool on)
328 ok &= set_atr_mask (RX_TXN | ENABLE);
329 ok &= set_atr_txval(0 | ENABLE);
330 ok &= set_atr_rxval(RX_TXN | 0);
333 ok &= set_atr_mask (0);
334 ok &= set_atr_txval(0);
335 ok &= set_atr_rxval(0);
342 wbxng_base_tx::set_enable(bool on)
345 Enable transmitter if on is true
349 //int mask = RX_TXN | ENABLE_5 | ENABLE_33;
351 v = ENABLE_5 | ENABLE_33;
356 throw std::runtime_error("set_enable called from wbxng_base_tx\n");
357 //return usrp()->write_io(d_which, v, mask);
361 wbxng_base_tx::gain_min()
363 return usrp()->pga_max();
367 wbxng_base_tx::gain_max()
369 return usrp()->pga_max();
373 wbxng_base_tx::gain_db_per_step()
379 wbxng_base_tx::set_gain(float gain)
384 @param gain: gain in decibels
387 return _set_pga(usrp()->pga_max());
391 /**************************************************************************/
394 wbxng_base_rx::wbxng_base_rx(usrp_basic_sptr _usrp, int which, int _power_on)
395 : wbxng_base(_usrp, which, _power_on)
398 @param usrp: instance of usrp.source_c
399 @param which: 0 or 1 corresponding to side RX_A or RX_B respectively.
403 d_spi_enable = SPI_ENABLE_RX_A;
406 d_spi_enable = SPI_ENABLE_RX_B;
409 d_common = new adf4350(_usrp, d_which, d_spi_enable);
412 usrp()->_write_oe(d_which, (POWER_UP|RX2_RX1N|ENABLE), 0xffff);
413 usrp()->write_io(d_which, (power_on()|RX2_RX1N|ENABLE),
414 (POWER_UP|RX2_RX1N|ENABLE));
416 // set up for RX on TX/RX port
417 select_rx_antenna("TX/RX");
419 bypass_adc_buffers(true);
425 wbxng_base_rx::~wbxng_base_rx()
431 wbxng_base_rx::shutdown()
433 // fprintf(stderr, "wbxng_base_rx::shutdown d_is_shutdown = %d\n", d_is_shutdown);
436 d_is_shutdown = true;
437 // do whatever there is to do to shutdown
440 //usrp()->common_write_io(C_RX, d_which, power_off(), (POWER_UP|ENABLE));
442 // Power down VCO/PLL
446 // fprintf(stderr, "wbxng_base_rx::shutdown before _write_control\n");
447 //_write_control(_compute_control_reg());
449 // fprintf(stderr, "wbxng_base_rx::shutdown before _enable_refclk\n");
450 //_enable_refclk(false); // turn off refclk
452 // fprintf(stderr, "wbxng_base_rx::shutdown before set_auto_tr\n");
453 //set_auto_tr(false);
455 // fprintf(stderr, "wbxng_base_rx::shutdown after set_auto_tr\n");
460 wbxng_base_rx::set_auto_tr(bool on)
465 ok &= set_atr_mask (ENABLE);
466 ok &= set_atr_txval( 0);
467 ok &= set_atr_rxval(ENABLE);
470 ok &= set_atr_mask (0);
471 ok &= set_atr_txval(0);
472 ok &= set_atr_rxval(0);
478 /* *** TODO *** Defined select_rx_antenna twice?
480 wbxng_base_rx::select_rx_antenna(int which_antenna)
483 Specify which antenna port to use for reception.
484 @param which_antenna: either 'TX/RX' or 'RX2'
487 if(which_antenna == 0) {
488 usrp()->write_io(d_which, 0,RX2_RX1N);
490 else if(which_antenna == 1) {
491 usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N);
495 // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n");
502 wbxng_base_rx::select_rx_antenna(const std::string &which_antenna)
505 Specify which antenna port to use for reception.
506 @param which_antenna: either 'TX/RX' or 'RX2'
510 if(which_antenna == "TX/RX") {
511 usrp()->write_io(d_which, 0, RX2_RX1N);
513 else if(which_antenna == "RX2") {
514 usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N);
517 // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n");
525 wbxng_base_rx::set_gain(float gain)
530 @param gain: gain in decibels
536 gain = std::max(gain_min(), std::min(gain, gain_max()));
538 float pga_gain, agc_gain;
539 float V_maxgain, V_mingain, V_fullscale, dac_value;
541 float maxgain = gain_max() - usrp()->pga_max();
542 float mingain = gain_min();
544 pga_gain = gain-maxgain;
545 assert(pga_gain <= usrp()->pga_max());
556 dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale;
558 assert(dac_value>=0 && dac_value<4096);
560 return (usrp()->write_aux_dac(d_which, 0, int(dac_value))
561 && _set_pga(int(pga_gain)));
566 // ----------------------------------------------------------------
568 db_wbxng_tx::db_wbxng_tx(usrp_basic_sptr usrp, int which)
569 : wbxng_base_tx(usrp, which)
573 db_wbxng_tx::~db_wbxng_tx()
579 db_wbxng_tx::_compute_regs(double freq, int &retR, int &retcontrol,
580 int &retN, double &retfreq)
582 return d_common->_compute_regs(_refclk_freq(), freq, retR,
583 retcontrol, retN, retfreq);
588 db_wbxng_rx::db_wbxng_rx(usrp_basic_sptr usrp, int which)
589 : wbxng_base_rx(usrp, which)
591 set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
594 db_wbxng_rx::~db_wbxng_rx()
599 db_wbxng_rx::gain_min()
601 return usrp()->pga_min();
605 db_wbxng_rx::gain_max()
607 return usrp()->pga_max()+70;
611 db_wbxng_rx::gain_db_per_step()
618 db_wbxng_rx::i_and_q_swapped()
625 db_wbxng_rx::_compute_regs(double freq, int &retR, int &retcontrol,
626 int &retN, double &retfreq)
628 return d_common->_compute_regs(_refclk_freq(), freq, retR,
629 retcontrol, retN, retfreq);