summaryrefslogtreecommitdiff
path: root/gr-usrp/src/db_xcvr2450.py
diff options
context:
space:
mode:
authorjcorgan2008-01-05 04:35:41 +0000
committerjcorgan2008-01-05 04:35:41 +0000
commit93a3a8624a3b82f55042ced8232f4d9805e87448 (patch)
treecdc16a394f9783e604913373f39caf7ca0463f0d /gr-usrp/src/db_xcvr2450.py
parentce16514534e5d7ebbc4fe46e2b09a25ccc5fdafd (diff)
downloadgnuradio-93a3a8624a3b82f55042ced8232f4d9805e87448.tar.gz
gnuradio-93a3a8624a3b82f55042ced8232f4d9805e87448.tar.bz2
gnuradio-93a3a8624a3b82f55042ced8232f4d9805e87448.zip
Merged r7323:7349 from jcorgan/xcvr2450 into trunk. Ads XCVR 2450 daughterboard code. Not fully tested.
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@7352 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'gr-usrp/src/db_xcvr2450.py')
-rw-r--r--gr-usrp/src/db_xcvr2450.py810
1 files changed, 365 insertions, 445 deletions
diff --git a/gr-usrp/src/db_xcvr2450.py b/gr-usrp/src/db_xcvr2450.py
index 8c22f0d80..daf4007f2 100644
--- a/gr-usrp/src/db_xcvr2450.py
+++ b/gr-usrp/src/db_xcvr2450.py
@@ -19,18 +19,16 @@
# Boston, MA 02110-1301, USA.
#
-from gnuradio import usrp1
-import time,math
+from gnuradio import usrp1, gru, eng_notation
+import time, math, weakref
from usrpm import usrp_dbid
import db_base
import db_instantiator
from usrpm.usrp_fpga_regs import *
-debug_using_gui = False # Must be set to True or False
-
-#if debug_using_gui:
-# import flexrf_debug_gui
+# Convenience function
+n2s = eng_notation.num_to_str
# d'board i/o pin defs
@@ -40,6 +38,8 @@ LB_PA_OFF = (1 << 14) # 2.4GHz PA, 1 = off, 0 = on
ANTSEL_TX1_RX2 = (1 << 13) # 1 = Ant 1 to TX, Ant 2 to RX
ANTSEL_TX2_RX1 = (1 << 12) # 1 = Ant 2 to TX, Ant 1 to RX
TX_EN = (1 << 11) # 1 = TX on, 0 = TX off
+TX_OE_MASK = HB_PA_OFF|LB_PA_OFF|ANTSEL_TX1_RX2|ANTSEL_TX2_RX1|TX_EN
+TX_SAFE_IO = HB_PA_OFF|LB_PA_OFF|ANTSEL_TX1_RX2
# RX IO Pins
LOCKDET = (1 << 15) # This is an INPUT!!!
@@ -53,65 +53,94 @@ B4 = (1 << 8)
B5 = (1 << 7)
B6 = (1 << 6)
B7 = (1 << 5)
+RX_OE_MASK = EN|RX_EN|RX_HP|B1|B2|B3|B4|B5|B6|B7
+RX_SAFE_IO = EN
-"""
-A few comments about the XCVR2450:
- It is half-duplex. I.e., transmit and receive are mutually exclusive.
- There is a single LO for both the Tx and Rx sides.
-"""
-class xcvr2450_base(db_base.db_base):
- """
- Abstract base class for all xcvr2450 boards.
+# ------------------------------------------------------------------------
+# A few comments about the XCVR2450:
+#
+# It is half-duplex. I.e., transmit and receive are mutually exclusive.
+# There is a single LO for both the Tx and Rx sides.
+# For our purposes the board is always either receiving or transmitting.
+#
+# Each board is uniquely identified by the *USRP hardware* instance and side
+# This dictionary holds a weak reference to existing board controller so it
+# can be created or retrieved as needed.
+
+_xcvr2450_inst = weakref.WeakValueDictionary()
+def _get_or_make_xcvr2450(usrp, which):
+ key = (usrp.serial_number(), which)
+ if not _xcvr2450_inst.has_key(key):
+ print "Creating new xcvr2450 instance"
+ inst = xcvr2450(usrp, which)
+ _xcvr2450_inst[key] = inst
+ else:
+ print "Using existing xcvr2450 instance"
+ inst = _xcvr2450_inst[key]
+ return inst
- Derive board specific subclasses from db_xcvr2450_base_{tx,rx}
- """
+# ------------------------------------------------------------------------
+# Common, shared object for xcvr2450 board. Transmit and receive classes
+# operate on an instance of this; one instance is created per physical
+# daughterboard.
+
+class xcvr2450(object):
def __init__(self, usrp, which):
- """
- @param usrp: instance of usrp.source_c
- @param which: which side: 0 or 1 corresponding to side A or B respectively
- @type which: int
- """
- # sets _u _which _tx and _slot
- db_base.db_base.__init__(self, usrp, which)
+ print "xcvr2450: __init__ with %s: %d" % (usrp.serial_number(), which)
+ self.u = usrp
+ self.which = which
+ # Use MSB with no header
self.spi_format = usrp1.SPI_FMT_MSB | usrp1.SPI_FMT_HDR_0
self.spi_enable = (usrp1.SPI_ENABLE_RX_A, usrp1.SPI_ENABLE_RX_B)[which]
- # FIXME -- the write reg functions don't work with 0xffff for masks
- self._rx_write_oe(int(), 0x7fff)
- self._rx_write_io((), ())
-
- self._tx_write_oe((), 0x7fff)
- self._tx_write_io((), ())
+ # Sane defaults
+ self.mimo = 1 # 0 = OFF, 1 = ON
+ self.int_div = 192 # 128 = min, 255 = max
+ self.frac_div = 0 # 0 = min, 65535 = max
+ self.highband = 0 # 0 = freq <= 5.4e9, 1 = freq > 5.4e9
+ self.five_gig = 0 # 0 = freq <= 3.e9, 1 = freq > 3e9
+ self.cp_current = 0 # 0 = 2mA, 1 = 4mA
+ self.ref_div = 4 # 1 to 7
+ self.rssi_hbw = 0 # 0 = 2 MHz, 1 = 6 MHz
+ self.txlpf_bw = 1 # 1 = 12 MHz, 2 = 18 MHz, 3 = 24 MHz
+ self.rxlpf_bw = 1 # 0 = 7.5 MHz, 1 = 9.5 MHz, 2 = 14 MHz, 3 = 18 MHz
+ self.rxlpf_fine = 2 # 0 = 90%, 1 = 95%, 2 = 100%, 3 = 105%, 4 = 110%
+ self.rxvga_ser = 1 # 0 = RXVGA controlled by B7:1, 1 = controlled serially
+ self.rssi_range = 1 # 0 = low range (datasheet typo), 1 = high range (0.5V - 2.0V)
+ self.rssi_mode = 1 # 0 = enable follows RXHP, 1 = enabled
+ self.rssi_mux = 0 # 0 = RSSI, 1 = TEMP
+ self.rx_hp_pin = 0 # 0 = Fc set by rx_hpf, 1 = 600 KHz
+ self.rx_hpf = 0 # 0 = 100Hz, 1 = 30KHz
+ self.rx_ant = 0 # 0 = Ant. #1, 1 = Ant. #2
+ self.tx_ant = 0 # 0 = Ant. #1, 1 = Ant. #2
+ self.txvga_ser = 1 # 0 = TXVGA controlled by B6:1, 1 = controlled serially
+ self.tx_driver_lin = 2 # 0 = 50% (worst linearity), 1 = 63%, 2 = 78%, 3 = 100% (best lin)
+ self.tx_vga_lin = 2 # 0 = 50% (worst linearity), 1 = 63%, 2 = 78%, 3 = 100% (best lin)
+ self.tx_upconv_lin = 2 # 0 = 50% (worst linearity), 1 = 63%, 2 = 78%, 3 = 100% (best lin)
+ self.tx_bb_gain = 3 # 0 = maxgain-5dB, 1 = max-3dB, 2 = max-1.5dB, 3 = max
+ self.pabias_delay = 15 # 0 = 0, 15 = 7uS
+ self.pabias = 0 # 0 = 0 uA, 63 = 315uA
+ self.rx_rf_gain = 0 # 0 = 0dB, 1 = 0dB, 2 = 15dB, 3 = 30dB
+ self.rx_bb_gain = 16 # 0 = min, 31 = max (0 - 62 dB)
+
+ self.txgain = 63 # 0 = min, 63 = max
+
+ # Initialize GPIO and ATR
+ self.tx_write_io(TX_SAFE_IO, TX_OE_MASK)
+ self.tx_write_oe(TX_OE_MASK, ~0)
+ self.tx_set_atr_txval(TX_SAFE_IO)
+ self.tx_set_atr_rxval(TX_SAFE_IO)
+ self.tx_set_atr_mask(TX_OE_MASK)
+ self.rx_write_io(RX_SAFE_IO, RX_OE_MASK)
+ self.rx_write_oe(RX_OE_MASK, ~0)
+ self.rx_set_atr_rxval(RX_SAFE_IO)
+ self.rx_set_atr_txval(RX_SAFE_IO)
+ self.rx_set_atr_mask(RX_OE_MASK)
- self.mimo = 1
- self.cp_current = 0 # 0 = 2mA, 1 = 4mA
- self.ref_div = 4 # 1 to 7
-
- self.rssi_hbw = 0 # 0 = 2 MHz, 1 = 6 MHz
- self.txlpf_bw = 1 # 1 = 12 MHz, 2 = 18 MHz, 3 = 24 MHz
- self.rxlpf_bw = 1 # 0 = 7.5 MHz, 1 = 9.5 MHz, 2 = 14 MHz, 3 = 18 MHz
- self.rxlpf_fine = 2 # 0 = 90%, 1 = 95%, 2 = 100%, 3 = 105%, 4 = 110%
-
- self.rxvga_ser = 1 # 0 = RXVGA controlled by B7:1, 1 = controlled serially
- self.txvga_ser = 1 # 0 = TXVGA controlled by B6:1, 1 = controlled serially
-
- self.tx_driver_lin = 2 # 0 = 50% (worst linearity), 1 = 63%, 2 = 78%, 3 = 100% (best lin)
- self.tx_vga_lin = 2 # 0 = 50% (worst linearity), 1 = 63%, 2 = 78%, 3 = 100% (best lin)
- self.tx_upconv_lin = 2 # 0 = 50% (worst linearity), 1 = 63%, 2 = 78%, 3 = 100% (best lin)
- self.tx_bb_gain = 0 # 0 = maxgain-5dB, 1 = max-3dB, 2 = max-1.5dB, 3 = max
-
- self.pabias_delay = 15 # 0 = 0, 15 = 7uS
- self.pabias = 0 # 0 = 0 uA, 63 = 315uA
-
- self.rxgain = 64
- self.txgain = 32
-
- self.set_freq(2.45e6)
- self.set_auto_tr(True)
-
- # SPI reset here
+ # Initialize chipset
+ # TODO: perform reset sequence to ensure power up defaults
self.set_reg_standby()
self.set_reg_bandselpll()
self.set_reg_cal()
@@ -121,131 +150,314 @@ class xcvr2450_base(db_base.db_base):
self.set_reg_pabias()
self.set_reg_rxgain()
self.set_reg_txgain()
+ self.set_freq(2.45e9)
+
+ def __del__(self):
+ print "xcvr2450: __del__"
+ self.tx_set_atr_txval(TX_SAFE_IO)
+ self.tx_set_atr_rxval(TX_SAFE_IO)
+ self.rx_set_atr_rxval(RX_SAFE_IO)
+ self.rx_set_atr_txval(RX_SAFE_IO)
- def set_reg_standby(self): # reg 2
- self.reg_standby = (self.mimo<<17)|(1<<16)|(1<<6)|(1<<5)|(1<<4)|2
+
+ # --------------------------------------------------------------------
+ # These methods set the MAX2829 onboard registers over the SPI bus.
+ # The SPI format is 18 bits, with the four LSBs holding the register no.
+ # Thus, the shift values used here are the D0-D13 values from the data
+ # sheet, *plus* four.
+
+ # Standby (2)
+ def set_reg_standby(self):
+ self.reg_standby = (
+ (self.mimo<<17) |
+ (1<<16) |
+ (1<<6) |
+ (1<<5) |
+ (1<<4) | 2)
self.send_reg(self.reg_standby)
+
+ # Integer-Divider Ratio (3)
+ def set_reg_int_divider(self):
+ self.reg_int_divider = (
+ ((self.frac_div & 0x03)<<16) |
+ (self.int_div<<4) | 3)
+ self.send_reg(self.reg_int_divider)
+
+ # Fractional-Divider Ratio (4)
+ def set_reg_frac_divider(self):
+ self.reg_frac_divider = ((self.frac_div & 0xfffc)<<2) | 4
+ self.send_reg(self.reg_frac_divider)
- def set_reg_bandselpll(self): # reg 5
- if self.freq > 5.4e9:
- self.highband = 1
- self.five_gig = 1
- else if self.freq > 3e9:
- self.highband = 0
- self.five_gig = 1
- else:
- self.highband = 0
- self.five_gig = 0
- self.reg_bandselpll = (self.mimo<<17)|(1<<16)|(1<<15)|(1<<11)|(self.highband<<10)| \
- (self.cp_current<<9)|(self.cp_current<<5)|(self.five_gig<<4)|5
+ # Band Select and PLL (5)
+ def set_reg_bandselpll(self):
+ self.reg_bandselpll = (
+ (self.mimo<<17) |
+ (1<<16) |
+ (1<<15) |
+ (1<<11) |
+ (self.highband<<10) |
+ (self.cp_current<<9) |
+ (self.ref_div<<5) |
+ (self.five_gig<<4) | 5)
self.send_reg(self.reg_bandselpll)
-
- def set_reg_cal(self): # reg 6
- # FIXME do calibration
+
+
+ # Calibration (6)
+ def set_reg_cal(self):
+ # FIXME do calibration
self.reg_cal = (1<<14)|6
self.send_reg(self.reg_cal)
+
+ # Lowpass Filter (7)
def set_reg_lpf(self):
- self.reg_lpf = (self.rssi_hbw<<15)|(self.txlpf_bw<<9)|(self.rxlpf_bw<<7)|(self.rxlpf_fine<<4)|7
+ self.reg_lpf = (
+ (self.rssi_hbw<<15) |
+ (self.txlpf_bw<<10) |
+ (self.rxlpf_bw<<9) |
+ (self.rxlpf_fine<<4) | 7)
self.send_reg(self.reg_lpf)
-
+
+
+ # Rx Control/RSSI (8)
def set_reg_rxrssi_ctrl(self):
- self.reg_rxrssi_ctrl = (self.rxvga_serial<<16)|(1<<15)|(1<<14)|(1<<9)|(1<<4)|8
+ self.reg_rxrssi_ctrl = (
+ (self.rxvga_ser<<16) |
+ (self.rssi_range<<15) |
+ (self.rssi_mode<<14) |
+ (self.rssi_mux<<12) |
+ (1<<9) |
+ (self.rx_hpf<<6) |
+ (1<<4) | 8)
self.send_reg(self.reg_rxrssi_ctrl)
+
+ # Tx Linearity/Baseband Gain (9)
def set_reg_txlin_gain(self):
- self.reg_txlin_gain = (self.txvga_ser<<14)|(self.tx_driver_lin<<12)| \
- (self.tx_vga_lin<<10)|(self.tx_upconv_lin<<6)|(self.tx_bb_gain<<4)|9
+ self.reg_txlin_gain = (
+ (self.txvga_ser<<14) |
+ (self.tx_driver_lin<<12) |
+ (self.tx_vga_lin<<10) |
+ (self.tx_upconv_lin<<6) |
+ (self.tx_bb_gain<<4) | 9)
self.send_reg(self.reg_txlin_gain)
+
+ # PA Bias DAC (10)
def set_reg_pabias(self):
- self.reg_pabias = (self.pabias_delay<<10)|(self.pabias<<4)|10
+ self.reg_pabias = (
+ (self.pabias_delay<<10) |
+ (self.pabias<<4) | 10)
self.send_reg(self.reg_pabias)
+
+ # Rx Gain (11)
def set_reg_rxgain(self):
- self.reg_rxgain = (self.rxgain<<4)|11
+ self.reg_rxgain = (
+ (self.rx_rf_gain<<9) |
+ (self.rx_bb_gain<<4) | 11)
self.send_reg(self.reg_rxgain)
+
+ # Tx Gain (12)
def set_reg_txgain(self):
- self.reg_txgain = (self.txgain<<4)|12
+ self.reg_txgain = (self.txgain<<4) | 12
self.send_reg(self.reg_txgain)
+
+
+ # Send register write to SPI
+ def send_reg(self, v):
+ # Send 24 bits, it keeps last 18 clocked in
+ s = ''.join((chr((v >> 16) & 0xff),
+ chr((v >> 8) & 0xff),
+ chr(v & 0xff)))
+ self.u._write_spi(0, self.spi_enable, self.spi_format, s)
+ print "xcvr2450: Setting reg %d to %06X" % ((v&15), v)
+
+ # --------------------------------------------------------------------
+ # These methods control the GPIO bus. Since the board has to access
+ # both the io_rx_* and io_tx_* pins, we define our own methods to do so.
+ # This bypasses any code in db_base.
+ #
+ # The board operates in ATR mode, always. Thus, when the board is first
+ # initialized, it is in receive mode, until bits show up in the TX FIFO.
+ #
+ def tx_write_oe(self, value, mask):
+ return self.u._write_fpga_reg((FR_OE_0, FR_OE_2)[self.which],
+ gru.hexint((mask << 16) | value))
+
+ def tx_write_io(self, value, mask):
+ return self.u._write_fpga_reg((FR_IO_0, FR_IO_2)[self.which],
+ gru.hexint((mask << 16) | value))
+
+ def tx_read_io(self):
+ t = self.u._read_fpga_reg((FR_RB_IO_RX_A_IO_TX_A, FR_RB_IO_RX_B_IO_TX_B)[self.which])
+ return t & 0xffff
+
+
+ def rx_write_oe(self, value, mask):
+ return self.u._write_fpga_reg((FR_OE_1, FR_OE_3)[self.which],
+ gru.hexint((mask << 16) | value))
+
+ def rx_write_io(self, value, mask):
+ return self.u._write_fpga_reg((FR_IO_1, FR_IO_3)[self.which],
+ gru.hexint((mask << 16) | value))
+
+ def rx_read_io(self):
+ t = self.u._read_fpga_reg((FR_RB_IO_RX_A_IO_TX_A, FR_RB_IO_RX_B_IO_TX_B)[self.which])
+ return (t >> 16) & 0xffff
+
+ def tx_set_atr_mask(self, v):
+ return self.u._write_fpga_reg((FR_ATR_MASK_0,FR_ATR_MASK_2)[self.which],
+ gru.hexint(v))
+
+ def tx_set_atr_txval(self, v):
+ return self.u._write_fpga_reg((FR_ATR_TXVAL_0,FR_ATR_TXVAL_2)[self.which],
+ gru.hexint(v))
+
+ def tx_set_atr_rxval(self, v):
+ return self.u._write_fpga_reg((FR_ATR_RXVAL_0,FR_ATR_RXVAL_2)[self.which],
+ gru.hexint(v))
+
+ def rx_set_atr_mask(self, v):
+ return self.u._write_fpga_reg((FR_ATR_MASK_1,FR_ATR_MASK_3)[self.which],
+ gru.hexint(v))
+
+ def rx_set_atr_txval(self, v):
+ return self.u._write_fpga_reg((FR_ATR_TXVAL_1,FR_ATR_TXVAL_3)[self.which],
+ gru.hexint(v))
+
+ def rx_set_atr_rxval(self, v):
+ return self.u._write_fpga_reg((FR_ATR_RXVAL_1,FR_ATR_RXVAL_3)[self.which],
+ gru.hexint(v))
+
+ def set_gpio(self):
+ # We calculate four values:
+ #
+ # io_rx_while_rx: what to drive onto io_rx_* when receiving
+ # io_rx_while_tx: what to drive onto io_rx_* when transmitting
+ # io_tx_while_rx: what to drive onto io_tx_* when receiving
+ # io_tx_while_tx: what to drive onto io_tx_* when transmitting
+ #
+ # B1-B7 is ignored as gain is set serially for now.
+
+ rx_hp = (0, RX_HP)[self.rx_hp_pin]
+ tx_antsel = (ANTSEL_TX1_RX2, ANTSEL_TX2_RX1)[self.tx_ant]
+ rx_antsel = (ANTSEL_TX1_RX2, ANTSEL_TX2_RX1)[self.rx_ant]
+ tx_pa_sel = (HB_PA_OFF, LB_PA_OFF)[self.five_gig]
+ io_rx_while_rx = EN|rx_hp|RX_EN
+ io_rx_while_tx = EN|rx_hp
+ io_tx_while_rx = HB_PA_OFF|LB_PA_OFF|rx_antsel
+ io_tx_while_tx = tx_pa_sel|tx_antsel|TX_EN
+ self.rx_set_atr_rxval(io_rx_while_rx)
+ self.rx_set_atr_txval(io_rx_while_tx)
+ self.tx_set_atr_rxval(io_tx_while_rx)
+ self.tx_set_atr_txval(io_tx_while_tx)
- def __del__(self):
- #self._u.write_io(self._which, self.power_off, POWER_UP) # turn off power to board
- #self._u._write_oe(self._which, 0, 0xffff) # turn off all outputs
- self.set_auto_tr(False)
+ print "GPIO: RXRX=%04X RXTX=%04X TXRX=%04X TXTX=%04X" % (
+ io_rx_while_rx, io_rx_while_tx, io_tx_while_rx, io_tx_while_tx)
+
+ # --------------------------------------------------------------------
+ # These methods set control the high-level operating parameters.
+
+ def set_freq(self, target_freq):
+ if target_freq > 3e9:
+ self.five_gig = 1
+ self.ref_div = 3
+ scaler = 4.0/5.0
+ else:
+ self.five_gig = 0
+ self.ref_div = 4
+ scaler = 4.0/3.0;
+
+ if target_freq > 5.4e9:
+ self.highband = 1
+ else:
+ self.highband = 0
+
+ vco_freq = target_freq*scaler;
+ ref_clk = self.u.fpga_master_clock_freq() # Assumes AD9515 is bypassed
+ phdet_freq = ref_clk/self.ref_div
+ div = vco_freq/phdet_freq
+ self.int_div = int(math.floor(div))
+ self.frac_div = int((div-self.int_div)*65536.0)
+ actual_freq = phdet_freq*(self.int_div+(self.frac_div/65536.0))/scaler
+
+ print "RF=%s VCO=%s R=%d PHD=%s DIV=%3.5f I=%3d F=%5d ACT=%s" % (
+ n2s(target_freq), n2s(vco_freq), self.ref_div, n2s(phdet_freq),
+ div, self.int_div, self.frac_div, n2s(actual_freq))
+
+ self.set_gpio()
+ self.set_reg_int_divider()
+ self.set_reg_frac_divider()
+ self.set_reg_bandselpll()
- def _lock_detect(self):
+ ok = self.lock_detect()
+ print "lock detect:", ok
+ return (ok, actual_freq)
+
+ def lock_detect(self):
"""
@returns: the value of the VCO/PLL lock detect bit.
@rtype: 0 or 1
"""
- if self._rx_read_io() & LOCKDET:
+ if self.rx_read_io() & LOCKDET:
return True
else: # Give it a second chance
- if self._rx_read_io() & LOCKDET:
+ if self.rx_read_io() & LOCKDET:
return True
else:
return False
- def send_reg(self,s):
- self._u._write_spi(0, self.spi_enable, self.spi_format, s)
- print "Set Reg %d: Value %x: \n" % ((s&15),s)
-
- # Both sides need access to the Rx pins.
- # Write them directly, bypassing the convenience routines.
- # (Sort of breaks modularity, but will work...)
-
- def _tx_write_oe(self, value, mask):
- return self._u._write_fpga_reg((FR_OE_0, FR_OE_2)[self._which],
- ((mask & 0xffff) << 16) | (value & 0xffff))
-
- def _rx_write_oe(self, value, mask):
- return self._u._write_fpga_reg((FR_OE_1, FR_OE_3)[self._which],
- ((mask & 0xffff) << 16) | (value & 0xffff))
-
- def _tx_write_io(self, value, mask):
- return self._u._write_fpga_reg((FR_IO_0, FR_IO_2)[self._which],
- ((mask & 0xffff) << 16) | (value & 0xffff))
-
- def _rx_write_io(self, value, mask):
- return self._u._write_fpga_reg((FR_IO_1, FR_IO_3)[self._which],
- ((mask & 0xffff) << 16) | (value & 0xffff))
-
- def _tx_read_io(self):
- t = self._u._read_fpga_reg((FR_RB_IO_RX_A_IO_TX_A, FR_RB_IO_RX_B_IO_TX_B)[self._which])
- return t & 0xffff
+ def set_rx_gain(self, gain):
+ if gain < 0.0: gain = 0.0
+ if gain > 92.0: gain = 92.0
+
+ # Split the gain between RF and baseband
+ # This is experimental, not prescribed
+ if gain < 31.0:
+ self.rx_rf_gain = 0 # 0 dB RF gain
+ self.rx_bb_gain = int(gain/2.0)
+
+ if gain >= 30.0 and gain < 60.5:
+ self.rx_rf_gain = 2 # 15 dB RF gain
+ self.rx_bb_gain = int((gain-15.0)/2.0)
+
+ if gain >= 60.5:
+ self.rx_rf_gain = 3 # 30.5 dB RF gain
+ self.rx_bb_gain = int((gain-30.5)/2.0)
+
+ self.set_reg_rxgain()
- def _rx_read_io(self):
- t = self._u._read_fpga_reg((FR_RB_IO_RX_A_IO_TX_A, FR_RB_IO_RX_B_IO_TX_B)[self._which])
- return (t >> 16) & 0xffff
+ def set_tx_gain(self, gain):
+ if gain < 0.0: gain = 0.0
+ if gain > 30.0: gain = 30.0
+ self.txgain = int((gain/30.0)*63)
+ self.set_reg_txgain()
- def _refclk_freq(self):
- return float(self._u.fpga_master_clock_freq())/self._refclk_divisor()
+class db_xcvr2450_base(db_base.db_base):
+ """
+ Abstract base class for all xcvr2450 boards.
- def _refclk_divisor(self):
+ Derive board specific subclasses from db_xcvr2450_base_{tx,rx}
+ """
+ def __init__(self, usrp, which):
"""
- Return value to stick in REFCLK_DIVISOR register
+ @param usrp: instance of usrp.source_c
+ @param which: which side: 0 or 1 corresponding to side A or B respectively
+ @type which: int
"""
- return 1
-
- # ----------------------------------------------------------------
-
- def set_freq(self, freq):
+ # sets _u _which _tx and _slot
+ db_base.db_base.__init__(self, usrp, which)
+ self.xcvr = _get_or_make_xcvr2450(usrp, which)
+
+ def set_freq(self, target_freq):
"""
@returns (ok, actual_baseband_freq) where:
ok is True or False and indicates success or failure,
actual_baseband_freq is the RF frequency that corresponds to DC in the IF.
"""
- raise NotImplementedError
-
- def _set_pga(self, pga_gain):
- if(self._which == 0):
- self._u.set_pga (0, pga_gain)
- self._u.set_pga (1, pga_gain)
- else:
- self._u.set_pga (2, pga_gain)
- self._u.set_pga (3, pga_gain)
+ return self.xcvr.set_freq(target_freq)
def is_quadrature(self):
"""
@@ -255,338 +467,46 @@ class xcvr2450_base(db_base.db_base):
"""
return True
+ def freq_range(self):
+ return (2.4e9, 6e9, 1e6)
+
+ def set_freq(self, target_freq):
+ return self.xcvr.set_freq(target_freq)
+
# ----------------------------------------------------------------
-class xcvr2450_tx(xcvr2450_base):
+class db_xcvr2450_tx(db_xcvr2450_base):
def __init__(self, usrp, which):
"""
@param usrp: instance of usrp.sink_c
@param which: 0 or 1 corresponding to side TX_A or TX_B respectively.
"""
- xcvr2450_base.__init__(self, usrp, which)
-
- # power up the transmit side, NO -- but set antenna to receive
- self._u.write_io(self._which, (TX_POWER), (TX_POWER|RX_TXN))
- self._lo_offset = 0e6
-
- set_atr_mask(v)
- set_atr_txval(v)
- set_atr_rxval(v)
- set_atr_tx_delay(v)
- set_atr_rx_delay(v)
-
- # Gain is not set by the PGA, but the PGA must be set at max gain in the TX
- return self._set_pga(self._u.pga_max())
-
- def __del__(self):
- # Power down and leave the T/R switch in the R position
- xcvr2450_base.__del__(self)
-
- def set_auto_tr(self, on):
- if on:
- self.set_atr_mask (RX_TXN)
- self.set_atr_txval(0)
- self.set_atr_rxval(RX_TXN)
- else:
- self.set_atr_mask (0)
- self.set_atr_txval(0)
- self.set_atr_rxval(0)
-
- def set_enable(self, on):
- """
- Enable transmitter if on is True
- """
- if on:
- v = 0
- else:
- v = RX_TXN
- self._u.write_io(self._which, v, RX_TXN)
+ print "db_xcvr2450_tx: __init__"
+ db_xcvr2450_base.__init__(self, usrp, which)
- def set_lo_offset(self, offset):
- """
- Set amount by which LO is offset from requested tuning frequency.
-
- @param offset: offset in Hz
- """
- self._lo_offset = offset
-
- def lo_offset(self):
- """
- Get amount by which LO is offset from requested tuning frequency.
-
- @returns Offset in Hz
- """
- return self._lo_offset
-
def gain_range(self):
- """
- Return range of gain that can be set by this d'board.
-
- @returns (min_gain, max_gain, step_size)
- Where gains are expressed in decibels (your mileage may vary)
-
- Gain is controlled by a VGA in the output amplifier, not the PGA
- """
- return (0, 63, 0.1)
+ return (0, 30, (30.0/63.0))
def set_gain(self, gain):
- """
- Set the gain.
-
- @param gain: gain in decibels
- @returns True/False
- """
- gain = int(gain)
- if (gain>gain_range()[1]) or (gain<gain_range()[0]):
- raise ValueError, "TX Gain out of range."
+ return self.xcvr.set_tx_gain(gain)
-class xcvr2450_rx(wbx_base):
+class db_xcvr2450_rx(db_xcvr2450_base):
def __init__(self, usrp, which):
"""
@param usrp: instance of usrp.source_c
@param which: 0 or 1 corresponding to side RX_A or RX_B respectively.
"""
- wbx_base.__init__(self, usrp, which)
-
- # set up for RX on TX/RX port
- self.select_rx_antenna('TX/RX')
-
- self.bypass_adc_buffers(True)
-
- self._lo_offset = 0.0
-
- def __del__(self):
- # Power down
- self._u.write_io(self._which, 0, (RXENABLE))
- wbx_base.__del__(self)
-
- def set_auto_tr(self, on):
- if on:
- self.set_atr_mask (ENABLE)
- self.set_atr_txval( 0)
- self.set_atr_rxval(ENABLE)
- else:
- self.set_atr_mask (0)
- self.set_atr_txval(0)
- self.set_atr_rxval(0)
-
- def select_rx_antenna(self, which_antenna):
- """
- Specify which antenna port to use for reception.
- @param which_antenna: either 'TX/RX' or 'RX2'
- """
- if which_antenna in (0, 'TX/RX'):
- self._u.write_io(self._which, 0, RX2_RX1N)
- elif which_antenna in (1, 'RX2'):
- self._u.write_io(self._which, RX2_RX1N, RX2_RX1N)
- else:
- raise ValueError, "which_antenna must be either 'TX/RX' or 'RX2'"
-
- def set_gain(self, gain):
- """
- Set the gain.
-
- @param gain: gain in decibels
- @returns True/False
- """
- maxgain = self.gain_range()[1] - self._u.pga_max()
- mingain = self.gain_range()[0]
- if gain > maxgain:
- pga_gain = gain-maxgain
- assert pga_gain <= self._u.pga_max()
- agc_gain = maxgain
- else:
- pga_gain = 0
- agc_gain = gain
- V_maxgain = .2
- V_mingain = 1.2
- V_fullscale = 3.3
- dac_value = (agc_gain*(V_maxgain-V_mingain)/(maxgain-mingain) + V_mingain)*4096/V_fullscale
- assert dac_value>=0 and dac_value<4096
- return self._u.write_aux_dac(self._which, 0, int(dac_value)) and \
- self._set_pga(int(pga_gain))
-
- def set_lo_offset(self, offset):
- """
- Set amount by which LO is offset from requested tuning frequency.
-
- @param offset: offset in Hz
- """
- self._lo_offset = offset
-
- def lo_offset(self):
- """
- Get amount by which LO is offset from requested tuning frequency.
-
- @returns Offset in Hz
- """
- return self._lo_offset
-
-
- def i_and_q_swapped(self):
- """
- Return True if this is a quadrature device and ADC 0 is Q.
- """
- return True
-
- def __init__(self):
- pass
-
- def _compute_regs(self, freq):
- """
- Determine values of R, control, and N registers, along with actual freq.
-
- @param freq: target frequency in Hz
- @type freq: float
- @returns: (R, N, control, actual_freq)
- @rtype: tuple(int, int, int, float)
- """
-
- # Band-specific N-Register Values
- phdet_freq = self._refclk_freq()/self.R_DIV
- print "phdet_freq = %f" % (phdet_freq,)
- desired_n = round(freq*self.freq_mult/phdet_freq)
- print "desired_n %f" % (desired_n,)
- actual_freq = desired_n * phdet_freq
- print "actual freq %f" % (actual_freq,)
- B = math.floor(desired_n/self._prescaler())
- A = desired_n - self._prescaler()*B
- print "A %d B %d" % (A,B)
- self.B_DIV = int(B) # bits 20:8
- self.A_DIV = int(A) # bit 6:2
- #assert self.B_DIV >= self.A_DIV
- if self.B_DIV < self.A_DIV:
- return (0,0,0,0)
- R = (self.R_RSV<<21) | (self.LDP<<20) | (self.TEST<<18) | \
- (self.ABP<<16) | (self.R_DIV<<2)
-
- N = (self.N_RSV<<22) | (self.CP_GAIN<<21) | (self.B_DIV<<8) | (self.A_DIV<<2)
-
- control = (self.P<<22) | (self.PD2<<21) | (self.CP2<<18) | (self.CP1<<15) | \
- (self.TC<<11) | (self.FL<<9) | (self.CP3S<<8) | (self.PDP<<7) | \
- (self.MUXOUT<<4) | (self.PD1<<3) | (self.CR<<2)
-
- return (R,N,control,actual_freq/self.freq_mult)
-
- def _write_all(self, R, N, control):
- """
- Write all PLL registers:
- R counter latch,
- N counter latch,
- Function latch,
- Initialization latch
-
- Adds 10ms delay between writing control and N if this is first call.
- This is the required power-up sequence.
-
- @param R: 24-bit R counter latch
- @type R: int
- @param N: 24-bit N counter latch
- @type N: int
- @param control: 24-bit control latch
- @type control: int
- """
- self._write_R(R)
- self._write_func(control)
- self._write_init(control)
- self._write_N(N)
-
- def _write_R(self, R):
- self._write_it((R & ~0x3) | 0)
-
- def _write_N(self, N):
- self._write_it((N & ~0x3) | 1)
-
- def _write_func(self, func):
- self._write_it((func & ~0x3) | 2)
-
- def _write_init(self, init):
- self._write_it((init & ~0x3) | 3)
-
- def _write_it(self, v):
- s = ''.join((chr((v >> 16) & 0xff),
- chr((v >> 8) & 0xff),
- chr(v & 0xff)))
- self._u._write_spi(0, self.spi_enable, self.spi_format, s)
-
- def _prescaler(self):
- if self.P == 0:
- return 8
- elif self.P == 1:
- return 16
- elif self.P == 2:
- return 32
- elif self.P == 3:
- return 64
- else:
- raise ValueError, "Prescaler out of range"
+ print "db_xcvr2450_rx: __init__"
+ db_xcvr2450_base.__init__(self, usrp, which)
def gain_range(self):
- """
- Return range of gain that can be set by this d'board.
-
- @returns (min_gain, max_gain, step_size)
- Where gains are expressed in decibels (your mileage may vary)
- """
- return (self._u.pga_min(), self._u.pga_max() + 45, 0.05)
-
-#----------------------------------------------------------------------
-class _lo_common(_ADF410X_common):
-
- def freq_range(self): # FIXME
- return (50e6, 1000e6, 16e6)
-
- def set_freq(self, freq):
- #freq += self._lo_offset
-
- if(freq < 20e6 or freq > 1200e6):
- raise ValueError, "Requested frequency out of range"
- div = 1
- lo_freq = freq * 2
- while lo_freq < 1e9 and div < 8:
- div = div * 2
- lo_freq = lo_freq * 2
- print "For RF freq of %f, we set DIV=%d and LO Freq=%f" % (freq, div, lo_freq)
- self.set_divider('main', div)
- self.set_divider('aux', 2)
-
- R, N, control, actual_freq = self._compute_regs(lo_freq)
- print "R %d N %d control %d actual freq %f" % (R,N,control,actual_freq)
- if R==0:
- return(False,0)
- self._write_all(R, N, control)
- return (self._lock_detect(), actual_freq/div/2)
+ return (0.0, 92.0, 1)
+ def set_gain(self, gain):
+ return self.xcvr.set_rx_gain(gain)
#------------------------------------------------------------
# hook these daughterboard classes into the auto-instantiation framework
db_instantiator.add(usrp_dbid.XCVR2450_TX, lambda usrp, which : (db_xcvr2450_tx(usrp, which),))
db_instantiator.add(usrp_dbid.XCVR2450_RX, lambda usrp, which : (db_xcvr2450_rx(usrp, which),))
-
-# ------------------------------------------------------------------------
-# Automatic Transmit/Receive switching
-#
-# The presence or absence of data in the FPGA transmit fifo
-# selects between two sets of values for each of the 4 banks of
-# daughterboard i/o pins.
-#
-# Each daughterboard slot has 3 16-bit registers associated with it:
-# FR_ATR_MASK_*, FR_ATR_TXVAL_* and FR_ATR_RXVAL_*
-#
-# FR_ATR_MASK_{0,1,2,3}:
-#
-# These registers determine which of the daugherboard i/o pins are
-# affected by ATR switching. If a bit in the mask is set, the
-# corresponding i/o bit is controlled by ATR, else it's output
-# value comes from the normal i/o pin output register:
-# FR_IO_{0,1,2,3}.
-#
-# FR_ATR_TXVAL_{0,1,2,3}:
-# FR_ATR_RXVAL_{0,1,2,3}:
-#
-# If the Tx fifo contains data, then the bits from TXVAL that are
-# selected by MASK are output. Otherwise, the bits from RXVAL that
-# are selected by MASK are output.
-
-