Fix WBX tuning to allow DDC use in reaching 50MHz
[debian/gnuradio] / usrp / host / lib / db_wbxng.cc
1 //
2 // Copyright 2008,2009 Free Software Foundation, Inc.
3 //
4 // This file is part of GNU Radio
5 //
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)
9 // any later version.
10 //
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.
15 //
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.
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <usrp/db_wbxng.h>
26 #include "db_wbxng_adf4350.h"
27 #include <db_base_impl.h>
28 #include <stdio.h>
29
30 // d'board i/o pin defs
31 // Tx and Rx have shared defs, but different i/o regs
32 #define ENABLE_5        (1 << 7)         // enables 5.0V power supply
33 #define ENABLE_33       (1 << 6)         // enables 3.3V supply
34 //#define RX_TXN          (1 << 15)         // Tx only: T/R antenna switch for TX/RX port
35 //#define RX2_RX1N        (1 << 15)         // Rx only: antenna switch between RX2 and TX/RX port
36 #define RX_TXN          ((1 << 5)|(1 << 15))         // Tx only: T/R antenna switch for TX/RX port
37 #define RX2_RX1N        ((1 << 5)|(1 << 15))         // Rx only: antenna switch between RX2 and TX/RX port
38 #define RXBB_EN         (1 << 4)
39 #define TXMOD_EN        (1 << 4)
40 #define PLL_CE          (1 << 3)
41 #define PLL_PDBRF       (1 << 2)
42 #define PLL_MUXOUT      (1 << 1)
43 #define PLL_LOCK_DETECT (1 << 0)
44
45 // RX Attenuator constants
46 #define ATTN_SHIFT      8
47 #define ATTN_MASK       (63 << ATTN_SHIFT)
48
49 wbxng_base::wbxng_base(usrp_basic_sptr _usrp, int which, int _power_on)
50   : db_base(_usrp, which), d_power_on(_power_on)
51 {
52   /*
53     @param usrp: instance of usrp.source_c
54     @param which: which side: 0 or 1 corresponding to side A or B respectively
55     @type which: int
56   */
57
58   usrp()->_write_oe(d_which, 0, 0xffff);   // turn off all outputs
59
60   d_first = true;
61   d_spi_format = SPI_FMT_MSB | SPI_FMT_HDR_0;
62
63   _enable_refclk(false);                // disable refclk
64
65   set_auto_tr(false);
66 }
67
68 wbxng_base::~wbxng_base()
69 {
70   if (d_common)
71     delete d_common;
72 }
73
74 struct freq_result_t
75 wbxng_base::set_freq(double freq)
76 {
77   /*
78     @returns (ok, actual_baseband_freq) where:
79     ok is True or False and indicates success or failure,
80     actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
81   */
82
83   // clamp freq
84   freq_t int_freq = freq_t(std::max(freq_min(), std::min(freq, freq_max())));
85
86   bool ok = d_common->_set_freq(int_freq*2);
87   double freq_result = (double) d_common->_get_freq()/2.0;
88   struct freq_result_t args = {ok, freq_result};
89
90   /* Wait before reading Lock Detect*/
91   timespec t;
92   t.tv_sec = 0;
93   t.tv_nsec = 10000000;
94   nanosleep(&t, NULL);
95
96   //fprintf(stderr,"Setting WBXNG frequency, requested %d, obtained %f, lock_detect %d\n",
97   //        int_freq, freq_result, d_common->_get_locked());
98
99   // FIXME
100   // Offsetting the LO helps get the Tx carrier leakage out of the way.
101   // This also ensures that on Rx, we're not getting hosed by the
102   // FPGA's DC removal loop's time constant.  We were seeing a
103   // problem when running with discontinuous transmission.
104   // Offsetting the LO made the problem go away.
105   //freq += d_lo_offset;
106
107   return args;
108 }
109
110 bool
111 wbxng_base::_set_pga(float pga_gain)
112 {
113   if(d_which == 0) {
114     usrp()->set_pga(0, pga_gain);
115     usrp()->set_pga(1, pga_gain);
116   }
117   else {
118     usrp()->set_pga(2, pga_gain);
119     usrp()->set_pga(3, pga_gain);
120   }
121   return true;
122 }
123
124 bool
125 wbxng_base::is_quadrature()
126 {
127   /*
128     Return True if this board requires both I & Q analog channels.
129
130     This bit of info is useful when setting up the USRP Rx mux register.
131   */
132   return true;
133 }
134
135 double
136 wbxng_base::freq_min()
137 {
138   return (double) d_common->_get_min_freq()/2.0;
139 }
140
141 double
142 wbxng_base::freq_max()
143 {
144   return (double) d_common->_get_max_freq()/2.0;
145 }
146
147 // ----------------------------------------------------------------
148
149 wbxng_base_tx::wbxng_base_tx(usrp_basic_sptr _usrp, int which, int _power_on)
150   : wbxng_base(_usrp, which, _power_on)
151 {
152   /*
153     @param usrp: instance of usrp.sink_c
154     @param which: 0 or 1 corresponding to side TX_A or TX_B respectively.
155   */
156
157   if(which == 0) {
158     d_spi_enable = SPI_ENABLE_TX_A;
159   }
160   else {
161     d_spi_enable = SPI_ENABLE_TX_B;
162   }
163
164   d_common = new adf4350(_usrp, d_which, d_spi_enable);
165
166   // power up the transmit side, but don't enable the mixer
167   usrp()->_write_oe(d_which,(RX_TXN|TXMOD_EN|ENABLE_33|ENABLE_5), (RX_TXN|TXMOD_EN|ENABLE_33|ENABLE_5));
168   usrp()->write_io(d_which, (power_on()|RX_TXN|ENABLE_33|ENABLE_5), (RX_TXN|ENABLE_33|ENABLE_5));
169   //set_lo_offset(4e6);
170   
171   // Disable VCO/PLL
172   d_common->_enable(true);
173
174   set_gain((gain_min() + gain_max()) / 2.0);  // initialize gain
175 }
176
177 wbxng_base_tx::~wbxng_base_tx()
178 {
179   shutdown();
180 }
181
182
183 void
184 wbxng_base_tx::shutdown()
185 {
186   // fprintf(stderr, "wbxng_base_tx::shutdown  d_is_shutdown = %d\n", d_is_shutdown);
187
188   if (!d_is_shutdown){
189     d_is_shutdown = true;
190     // do whatever there is to do to shutdown
191
192     // Disable VCO/PLL
193     d_common->_enable(false);
194
195     // Power down and leave the T/R switch in the R position
196     usrp()->write_io(d_which, (power_off()|RX_TXN), (RX_TXN|ENABLE_33|ENABLE_5));
197
198
199     /*
200     _write_control(_compute_control_reg());
201     */
202     _enable_refclk(false);                       // turn off refclk
203     set_auto_tr(false);
204   }
205 }
206
207 bool
208 wbxng_base_tx::set_auto_tr(bool on)
209 {
210   bool ok = true;
211   if(on) {
212     ok &= set_atr_mask (RX_TXN | TXMOD_EN);
213     ok &= set_atr_txval(0      | TXMOD_EN);
214     ok &= set_atr_rxval(RX_TXN);
215   }
216   else {
217     ok &= set_atr_mask (0);
218     ok &= set_atr_txval(0);
219     ok &= set_atr_rxval(0);
220   }
221   return ok;
222 }
223
224 bool
225 wbxng_base_tx::set_enable(bool on)
226 {
227   /*
228     Enable transmitter if on is true
229   */
230
231   int v;
232   int mask = RX_TXN | TXMOD_EN;
233   if(on) {
234     v = TXMOD_EN;
235     // Enable VCO/PLL
236     //d_common->_enable(true);
237   }
238   else {
239     v = RX_TXN;
240     // Disable VCO/PLL
241     //d_common->_enable(false);
242   }
243   return usrp()->write_io(d_which, v, mask);
244 }
245
246 float
247 wbxng_base_tx::gain_min()
248 {
249   return 0.0;
250 }
251
252 float
253 wbxng_base_tx::gain_max()
254 {
255   return 25.0;
256 }
257
258 float
259 wbxng_base_tx::gain_db_per_step()
260 {
261   return gain_max()/(1+(1.4-0.5)*4096/3.3);
262 }
263
264 bool
265 wbxng_base_tx::set_gain(float gain)
266 {
267   /*
268     Set the gain.
269
270     @param gain:  gain in decibels
271     @returns True/False
272   */
273
274   // clamp gain
275   gain = std::max(gain_min(), std::min(gain, gain_max()));
276
277   float pga_gain, agc_gain;
278   float V_maxgain, V_mingain, V_fullscale, dac_value;
279
280   float maxgain = gain_max();
281   float mingain = gain_min();
282   pga_gain = 0;
283   agc_gain = gain;
284
285   V_maxgain = 0.5;
286   V_mingain = 1.4;
287   V_fullscale = 3.3;
288   dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale;
289
290   //fprintf(stderr, "TXGAIN: %f dB, Dac Code: %d, Voltage: %f\n", gain, int(dac_value), float((dac_value/4096.0)*V_fullscale));
291   assert(dac_value>=0 && dac_value<4096);
292
293   return (usrp()->write_aux_dac(d_which, 0, int(dac_value))
294      && _set_pga(usrp()->pga_max()));
295
296 }
297
298
299 /**************************************************************************/
300
301
302 wbxng_base_rx::wbxng_base_rx(usrp_basic_sptr _usrp, int which, int _power_on)
303   : wbxng_base(_usrp, which, _power_on)
304 {
305   /*
306     @param usrp: instance of usrp.source_c
307     @param which: 0 or 1 corresponding to side RX_A or RX_B respectively.
308   */
309
310   if(which == 0) {
311     d_spi_enable = SPI_ENABLE_RX_A;
312   }
313   else {
314     d_spi_enable = SPI_ENABLE_RX_B;
315   }
316
317   d_common = new adf4350(_usrp, d_which, d_spi_enable);
318   
319   // Disable VCO/PLL
320   d_common->_enable(true);
321
322   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));
323   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));
324   //fprintf(stderr,"Setting WBXNG RXBB on");
325
326   // set up for RX on TX/RX port
327   select_rx_antenna("TX/RX");
328
329   bypass_adc_buffers(true);
330
331   /*
332   set_lo_offset(-4e6);
333   */
334 }
335
336 wbxng_base_rx::~wbxng_base_rx()
337 {
338   shutdown();
339 }
340
341 void
342 wbxng_base_rx::shutdown()
343 {
344   // fprintf(stderr, "wbxng_base_rx::shutdown  d_is_shutdown = %d\n", d_is_shutdown);
345
346   if (!d_is_shutdown){
347     d_is_shutdown = true;
348     // do whatever there is to do to shutdown
349
350     // Power down VCO/PLL
351     d_common->_enable(false);
352
353     // fprintf(stderr, "wbxng_base_rx::shutdown  before _write_control\n");
354     //_write_control(_compute_control_reg());
355
356     // fprintf(stderr, "wbxng_base_rx::shutdown  before _enable_refclk\n");
357     _enable_refclk(false);                       // turn off refclk
358
359     // fprintf(stderr, "wbxng_base_rx::shutdown  before set_auto_tr\n");
360     set_auto_tr(false);
361
362     // Power down
363     usrp()->write_io(d_which, power_off(), (RX2_RX1N|RXBB_EN|ATTN_MASK|ENABLE_33|ENABLE_5));
364
365     // fprintf(stderr, "wbxng_base_rx::shutdown  after set_auto_tr\n");
366   }
367 }
368
369 bool
370 wbxng_base_rx::set_auto_tr(bool on)
371 {
372   bool ok = true;
373   if(on) {
374     ok &= set_atr_mask (RXBB_EN|RX2_RX1N);
375     ok &= set_atr_txval(      0|RX2_RX1N);
376     ok &= set_atr_rxval(RXBB_EN|       0);
377   }
378   else {
379     ok &= set_atr_mask (0);
380     ok &= set_atr_txval(0);
381     ok &= set_atr_rxval(0);
382   }
383   return true;
384 }
385
386 bool
387 wbxng_base_rx::select_rx_antenna(int which_antenna)
388 {
389   /*
390     Specify which antenna port to use for reception.
391     @param which_antenna: either 'TX/RX' or 'RX2'
392   */
393
394   if(which_antenna == 0) {
395     usrp()->write_io(d_which, 0,RX2_RX1N);
396   }
397   else if(which_antenna == 1) {
398     usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N);
399   }
400   else {
401     return false;
402   }
403   return true;
404 }
405
406 bool
407 wbxng_base_rx::select_rx_antenna(const std::string &which_antenna)
408 {
409   /*
410     Specify which antenna port to use for reception.
411     @param which_antenna: either 'TX/RX' or 'RX2'
412   */
413
414
415   if(which_antenna == "TX/RX") {
416     usrp()->write_io(d_which, 0, RX2_RX1N);
417   }
418   else if(which_antenna == "RX2") {
419     usrp()->write_io(d_which, RX2_RX1N, RX2_RX1N);
420   }
421   else {
422     return false;
423   }
424
425   return true;
426 }
427
428 bool
429 wbxng_base_rx::set_gain(float gain)
430 {
431   /*
432     Set the gain.
433
434     @param gain:  gain in decibels
435     @returns True/False
436   */
437
438   // clamp gain
439   gain = std::max(gain_min(), std::min(gain, gain_max()));
440
441   float pga_gain, agc_gain;
442
443   float maxgain = gain_max() - usrp()->pga_max();
444   float mingain = gain_min();
445   if(gain > maxgain) {
446     pga_gain = gain-maxgain;
447     assert(pga_gain <= usrp()->pga_max());
448     agc_gain = maxgain;
449   }
450   else {
451     pga_gain = 0;
452     agc_gain = gain;
453   }
454
455   return _set_attn(maxgain-agc_gain) && _set_pga(int(pga_gain));
456 }
457
458 bool
459 wbxng_base_rx::_set_attn(float attn)
460 {
461   int attn_code = int(floor(attn/0.5));
462   unsigned int iobits = (~attn_code) << ATTN_SHIFT;
463   //fprintf(stderr, "Attenuation: %f dB, Code: %d, IO Bits %x, Mask: %x \n", attn, attn_code, iobits & ATTN_MASK, ATTN_MASK);
464   return usrp()->write_io(d_which, iobits, ATTN_MASK);
465 }
466
467 // ----------------------------------------------------------------
468
469 db_wbxng_tx::db_wbxng_tx(usrp_basic_sptr usrp, int which)
470   : wbxng_base_tx(usrp, which)
471 {
472 }
473
474 db_wbxng_tx::~db_wbxng_tx()
475 {
476 }
477
478 db_wbxng_rx::db_wbxng_rx(usrp_basic_sptr usrp, int which)
479   : wbxng_base_rx(usrp, which)
480 {
481   set_gain((gain_min() + gain_max()) / 2.0);  // initialize gain
482 }
483
484 db_wbxng_rx::~db_wbxng_rx()
485 {
486 }
487
488 float
489 db_wbxng_rx::gain_min()
490 {
491   return usrp()->pga_min();
492 }
493
494 float
495 db_wbxng_rx::gain_max()
496 {
497   return usrp()->pga_max()+30.5;
498 }
499
500 float
501 db_wbxng_rx::gain_db_per_step()
502 {
503   return 0.05;
504 }
505
506
507 bool
508 db_wbxng_rx::i_and_q_swapped()
509 {
510   return false;
511 }