commit-gnuradio
[Top][All Lists]
Advanced

[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)
 
         
 #------------------------------------------------------------    





reply via email to

[Prev in Thread] Current Thread [Next in Thread]