[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] r7345 - gnuradio/branches/developers/jcorgan/xcvr2450/
From: |
jcorgan |
Subject: |
[Commit-gnuradio] r7345 - gnuradio/branches/developers/jcorgan/xcvr2450/gr-usrp/src |
Date: |
Fri, 4 Jan 2008 14:40:53 -0700 (MST) |
Author: jcorgan
Date: 2008-01-04 14:40:52 -0700 (Fri, 04 Jan 2008)
New Revision: 7345
Modified:
gnuradio/branches/developers/jcorgan/xcvr2450/gr-usrp/src/db_xcvr2450.py
Log:
Work in progress. Code reorganization and cleanup. Implemented
'set_freq' method. With hardware modified to bypass the AD9515
clock divider, to force the PLL ref frequency to 64 MHz, successful
VCO/PLL lock is still achieved over the following ranges:
2.4G : 2.324 - 2.584GHz
5.5G : 4.647 - 5.865GHz
Modified:
gnuradio/branches/developers/jcorgan/xcvr2450/gr-usrp/src/db_xcvr2450.py
===================================================================
--- gnuradio/branches/developers/jcorgan/xcvr2450/gr-usrp/src/db_xcvr2450.py
2008-01-04 20:33:23 UTC (rev 7344)
+++ gnuradio/branches/developers/jcorgan/xcvr2450/gr-usrp/src/db_xcvr2450.py
2008-01-04 21:40:52 UTC (rev 7345)
@@ -19,14 +19,17 @@
# Boston, MA 02110-1301, USA.
#
-from gnuradio import usrp1, gru
-import time,math, weakref
+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 *
+# Convenience function
+n2s = eng_notation.num_to_str
+
# d'board i/o pin defs
# TX IO Pins
@@ -55,35 +58,37 @@
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.
-"""
-
# ------------------------------------------------------------------------
+# 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
-_MAX2829_inst = weakref.WeakValueDictionary()
-def _get_or_make_MAX2829(usrp, which):
+# 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 _MAX2829_inst.has_key(key):
- print "Creating new MAX2829 instance"
- inst = MAX2829(usrp, which)
- _MAX2829_inst[key] = inst
+ if not _xcvr2450_inst.has_key(key):
+ print "Creating new xcvr2450 instance"
+ inst = xcvr2450(usrp, which)
+ _xcvr2450_inst[key] = inst
else:
- print "Using existing MAX2829 instance"
- inst = _MAX2829_inst[key]
+ print "Using existing xcvr2450 instance"
+ inst = _xcvr2450_inst[key]
return inst
+# ------------------------------------------------------------------------
+# Common, shared object for xcvr2450 board. Transmit and receive classes
+# operate on an instance of this; one instance is created per physical
+# daughterboard.
-class MAX2829(object):
- """
- Common, shared object for MAX2829 chipset. 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):
- print "MAX2829: __init__ with %s: %d" % (usrp.serial_number(), which)
+ print "xcvr2450: __init__ with %s: %d" % (usrp.serial_number(), which)
self._u = usrp
self._which = which
@@ -91,13 +96,12 @@
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: set default dependent params instead
- self.freq = 2.45e9
-
- # Configuration defaults
+ # MAX2829 chipset configuration
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
@@ -119,6 +123,18 @@
self.rxgain = 64 # 0 = min, 127 = max
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)
+
# Initialize chipset
# TODO: perform reset sequence to ensure power up defaults
self.set_reg_standby()
@@ -132,7 +148,12 @@
self.set_reg_txgain()
#self.set_freq(2.45e9)
-
+ # --------------------------------------------------------------------
+ # 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 = (
@@ -148,8 +169,6 @@
self.reg_int_divider = (
((self.frac_div & 0x03)<<16) |
(self.int_div<<4) | 3)
- print "int_div=",self.int_div
- print "reg_int_divider=",self.reg_int_divider
self._send_reg(self.reg_int_divider)
# Fractional-Divider Ratio (4)
@@ -159,17 +178,6 @@
# Band Select and PLL (5)
def set_reg_bandselpll(self):
- 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) |
@@ -250,60 +258,36 @@
chr((v >> 8) & 0xff),
chr(v & 0xff)))
self._u._write_spi(0, self.spi_enable, self.spi_format, s)
- print "MAX2829: Setting reg %d to %06X" % ((v&15), v)
+ print "xcvr2450: Setting reg %d to %06X" % ((v&15), v)
-
-class db_xcvr2450_base(db_base.db_base):
- """
- Abstract base class for all xcvr2450 boards.
-
- Derive board specific subclasses from db_xcvr2450_base_{tx,rx}
- """
- 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)
- self._xcvr = _get_or_make_MAX2829(usrp, which)
-
- self._rx_write_io(RX_SAFE_IO, RX_OE_MASK)
- self._tx_write_io(TX_TEST_IO, TX_OE_MASK)
- self._rx_write_oe(RX_OE_MASK, ~0)
- self._tx_write_oe(TX_OE_MASK, ~0)
-
- def __del__(self):
- pass
- #self.set_auto_tr(False)
-
- def _lock_detect(self):
- """
- @returns: the value of the VCO/PLL lock detect bit.
- @rtype: 0 or 1
- """
- if self._rx_read_io() & LOCKDET:
- return True
- else: # Give it a second chance
- if self._rx_read_io() & LOCKDET:
- return True
- else:
- return False
-
-
- # Both sides need access to the Rx pins.
- # Write them directly, bypassing the convenience routines.
- # (Sort of breaks modularity, but will work...)
-
+ # --------------------------------------------------------------------
+ # 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.
+ #
+ # We calculate and maintain 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
+
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))
@@ -312,32 +296,112 @@
return self._u._write_fpga_reg((FR_IO_1, FR_IO_3)[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_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 _refclk_freq(self):
- return float(self._u.fpga_master_clock_freq())/self._refclk_divisor()
+ 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 _refclk_divisor(self):
+ 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))
+
+ # --------------------------------------------------------------------
+ # 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 "For target =", n2s(target_freq)
+ print " VCO freq =", n2s(vco_freq)
+ print " ref_div =", self.ref_div
+ print " div =", div
+ print " int_div =", self.int_div
+ print " frac_div =", self.frac_div
+ print " actual =", n2s(actual_freq)
+
+ self.set_reg_int_divider()
+ self.set_reg_frac_divider()
+ self.set_reg_bandselpll()
+
+ return (self._lock_detect(), actual_freq)
+
+ def _lock_detect(self):
"""
- Return value to stick in REFCLK_DIVISOR register
+ @returns: the value of the VCO/PLL lock detect bit.
+ @rtype: 0 or 1
"""
- return 1
+ if self._rx_read_io() & LOCKDET:
+ return True
+ else: # Give it a second chance
+ if self._rx_read_io() & LOCKDET:
+ return True
+ else:
+ return False
+
+
+class db_xcvr2450_base(db_base.db_base):
+ """
+ Abstract base class for all xcvr2450 boards.
+
+ Derive board specific subclasses from db_xcvr2450_base_{tx,rx}
+ """
+ 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)
+ self._xcvr = _get_or_make_xcvr2450(usrp, which)
+
- # ----------------------------------------------------------------
-
- def set_freq(self, freq):
+ 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
+ return self._xcvr.set_freq(target_freq)
def is_quadrature(self):
@@ -353,22 +417,9 @@
return (2.4e9, 6e9, 1e6)
- def set_freq(self, freq):
- if freq < 2.4e9 or freq > 6e9:
- raise ValueError("Frequency out of range")
+ def set_freq(self, target_freq):
+ return self._xcvr.set_freq(target_freq)
- self._xcvr.freq = freq
- self._xcvr.ref_div = 2
- self._xcvr.frac_div = 0
- self._xcvr.int_div = 137
-
- self._xcvr.set_reg_int_divider()
- self._xcvr.set_reg_frac_divider()
- self._xcvr.set_reg_bandselpll()
-
- print self._lock_detect()
- return (True, freq)
-
#FIXME: temporary for debugging
def set_gain(self, gain):
return True
@@ -386,8 +437,7 @@
#FIXME: temporary for debugging
def gain_range(self):
- return (0, 5, 1)
-
+ return (0, 63, 1)
class db_xcvr2450_rx(db_xcvr2450_base):
@@ -401,7 +451,7 @@
#FIXME: temporary for debugging
def gain_range(self):
- return (0, 90, 1)
+ return (0, 127, 1)
#------------------------------------------------------------
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Commit-gnuradio] r7345 - gnuradio/branches/developers/jcorgan/xcvr2450/gr-usrp/src,
jcorgan <=