diff options
author | jcorgan | 2008-01-05 04:35:41 +0000 |
---|---|---|
committer | jcorgan | 2008-01-05 04:35:41 +0000 |
commit | 93a3a8624a3b82f55042ced8232f4d9805e87448 (patch) | |
tree | cdc16a394f9783e604913373f39caf7ca0463f0d /gr-usrp/src/db_xcvr2450.py | |
parent | ce16514534e5d7ebbc4fe46e2b09a25ccc5fdafd (diff) | |
download | gnuradio-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.py | 810 |
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. - - |