Merged eb/gcell-wip2 rev 10130:10152 into trunk.
[debian/gnuradio] / gr-usrp / src / db_xcvr2450.py
1 #
2 # Copyright 2007 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 version 2, 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
22 from gnuradio import usrp1, gru, eng_notation
23 import time, math, weakref
24
25 from usrpm import usrp_dbid
26 import db_base
27 import db_instantiator
28 from usrpm.usrp_fpga_regs import *
29
30 # Convenience function
31 n2s = eng_notation.num_to_str
32
33 # d'board i/o pin defs
34
35 # TX IO Pins
36 HB_PA_OFF = (1 << 15)       # 5GHz PA, 1 = off, 0 = on
37 LB_PA_OFF = (1 << 14)       # 2.4GHz PA, 1 = off, 0 = on
38 ANTSEL_TX1_RX2 = (1 << 13)  # 1 = Ant 1 to TX, Ant 2 to RX
39 ANTSEL_TX2_RX1 = (1 << 12)    # 1 = Ant 2 to TX, Ant 1 to RX
40 TX_EN = (1 << 11)           # 1 = TX on, 0 = TX off
41 AD9515DIV = (1 << 4)        # 1 = Div  by 3, 0 = Div by 2
42
43 TX_OE_MASK = HB_PA_OFF|LB_PA_OFF|ANTSEL_TX1_RX2|ANTSEL_TX2_RX1|TX_EN|AD9515DIV
44 TX_SAFE_IO = HB_PA_OFF|LB_PA_OFF|ANTSEL_TX1_RX2|AD9515DIV
45
46 # RX IO Pins
47 LOCKDET = (1 << 15)         # This is an INPUT!!!
48 EN = (1 << 14)
49 RX_EN = (1 << 13)           # 1 = RX on, 0 = RX off
50 RX_HP = (1 << 12)
51 B1 = (1 << 11)
52 B2 = (1 << 10)
53 B3 = (1 << 9)
54 B4 = (1 << 8)
55 B5 = (1 << 7)
56 B6 = (1 << 6)
57 B7 = (1 << 5)
58 RX_OE_MASK = EN|RX_EN|RX_HP|B1|B2|B3|B4|B5|B6|B7
59 RX_SAFE_IO = EN
60
61
62 # ------------------------------------------------------------------------
63 # A few comments about the XCVR2450:
64 #
65 # It is half-duplex.  I.e., transmit and receive are mutually exclusive.
66 # There is a single LO for both the Tx and Rx sides.
67 # For our purposes the board is always either receiving or transmitting.
68 #
69 # Each board is uniquely identified by the *USRP hardware* instance and side
70 # This dictionary holds a weak reference to existing board controller so it
71 # can be created or retrieved as needed.
72
73 _xcvr2450_inst = weakref.WeakValueDictionary()
74 def _get_or_make_xcvr2450(usrp, which):
75     key = (usrp.serial_number(), which)
76     if not _xcvr2450_inst.has_key(key):
77         print "Creating new xcvr2450 instance"
78         inst = xcvr2450(usrp, which)
79         _xcvr2450_inst[key] = inst
80     else:
81         print "Using existing xcvr2450 instance"
82         inst = _xcvr2450_inst[key]
83     return inst
84
85 # ------------------------------------------------------------------------
86 # Common, shared object for xcvr2450 board.  Transmit and receive classes
87 # operate on an instance of this; one instance is created per physical
88 # daughterboard.
89
90 class xcvr2450(object):
91     def __init__(self, usrp, which):
92         print "xcvr2450: __init__ with %s: %d" % (usrp.serial_number(), which)
93         self.u = usrp
94         self.which = which
95
96         # Use MSB with no header
97         self.spi_format = usrp1.SPI_FMT_MSB | usrp1.SPI_FMT_HDR_0
98         self.spi_enable = (usrp1.SPI_ENABLE_RX_A, usrp1.SPI_ENABLE_RX_B)[which]
99
100         # Sane defaults
101         self.mimo = 1              # 0 = OFF, 1 = ON
102         self.int_div = 192         # 128 = min, 255 = max
103         self.frac_div = 0          # 0 = min, 65535 = max
104         self.highband = 0          # 0 = freq <= 5.4e9, 1 = freq > 5.4e9
105         self.five_gig = 0          # 0 = freq <= 3.e9, 1 = freq > 3e9
106         self.cp_current = 0        # 0 = 2mA, 1 = 4mA
107         self.ref_div = 4           # 1 to 7
108         self.rssi_hbw = 0          # 0 = 2 MHz, 1 = 6 MHz
109         self.txlpf_bw = 1          # 1 = 12 MHz, 2 = 18 MHz, 3 = 24 MHz
110         self.rxlpf_bw = 1          # 0 = 7.5 MHz, 1 = 9.5 MHz, 2 = 14 MHz, 3 = 18 MHz
111         self.rxlpf_fine = 2        # 0 = 90%, 1 = 95%, 2 = 100%, 3 = 105%, 4 = 110%
112         self.rxvga_ser = 1         # 0 = RXVGA controlled by B7:1, 1 = controlled serially
113         self.rssi_range = 1        # 0 = low range (datasheet typo), 1 = high range (0.5V - 2.0V) 
114         self.rssi_mode = 1         # 0 = enable follows RXHP, 1 = enabled
115         self.rssi_mux = 0          # 0 = RSSI, 1 = TEMP
116         self.rx_hp_pin = 0         # 0 = Fc set by rx_hpf, 1 = 600 KHz
117         self.rx_hpf = 0            # 0 = 100Hz, 1 = 30KHz
118         self.rx_ant = 0            # 0 = Ant. #1, 1 = Ant. #2
119         self.tx_ant = 0            # 0 = Ant. #1, 1 = Ant. #2
120         self.txvga_ser = 1         # 0 = TXVGA controlled by B6:1, 1 = controlled serially
121         self.tx_driver_lin = 2     # 0 = 50% (worst linearity), 1 = 63%, 2 = 78%, 3 = 100% (best lin)
122         self.tx_vga_lin = 2        # 0 = 50% (worst linearity), 1 = 63%, 2 = 78%, 3 = 100% (best lin)
123         self.tx_upconv_lin = 2     # 0 = 50% (worst linearity), 1 = 63%, 2 = 78%, 3 = 100% (best lin)
124         self.tx_bb_gain = 3        # 0 = maxgain-5dB, 1 = max-3dB, 2 = max-1.5dB, 3 = max
125         self.pabias_delay = 15     # 0 = 0, 15 = 7uS
126         self.pabias = 0            # 0 = 0 uA, 63 = 315uA
127         self.rx_rf_gain = 0        # 0 = 0dB, 1 = 0dB, 2 = 15dB, 3 = 30dB
128         self.rx_bb_gain = 16       # 0 = min, 31 = max (0 - 62 dB)
129
130         self.txgain = 63           # 0 = min, 63 = max
131
132         # Initialize GPIO and ATR
133         self.tx_write_io(TX_SAFE_IO, TX_OE_MASK)
134         self.tx_write_oe(TX_OE_MASK, ~0)
135         self.tx_set_atr_txval(TX_SAFE_IO)
136         self.tx_set_atr_rxval(TX_SAFE_IO)
137         self.tx_set_atr_mask(TX_OE_MASK)
138         self.rx_write_io(RX_SAFE_IO, RX_OE_MASK)
139         self.rx_write_oe(RX_OE_MASK, ~0)
140         self.rx_set_atr_rxval(RX_SAFE_IO)
141         self.rx_set_atr_txval(RX_SAFE_IO)
142         self.rx_set_atr_mask(RX_OE_MASK)
143         
144         # Initialize chipset
145         # TODO: perform reset sequence to ensure power up defaults
146         self.set_reg_standby()
147         self.set_reg_bandselpll()
148         self.set_reg_cal()
149         self.set_reg_lpf()
150         self.set_reg_rxrssi_ctrl()
151         self.set_reg_txlin_gain()
152         self.set_reg_pabias()
153         self.set_reg_rxgain()
154         self.set_reg_txgain()
155         self.set_freq(2.45e9)
156
157     def __del__(self):
158         print "xcvr2450: __del__"
159         self.tx_set_atr_txval(TX_SAFE_IO)
160         self.tx_set_atr_rxval(TX_SAFE_IO)
161         self.rx_set_atr_rxval(RX_SAFE_IO)
162         self.rx_set_atr_txval(RX_SAFE_IO)
163         
164
165     # --------------------------------------------------------------------
166     # These methods set the MAX2829 onboard registers over the SPI bus.
167     # The SPI format is 18 bits, with the four LSBs holding the register no.
168     # Thus, the shift values used here are the D0-D13 values from the data
169     # sheet, *plus* four.
170     
171     # Standby (2)
172     def set_reg_standby(self):
173         self.reg_standby = (
174             (self.mimo<<17) | 
175             (1<<16)         | 
176             (1<<6)          | 
177             (1<<5)          | 
178             (1<<4)          | 2)
179         self.send_reg(self.reg_standby)
180
181     # Integer-Divider Ratio (3)
182     def set_reg_int_divider(self):
183         self.reg_int_divider = (
184             ((self.frac_div & 0x03)<<16) | 
185              (self.int_div<<4)           | 3)
186         self.send_reg(self.reg_int_divider)
187
188     # Fractional-Divider Ratio (4)
189     def set_reg_frac_divider(self):
190         self.reg_frac_divider = ((self.frac_div & 0xfffc)<<2) | 4
191         self.send_reg(self.reg_frac_divider)
192         
193     # Band Select and PLL (5)
194     def set_reg_bandselpll(self):
195         self.reg_bandselpll = (
196             (self.mimo<<17)      |
197             (1<<16)              |
198             (1<<15)              |
199             (1<<11)              |
200             (self.highband<<10)  |
201             (self.cp_current<<9) |
202             (self.ref_div<<5)    |
203             (self.five_gig<<4)   | 5)
204         self.send_reg(self.reg_bandselpll)
205      
206
207     # Calibration (6)
208     def set_reg_cal(self):
209         # FIXME do calibration
210         self.reg_cal = (1<<14)|6
211         self.send_reg(self.reg_cal)
212
213
214     # Lowpass Filter (7)
215     def set_reg_lpf(self):
216         self.reg_lpf = (
217             (self.rssi_hbw<<15)  |
218             (self.txlpf_bw<<10)  |
219             (self.rxlpf_bw<<9)   |
220             (self.rxlpf_fine<<4) | 7)
221         self.send_reg(self.reg_lpf)
222
223
224     # Rx Control/RSSI (8)
225     def set_reg_rxrssi_ctrl(self):
226         self.reg_rxrssi_ctrl = (
227             (self.rxvga_ser<<16)  |
228             (self.rssi_range<<15) |
229             (self.rssi_mode<<14)  |
230             (self.rssi_mux<<12)   |
231             (1<<9)                |
232             (self.rx_hpf<<6)      |
233             (1<<4)                | 8)
234         self.send_reg(self.reg_rxrssi_ctrl)
235
236
237     # Tx Linearity/Baseband Gain (9)
238     def set_reg_txlin_gain(self):
239         self.reg_txlin_gain = (
240             (self.txvga_ser<<14)     |
241             (self.tx_driver_lin<<12) |
242             (self.tx_vga_lin<<10)    |
243             (self.tx_upconv_lin<<6)  |
244             (self.tx_bb_gain<<4)     | 9)
245         self.send_reg(self.reg_txlin_gain)
246
247
248     # PA Bias DAC (10)
249     def set_reg_pabias(self):
250         self.reg_pabias = (
251             (self.pabias_delay<<10) |
252             (self.pabias<<4)        | 10)
253         self.send_reg(self.reg_pabias)
254
255
256     # Rx Gain (11)
257     def set_reg_rxgain(self):
258         self.reg_rxgain = (
259             (self.rx_rf_gain<<9) |
260             (self.rx_bb_gain<<4) | 11)
261         self.send_reg(self.reg_rxgain)
262
263
264     # Tx Gain (12)
265     def set_reg_txgain(self):
266         self.reg_txgain = (self.txgain<<4) | 12
267         self.send_reg(self.reg_txgain)
268
269
270     # Send register write to SPI
271     def send_reg(self, v):
272         # Send 24 bits, it keeps last 18 clocked in
273         s = ''.join((chr((v >> 16) & 0xff),
274                      chr((v >>  8) & 0xff),
275                      chr(v & 0xff)))
276         self.u._write_spi(0, self.spi_enable, self.spi_format, s)
277         #print "xcvr2450: Setting reg %d to %06X" % ((v&15), v)
278
279     # --------------------------------------------------------------------
280     # These methods control the GPIO bus.  Since the board has to access
281     # both the io_rx_* and io_tx_* pins, we define our own methods to do so.
282     # This bypasses any code in db_base.
283     #
284     # The board operates in ATR mode, always.  Thus, when the board is first
285     # initialized, it is in receive mode, until bits show up in the TX FIFO.
286     #
287     def tx_write_oe(self, value, mask):
288         return self.u._write_fpga_reg((FR_OE_0, FR_OE_2)[self.which],
289                                        gru.hexint((mask << 16) | value))
290     
291     def tx_write_io(self, value, mask):
292         return self.u._write_fpga_reg((FR_IO_0, FR_IO_2)[self.which],
293                                        gru.hexint((mask << 16) | value))
294
295     def tx_read_io(self):
296         t = self.u._read_fpga_reg((FR_RB_IO_RX_A_IO_TX_A, FR_RB_IO_RX_B_IO_TX_B)[self.which])
297         return t & 0xffff
298
299
300     def rx_write_oe(self, value, mask):
301         return self.u._write_fpga_reg((FR_OE_1, FR_OE_3)[self.which],
302                                        gru.hexint((mask << 16) | value))
303
304     def rx_write_io(self, value, mask):
305         return self.u._write_fpga_reg((FR_IO_1, FR_IO_3)[self.which],
306                                        gru.hexint((mask << 16) | value))
307
308     def rx_read_io(self):
309         t = self.u._read_fpga_reg((FR_RB_IO_RX_A_IO_TX_A, FR_RB_IO_RX_B_IO_TX_B)[self.which])
310         return (t >> 16) & 0xffff
311
312     def tx_set_atr_mask(self, v):
313         return self.u._write_fpga_reg((FR_ATR_MASK_0,FR_ATR_MASK_2)[self.which],
314                                        gru.hexint(v))
315
316     def tx_set_atr_txval(self, v):
317         return self.u._write_fpga_reg((FR_ATR_TXVAL_0,FR_ATR_TXVAL_2)[self.which],
318                                        gru.hexint(v))
319
320     def tx_set_atr_rxval(self, v):
321         return self.u._write_fpga_reg((FR_ATR_RXVAL_0,FR_ATR_RXVAL_2)[self.which],
322                                        gru.hexint(v))
323
324     def rx_set_atr_mask(self, v):
325         return self.u._write_fpga_reg((FR_ATR_MASK_1,FR_ATR_MASK_3)[self.which],
326                                        gru.hexint(v))
327
328     def rx_set_atr_txval(self, v):
329         return self.u._write_fpga_reg((FR_ATR_TXVAL_1,FR_ATR_TXVAL_3)[self.which],
330                                        gru.hexint(v))
331
332     def rx_set_atr_rxval(self, v):
333         return self.u._write_fpga_reg((FR_ATR_RXVAL_1,FR_ATR_RXVAL_3)[self.which],
334                                        gru.hexint(v))
335
336     def set_gpio(self):
337         # We calculate four values:
338         #
339         # io_rx_while_rx: what to drive onto io_rx_* when receiving
340         # io_rx_while_tx: what to drive onto io_rx_* when transmitting
341         # io_tx_while_rx: what to drive onto io_tx_* when receiving
342         # io_tx_while_tx: what to drive onto io_tx_* when transmitting
343         #
344         # B1-B7 is ignored as gain is set serially for now.
345
346         rx_hp     = (0, RX_HP)[self.rx_hp_pin]
347         tx_antsel = (ANTSEL_TX1_RX2, ANTSEL_TX2_RX1)[self.tx_ant] 
348         rx_antsel = (ANTSEL_TX1_RX2, ANTSEL_TX2_RX1)[self.rx_ant] 
349         tx_pa_sel = (HB_PA_OFF, LB_PA_OFF)[self.five_gig]
350         io_rx_while_rx = EN|rx_hp|RX_EN
351         io_rx_while_tx = EN|rx_hp
352         io_tx_while_rx = HB_PA_OFF|LB_PA_OFF|rx_antsel|AD9515DIV
353         io_tx_while_tx = tx_pa_sel|tx_antsel|TX_EN|AD9515DIV
354         self.rx_set_atr_rxval(io_rx_while_rx)
355         self.rx_set_atr_txval(io_rx_while_tx)
356         self.tx_set_atr_rxval(io_tx_while_rx)
357         self.tx_set_atr_txval(io_tx_while_tx)
358         
359         #print "GPIO: RXRX=%04X RXTX=%04X TXRX=%04X TXTX=%04X" % (
360             #io_rx_while_rx, io_rx_while_tx, io_tx_while_rx, io_tx_while_tx)
361
362     # --------------------------------------------------------------------
363     # These methods set control the high-level operating parameters.
364
365     def set_freq(self, target_freq):
366         if target_freq > 3e9:
367             self.five_gig = 1
368             self.ref_div = 1
369             self.ad9515_div = 3
370             scaler = 4.0/5.0
371         else:
372             self.five_gig = 0
373             self.ref_div = 1
374             self.ad9515_div = 3
375             scaler = 4.0/3.0;
376
377         if target_freq > 5.275e9:
378             self.highband = 1
379         else:
380             self.highband = 0
381
382         vco_freq = target_freq*scaler;
383         sys_clk = self.u.fpga_master_clock_freq()  # Usually 64e6
384         ref_clk = sys_clk / self.ad9515_div
385         
386         phdet_freq = ref_clk/self.ref_div
387         div = vco_freq/phdet_freq
388         self.int_div = int(math.floor(div))
389         self.frac_div = int((div-self.int_div)*65536.0)
390         actual_freq = phdet_freq*(self.int_div+(self.frac_div/65536.0))/scaler
391
392         #print "RF=%s VCO=%s R=%d PHD=%s DIV=%3.5f I=%3d F=%5d ACT=%s" % (
393         #    n2s(target_freq), n2s(vco_freq), self.ref_div, n2s(phdet_freq),
394         #    div, self.int_div, self.frac_div, n2s(actual_freq))
395
396         self.set_gpio()
397         self.set_reg_int_divider()
398         self.set_reg_frac_divider()
399         self.set_reg_bandselpll()
400
401         ok = self.lock_detect()
402         #if(not ok):
403         #    ok = self.lock_detect()
404         #    if ok:
405         #        print "lock detect on 2nd try %f" % (target_freq,)
406
407         if(not ok):
408             if (target_freq > 5.275e9) and (target_freq <= 5.35e9):
409                 self.highband = 0
410                 self.set_reg_bandselpll()
411                 ok = self.lock_detect()
412                 print "swap to 0 at %f, ok %d" % (target_freq,ok)
413             if (target_freq >= 5.25e9) and (target_freq <= 5.275e9):
414                 self.highband = 1
415                 self.set_reg_bandselpll()
416                 ok = self.lock_detect()
417                 print "swap to 1 at %f, ok %d" % (target_freq,ok)
418                 
419         if(not ok):
420             print "Fail %f" % (target_freq,)
421         return (ok, actual_freq)
422
423     def lock_detect(self):
424         """
425         @returns: the value of the VCO/PLL lock detect bit.
426         @rtype: 0 or 1
427         """
428         if self.rx_read_io() & LOCKDET:
429             return True
430         else:      # Give it a second chance
431             if self.rx_read_io() & LOCKDET:
432                 return True
433             else:
434                 return False
435
436     def set_rx_gain(self, gain):
437         if gain < 0.0: gain = 0.0
438         if gain > 92.0: gain = 92.0
439         
440         # Split the gain between RF and baseband
441         # This is experimental, not prescribed
442         if gain < 31.0:
443             self.rx_rf_gain = 0                    # 0 dB RF gain
444             self.rx_bb_gain = int(gain/2.0)
445             
446         if gain >= 30.0 and gain < 60.5:
447             self.rx_rf_gain = 2                    # 15 dB RF gain
448             self.rx_bb_gain = int((gain-15.0)/2.0)
449     
450         if gain >= 60.5:
451             self.rx_rf_gain = 3                    # 30.5 dB RF gain
452             self.rx_bb_gain = int((gain-30.5)/2.0)
453     
454         self.set_reg_rxgain()
455
456     def set_tx_gain(self, gain):
457         if gain < 0.0: gain = 0.0
458         if gain > 30.0: gain = 30.0
459         self.txgain = int((gain/30.0)*63)
460         self.set_reg_txgain()
461
462 class db_xcvr2450_base(db_base.db_base):
463     """
464     Abstract base class for all xcvr2450 boards.
465
466     Derive board specific subclasses from db_xcvr2450_base_{tx,rx}
467     """
468     def __init__(self, usrp, which):
469         """
470         @param usrp: instance of usrp.source_c
471         @param which: which side: 0 or 1 corresponding to side A or B respectively
472         @type which: int
473         """
474         # sets _u  _which _tx and _slot
475         db_base.db_base.__init__(self, usrp, which)
476         self.xcvr = _get_or_make_xcvr2450(usrp, which)
477         
478     def set_freq(self, target_freq):
479         """
480         @returns (ok, actual_baseband_freq) where:
481            ok is True or False and indicates success or failure,
482            actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
483         """
484         return self.xcvr.set_freq(target_freq)
485
486     def is_quadrature(self):
487         """
488         Return True if this board requires both I & Q analog channels.
489
490         This bit of info is useful when setting up the USRP Rx mux register.
491         """
492         return True
493
494     def freq_range(self):
495         return (2.4e9, 6e9, 1e6)
496
497     def set_freq(self, target_freq):
498         return self.xcvr.set_freq(target_freq)
499
500 # ----------------------------------------------------------------
501
502 class db_xcvr2450_tx(db_xcvr2450_base):
503     def __init__(self, usrp, which):
504         """
505         @param usrp: instance of usrp.sink_c
506         @param which: 0 or 1 corresponding to side TX_A or TX_B respectively.
507         """
508         print "db_xcvr2450_tx: __init__"
509         db_xcvr2450_base.__init__(self, usrp, which)
510
511     def gain_range(self):
512         return (0, 30, (30.0/63.0))
513
514     def set_gain(self, gain):
515         return self.xcvr.set_tx_gain(gain)
516
517     def i_and_q_swapped(self):
518         return True
519
520 class db_xcvr2450_rx(db_xcvr2450_base):
521     def __init__(self, usrp, which):
522         """
523         @param usrp: instance of usrp.source_c
524         @param which: 0 or 1 corresponding to side RX_A or RX_B respectively.
525         """
526         print "db_xcvr2450_rx: __init__"
527         db_xcvr2450_base.__init__(self, usrp, which)
528
529     def gain_range(self):
530         return (0.0, 92.0, 1)
531
532     def set_gain(self, gain):
533         return self.xcvr.set_rx_gain(gain)
534         
535 #------------------------------------------------------------    
536 # hook these daughterboard classes into the auto-instantiation framework
537 db_instantiator.add(usrp_dbid.XCVR2450_TX, lambda usrp, which : (db_xcvr2450_tx(usrp, which),))
538 db_instantiator.add(usrp_dbid.XCVR2450_RX, lambda usrp, which : (db_xcvr2450_rx(usrp, which),))