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 RXBB_EN (1 << 4)
33 #define TXMOD_EN (1 << 4)
34 #define PLL_CE (1 << 3)
35 #define PLL_PDBRF (1 << 2)
36 #define PLL_MUXOUT (1 << 1)
37 #define PLL_LOCK_DETECT (1 << 0)
39 wbxng_base::wbxng_base(usrp_basic_sptr _usrp, int which, int _power_on)
40 : db_base(_usrp, which), d_power_on(_power_on)
43 @param usrp: instance of usrp.source_c
44 @param which: which side: 0 or 1 corresponding to side A or B respectively
48 usrp()->_write_oe(d_which, 0, 0xffff); // turn off all outputs
51 d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0;
53 _enable_refclk(false); // disable refclk
58 wbxng_base::~wbxng_base()
64 wbxng_base::_write_all(int R, int control, int N)
67 Write R counter latch, control latch and N counter latch to VCO.
69 Adds 10ms delay between writing control and N if this is first call.
70 This is the required power-up sequence.
72 @param R: 24-bit R counter latch
74 @param control: 24-bit control latch
76 @param N: 24-bit N counter latch
85 _write_control(control);
96 wbxng_base::_write_control(int control)
98 //_write_it((control & ~0x3) | 0);
102 wbxng_base::_write_R(int R)
104 //_write_it((R & ~0x3) | 1);
108 wbxng_base::_write_N(int N)
110 //_write_it((N & ~0x3) | 2);
114 wbxng_base::_write_it(int v)
117 s[0] = (char)((v >> 16) & 0xff);
118 s[1] = (char)((v >> 8) & 0xff);
119 s[2] = (char)(v & 0xff);
120 std::string str(s, 3);
121 //usrp()->_write_spi(0, d_spi_enable, d_spi_format, str);
125 wbxng_base::_lock_detect()
128 @returns: the value of the VCO/PLL lock detect bit.
132 if(d_common->_get_locked()){
135 else { // Give it a second chance
138 // FIXME: make portable sleep
141 t.tv_nsec = 100000000;
144 if(usrp()->read_io(d_which) & PLL_LOCK_DETECT) {
153 throw std::runtime_error("_lock_detect called from wbxng_base\n");
158 wbxng_base::_compute_regs(double freq, int &retR, int &retcontrol,
159 int &retN, double &retfreq)
162 Determine values of R, control, and N registers, along with actual freq.
164 @param freq: target frequency in Hz
166 @returns: (R, control, N, actual_freq)
167 @rtype: tuple(int, int, int, float)
169 Override this in derived classes.
172 //raise NotImplementedError;
173 throw std::runtime_error("_compute_regs called from wbxng_base\n");
178 wbxng_base::_compute_control_reg()
180 throw std::runtime_error("_compute_control_reg called from wbxng_base\n");
181 //return d_common->_compute_control_reg();
185 wbxng_base::_refclk_divisor()
187 throw std::runtime_error("_refclk_divisor called from wbxng_base\n");
188 //return d_common->_refclk_divisor();
192 wbxng_base::_refclk_freq()
194 throw std::runtime_error("_refclk_divisor called from wbxng_base\n");
195 // *** TODO *** Magic Number 64e6?
196 //return 64e6/_refclk_divisor();
200 wbxng_base::set_freq(double freq)
203 @returns (ok, actual_baseband_freq) where:
204 ok is True or False and indicates success or failure,
205 actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
208 freq_t int_freq = freq_t(freq);
209 bool ok = d_common->_set_freq(int_freq*2);
210 double freq_result = (double) d_common->_get_freq()/2.0;
211 struct freq_result_t args = {ok, freq_result};
213 /* Wait before reading Lock Detect*/
216 t.tv_nsec = 10000000;
219 fprintf(stderr,"Setting WBXNG frequency, requested %d, obtained %f, lock_detect %d\n",
220 int_freq, freq_result, _lock_detect());
222 // Offsetting the LO helps get the Tx carrier leakage out of the way.
223 // This also ensures that on Rx, we're not getting hosed by the
224 // FPGA's DC removal loop's time constant. We were seeing a
225 // problem when running with discontinuous transmission.
226 // Offsetting the LO made the problem go away.
227 //freq += d_lo_offset;
230 //double actual_freq;
231 //_compute_regs(freq, R, control, N, actual_freq);
237 //_write_all(R, control, N);
238 //args.ok = _lock_detect();
239 //args.baseband_freq = actual_freq;
244 wbxng_base::_set_pga(float pga_gain)
248 usrp()->set_pga(0, pga_gain);
249 usrp()->set_pga(1, pga_gain);
252 usrp()->set_pga(2, pga_gain);
253 usrp()->set_pga(3, pga_gain);
260 wbxng_base::is_quadrature()
263 Return True if this board requires both I & Q analog channels.
265 This bit of info is useful when setting up the USRP Rx mux register.
271 wbxng_base::freq_min()
273 return (double) d_common->_get_min_freq()/2.0;
277 wbxng_base::freq_max()
279 return (double) d_common->_get_max_freq()/2.0;
282 // ----------------------------------------------------------------
284 wbxng_base_tx::wbxng_base_tx(usrp_basic_sptr _usrp, int which, int _power_on)
285 : wbxng_base(_usrp, which, _power_on)
288 @param usrp: instance of usrp.sink_c
289 @param which: 0 or 1 corresponding to side TX_A or TX_B respectively.
293 d_spi_enable = SPI_ENABLE_TX_A;
296 d_spi_enable = SPI_ENABLE_TX_B;
299 d_common = new adf4350(_usrp, d_which, d_spi_enable);
301 // power up the transmit side, but don't enable the mixer
302 usrp()->_write_oe(d_which,(RX_TXN|TXMOD_EN|ENABLE_33|ENABLE_5), (RX_TXN|TXMOD_EN|ENABLE_33|ENABLE_5));
303 usrp()->write_io(d_which, (power_on()|RX_TXN|TXMOD_EN|ENABLE_33|ENABLE_5), (RX_TXN|TXMOD_EN|ENABLE_33|ENABLE_5));
304 fprintf(stderr,"Setting WBXNG TXMOD on");
305 //set_lo_offset(4e6);
307 //set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
310 wbxng_base_tx::~wbxng_base_tx()
317 wbxng_base_tx::shutdown()
319 // fprintf(stderr, "wbxng_base_tx::shutdown d_is_shutdown = %d\n", d_is_shutdown);
322 d_is_shutdown = true;
323 // do whatever there is to do to shutdown
325 // Power down and leave the T/R switch in the R position
326 usrp()->write_io(d_which, (power_off()|RX_TXN), (RX_TXN|ENABLE_33|ENABLE_5));
328 // Power down VCO/PLL
329 d_common->_enable(false);
332 _write_control(_compute_control_reg());
334 _enable_refclk(false); // turn off refclk
340 wbxng_base_tx::set_auto_tr(bool on)
344 ok &= set_atr_mask (RX_TXN | ENABLE_33 | ENABLE_5);
345 ok &= set_atr_txval(0 | ENABLE_33 | ENABLE_5);
346 ok &= set_atr_rxval(RX_TXN | 0);
349 ok &= set_atr_mask (0);
350 ok &= set_atr_txval(0);
351 ok &= set_atr_rxval(0);
357 wbxng_base_tx::set_enable(bool on)
360 Enable transmitter if on is true
364 int mask = RX_TXN | ENABLE_5 | ENABLE_33;
366 v = ENABLE_5 | ENABLE_33;
371 return usrp()->write_io(d_which, v, mask);
375 wbxng_base_tx::gain_min()
377 return usrp()->pga_max();
381 wbxng_base_tx::gain_max()
383 return usrp()->pga_max();
387 wbxng_base_tx::gain_db_per_step()
393 wbxng_base_tx::set_gain(float gain)
398 @param gain: gain in decibels
401 return _set_pga(usrp()->pga_max());
405 /**************************************************************************/
408 wbxng_base_rx::wbxng_base_rx(usrp_basic_sptr _usrp, int which, int _power_on)
409 : wbxng_base(_usrp, which, _power_on)
412 @param usrp: instance of usrp.source_c
413 @param which: 0 or 1 corresponding to side RX_A or RX_B respectively.
417 d_spi_enable = SPI_ENABLE_RX_A;
420 d_spi_enable = SPI_ENABLE_RX_B;
423 d_common = new adf4350(_usrp, d_which, d_spi_enable);
425 usrp()->_write_oe(d_which, (RX2_RX1N|RXBB_EN|ENABLE_33|ENABLE_5), (RX2_RX1N|RXBB_EN|ENABLE_33|ENABLE_5));
426 usrp()->write_io(d_which, (power_on()|RX2_RX1N|RXBB_EN|ENABLE_33|ENABLE_5), (RX2_RX1N|RXBB_EN|ENABLE_33|ENABLE_5));
427 fprintf(stderr,"Setting WBXNG RXBB on");
429 // set up for RX on TX/RX port
430 select_rx_antenna("TX/RX");
432 bypass_adc_buffers(true);
439 wbxng_base_rx::~wbxng_base_rx()
445 wbxng_base_rx::shutdown()
447 // fprintf(stderr, "wbxng_base_rx::shutdown d_is_shutdown = %d\n", d_is_shutdown);
450 d_is_shutdown = true;
451 // do whatever there is to do to shutdown
454 usrp()->common_write_io(C_RX, d_which, power_off(), (ENABLE_33|ENABLE_5));
456 // Power down VCO/PLL
457 d_common->_enable(false);
459 // fprintf(stderr, "wbxng_base_rx::shutdown before _write_control\n");
460 //_write_control(_compute_control_reg());
462 // fprintf(stderr, "wbxng_base_rx::shutdown before _enable_refclk\n");
463 _enable_refclk(false); // turn off refclk
465 // fprintf(stderr, "wbxng_base_rx::shutdown before set_auto_tr\n");
468 // fprintf(stderr, "wbxng_base_rx::shutdown after set_auto_tr\n");
473 wbxng_base_rx::set_auto_tr(bool on)
477 ok &= set_atr_mask (ENABLE_33|ENABLE_5);
478 ok &= set_atr_txval( 0);
479 ok &= set_atr_rxval(ENABLE_33|ENABLE_5);
482 ok &= set_atr_mask (0);
483 ok &= set_atr_txval(0);
484 ok &= set_atr_rxval(0);
490 wbxng_base_rx::select_rx_antenna(int which_antenna)
493 Specify which antenna port to use for reception.
494 @param which_antenna: either 'TX/RX' or 'RX2'
497 if(which_antenna == 0) {
498 usrp()->write_io(d_which, 0,RX2_RX1N);
500 else if(which_antenna == 1) {
501 usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N);
505 // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n");
511 wbxng_base_rx::select_rx_antenna(const std::string &which_antenna)
514 Specify which antenna port to use for reception.
515 @param which_antenna: either 'TX/RX' or 'RX2'
519 if(which_antenna == "TX/RX") {
520 usrp()->write_io(d_which, 0, RX2_RX1N);
522 else if(which_antenna == "RX2") {
523 usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N);
526 // throw std::invalid_argument("which_antenna must be either 'TX/RX' or 'RX2'\n");
534 wbxng_base_rx::set_gain(float gain)
539 @param gain: gain in decibels
545 gain = std::max(gain_min(), std::min(gain, gain_max()));
547 float pga_gain, agc_gain;
548 float V_maxgain, V_mingain, V_fullscale, dac_value;
550 float maxgain = gain_max() - usrp()->pga_max();
551 float mingain = gain_min();
553 pga_gain = gain-maxgain;
554 assert(pga_gain <= usrp()->pga_max());
565 dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale;
567 assert(dac_value>=0 && dac_value<4096);
569 return (usrp()->write_aux_dac(d_which, 0, int(dac_value))
570 && _set_pga(int(pga_gain)));
575 // ----------------------------------------------------------------
577 db_wbxng_tx::db_wbxng_tx(usrp_basic_sptr usrp, int which)
578 : wbxng_base_tx(usrp, which)
582 db_wbxng_tx::~db_wbxng_tx()
588 db_wbxng_tx::_compute_regs(double freq, int &retR, int &retcontrol,
589 int &retN, double &retfreq)
591 return d_common->_compute_regs(_refclk_freq(), freq, retR,
592 retcontrol, retN, retfreq);
597 db_wbxng_rx::db_wbxng_rx(usrp_basic_sptr usrp, int which)
598 : wbxng_base_rx(usrp, which)
600 set_gain((gain_min() + gain_max()) / 2.0); // initialize gain
603 db_wbxng_rx::~db_wbxng_rx()
608 db_wbxng_rx::gain_min()
610 return usrp()->pga_min();
614 db_wbxng_rx::gain_max()
616 return usrp()->pga_max()+70;
620 db_wbxng_rx::gain_db_per_step()
627 db_wbxng_rx::i_and_q_swapped()
634 db_wbxng_rx::_compute_regs(double freq, int &retR, int &retcontrol,
635 int &retN, double &retfreq)
637 return d_common->_compute_regs(_refclk_freq(), freq, retR,
638 retcontrol, retN, retfreq);