aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordjepson1 <daniel.jepson@ni.com>2017-10-09 10:35:25 -0500
committerMartin Braun <martin.braun@ettus.com>2017-12-22 15:04:02 -0800
commitee3f82e4544c06cb25f90ecd3871d1a2ac4638c7 (patch)
treed92a80b6505f279dd40e79dea89376e0062afa5c
parent5c489c2597948b131aaddb516fe6af40e438b251 (diff)
downloaduhd-ee3f82e4544c06cb25f90ecd3871d1a2ac4638c7.tar.gz
uhd-ee3f82e4544c06cb25f90ecd3871d1a2ac4638c7.tar.bz2
uhd-ee3f82e4544c06cb25f90ecd3871d1a2ac4638c7.zip
mg: Updated support for LMK
- add clock shifting - add DAC support - modify __init__ calls for cleanup Signed-off-by: djepson1 <daniel.jepson@ni.com>
-rw-r--r--mpm/python/usrp_mpm/dboard_manager/lmk_mg.py82
-rw-r--r--mpm/python/usrp_mpm/dboard_manager/magnesium.py66
2 files changed, 116 insertions, 32 deletions
diff --git a/mpm/python/usrp_mpm/dboard_manager/lmk_mg.py b/mpm/python/usrp_mpm/dboard_manager/lmk_mg.py
index b295874a1..ca088b80b 100644
--- a/mpm/python/usrp_mpm/dboard_manager/lmk_mg.py
+++ b/mpm/python/usrp_mpm/dboard_manager/lmk_mg.py
@@ -25,12 +25,16 @@ from ..mpmlog import get_logger
from ..chips import LMK04828
class LMK04828Mg(LMK04828):
- def __init__(self, regs_iface, spi_lock, slot=None):
+ def __init__(self, regs_iface, spi_lock, ref_clock_freq, slot=None):
LMK04828.__init__(self, regs_iface, slot)
+ self.log.trace("Using reference clock frequency {} MHz".format(ref_clock_freq/1e6))
self.spi_lock = spi_lock
self.log = get_logger("LMK04828")
assert hasattr(self.spi_lock, 'lock')
assert hasattr(self.spi_lock, 'unlock')
+ self.ref_clock_freq = ref_clock_freq
+ self.init()
+ self.config()
def init(self):
"""
@@ -52,59 +56,59 @@ class LMK04828Mg(LMK04828):
Write lots of config foo.
"""
self.log.trace("LMK Initialization")
- clkin0_r_divider = {10e6: 0x0A, 20e6: 0x14}[10e6] # FIXME: hard coded to use 10 MHz
+ clkin0_r_divider = {10e6: 0x0A, 20e6: 0x14}[self.ref_clock_freq]
self.pokes8((
(0x100, 0x78), # CLKout Config
- (0x101, 0x55), # CLKout Config
- (0x102, 0x55), # CLKout Config
+ (0x101, 0xCC), # CLKout Config
+ (0x102, 0xCC), # CLKout Config
(0x103, 0x00), # CLKout Config
(0x104, 0x20), # CLKout Config
(0x105, 0x00), # CLKout Config
- (0x106, 0xF2), # CLKout Config MYK: (0xAB where A = SYSREF, B = CLK)
+ (0x106, 0x72), # CLKout Config MYK: (0xAB where A = SYSREF, B = CLK)
(0x107, 0x15), # CLKout Config 0x15 = LVDS, 0x55 = LVPECL
(0x108, 0x7E), # CLKout Config
- (0x109, 0x55), # CLKout Config
- (0x10A, 0x55), # CLKout Config
+ (0x109, 0xFF), # CLKout Config
+ (0x10A, 0xFF), # CLKout Config
(0x10B, 0x00), # CLKout Config
(0x10C, 0x00), # CLKout Config
(0x10D, 0x00), # CLKout Config
- (0x10E, 0xF0), # CLKout Config
+ (0x10E, 0x70), # CLKout Config
(0x10F, 0x55), # CLKout Config
- (0x110, 0x61), # CLKout Config
- (0x111, 0x55), # CLKout Config
- (0x112, 0x55), # CLKout Config
+ (0x110, 0x78), # CLKout Config
+ (0x111, 0xCC), # CLKout Config
+ (0x112, 0xCC), # CLKout Config
(0x113, 0x00), # CLKout Config
(0x114, 0x00), # CLKout Config
(0x115, 0x00), # CLKout Config
(0x116, 0xF9), # CLKout Config
(0x117, 0x00), # CLKout Config
(0x118, 0x78), # CLKout Config
- (0x119, 0x55), # CLKout Config
- (0x11A, 0x55), # CLKout Config
+ (0x119, 0xCC), # CLKout Config
+ (0x11A, 0xCC), # CLKout Config
(0x11B, 0x00), # CLKout Config
(0x11C, 0x20), # CLKout Config
(0x11D, 0x00), # CLKout Config
(0x11E, 0xF1), # CLKout Config
(0x11F, 0x00), # CLKout Config
(0x120, 0x78), # CLKout Config
- (0x121, 0x55), # CLKout Config
- (0x122, 0x55), # CLKout Config
+ (0x121, 0xCC), # CLKout Config
+ (0x122, 0xCC), # CLKout Config
(0x123, 0x00), # CLKout Config
- (0x124, 0x20), # CLKout Config
+ (0x124, 0x20), # CLKout Config 0x20 = SYSREF output, 0x00 = DEVCLK
(0x125, 0x00), # CLKout Config
- (0x126, 0xF2), # CLKout Config FPGA: (0xAB where A = SYSREF, B = CLK)
- (0x127, 0x55), # CLKout Config 0x15 = LVDS, 0x55 = LVPECL
+ (0x126, 0x72), # CLKout Config FPGA: (0xAB where A = SYSREF, B = CLK)
+ (0x127, 0x55), # CLKout Config 0x1 = LVDS, 0x5 = LVPECL
(0x128, 0x78), # CLKout Config
- (0x129, 0x55), # CLKout Config
- (0x12A, 0x55), # CLKout Config
+ (0x129, 0xCC), # CLKout Config
+ (0x12A, 0xCC), # CLKout Config
(0x12B, 0x00), # CLKout Config
(0x12C, 0x00), # CLKout Config
(0x12D, 0x00), # CLKout Config
- (0x12E, 0xF0), # CLKout Config
- (0x12F, 0x50), # CLKout Config
+ (0x12E, 0x72), # CLKout Config
+ (0x12F, 0xD0), # CLKout Config
(0x130, 0x78), # CLKout Config
- (0x131, 0x55), # CLKout Config
- (0x132, 0x55), # CLKout Config
+ (0x131, 0xCC), # CLKout Config
+ (0x132, 0xCC), # CLKout Config
(0x133, 0x00), # CLKout Config
(0x134, 0x20), # CLKout Config
(0x135, 0x00), # CLKout Config
@@ -128,6 +132,7 @@ class LMK04828Mg(LMK04828):
(0x147, 0x1A), # CLKin_SEL = CLKin1 manual; CLKin1 to PLL1
# (0x148, 0x01), # CLKin_SEL0 = input with pullup: previously written above!
(0x149, 0x01), # CLKin_SEL1 = input with pulldown
+ (0x14A, 0x02), # RESET type
(0x14B, 0x01), # Holdover & DAC Manual Mode
(0x14C, 0xF6), # DAC Manual Mode
(0x14D, 0x00), # DAC Settings (defaults)
@@ -190,3 +195,32 @@ class LMK04828Mg(LMK04828):
))
self.log.info("LMK init'd and locked!")
+ def lmk_shift(self, num_shifts=0):
+ """
+ Apply time shift
+ """
+ # TODO: these numbers need to be based off the radio clock freq.
+ self.log.trace("LMK04828 Clock Phase Shifting Commencing...")
+ ddly_value = 0xCD if num_shifts >= 0 else 0xCB
+ ddly_value_sysref_reg0 = 0x01
+ ddly_value_sysref_reg1 = 0xE1 if num_shifts >= 0 else 0xDF # 0xE0 is normal
+ self.pokes8((
+ (0x141, 0xB1), # Dynamic digital delay enable on outputs 0, 8, 10
+ (0x143, 0x53), # SYSREF_CLR; SYNC Enabled; SYNC from pulser @ regwrite
+ (0x139, 0x02), # SYSREF_MUX = Pulser
+ (0x101, ddly_value), # Set DDLY values for DCLKout0 +/-1 on low cnt.
+ (0x102, ddly_value), # Hidden register. Write the same as previous based on inc/dec.
+ (0x121, ddly_value), # Set DDLY values for DCLKout8 +/-1 on low cnt
+ (0x122, ddly_value), # Hidden register. Write the same as previous based on inc/dec.
+ (0x129, ddly_value), # Set DDLY values for DCLKout10 +/-1 on low cnt
+ (0x12A, ddly_value), # Hidden register. Write the same as previous based on inc/dec.
+ (0x13C, ddly_value_sysref_reg0), # SYSREF DDLY value
+ (0x13D, ddly_value_sysref_reg1), # SYSREF DDLY value
+ (0x144, 0x4E), # Enable SYNC on outputs 0, 8, 10
+ ))
+ for x in range(abs(num_shifts)):
+ self.poke8(0x142, 0x1)
+ # Put everything back the way it was before shifting.
+ self.poke8(0x144, 0xFF) # Disable SYNC on all outputs including SYSREF
+ # self.poke8(0x143, 0xD2) # Reset SYSREF engine to proper SYNC settings
+ self.poke8(0x143, 0x52) # Pulser selected; SYNC enabled; 1 shot enabled
diff --git a/mpm/python/usrp_mpm/dboard_manager/magnesium.py b/mpm/python/usrp_mpm/dboard_manager/magnesium.py
index 55a53b984..df573219d 100644
--- a/mpm/python/usrp_mpm/dboard_manager/magnesium.py
+++ b/mpm/python/usrp_mpm/dboard_manager/magnesium.py
@@ -28,6 +28,7 @@ from .. import nijesdcore
from ..uio import UIO
from ..mpmlog import get_logger
from .lmk_mg import LMK04828Mg
+from usrp_mpm.cores import ClockSynchronizer
def create_spidev_iface(dev_node):
"""
@@ -69,6 +70,20 @@ def create_spidev_iface_cpld(dev_node):
SPI_WRIT_FLAG
)
+def create_spidev_iface_phasedac(dev_node):
+ """
+ Create a regs iface from a spidev node (ADS5681)
+ """
+ return lib.spi.make_spidev_regs_iface(
+ str(dev_node),
+ 1000000, # Speed (Hz)
+ 1, # SPI mode
+ 16, # Addr shift
+ 0, # Data shift
+ 0, # Read flag
+ 0, # Write flag
+ )
+
class Magnesium(DboardManagerBase):
"""
Holds all dboard specific information and methods of the magnesium dboard
@@ -81,7 +96,18 @@ class Magnesium(DboardManagerBase):
pids = [0x150]
# Maps the chipselects to the corresponding devices:
- spi_chipselect = {"cpld": 0, "lmk": 1, "mykonos": 2}
+ spi_chipselect = {"cpld": 0, "lmk": 1, "mykonos": 2, "phase_dac": 3}
+ spi_factories = {
+ "cpld": create_spidev_iface_cpld,
+ "lmk": create_spidev_iface,
+ "mykonos": create_spidev_iface,
+ "phase_dac": create_spidev_iface_phasedac,
+ }
+
+ # DAC is initialized to midscale automatically on power-on: 16-bit DAC, so midpoint
+ # is at 2^15 = 32768. However, the linearity of the DAC is best just below that
+ # point, so we set it to the (carefully calculated) alternate value instead.
+ INIT_PHASE_DAC_WORD = 31000 # Intentionally decimal
def _get_mykonos_function(self, name):
mykfunc = getattr(self.mykonos, name)
@@ -95,6 +121,7 @@ class Magnesium(DboardManagerBase):
self.log = get_logger("Magnesium-{}".format(slot_idx))
self.log.trace("Initializing Magnesium daughterboard, slot index {}".format(self.slot_idx))
+ self.ref_clock_freq = 10e6 # TODO: make this not fixed
self.log.debug("Loading C++ drivers for CPLD SPI.")
self.cpld_regs = create_spidev_iface_cpld(self._spi_nodes['cpld'])
@@ -102,10 +129,6 @@ class Magnesium(DboardManagerBase):
self._device = lib.dboards.magnesium_manager(
self._spi_nodes['mykonos'],
)
- self.spi_lock = self._device.get_spi_lock()
- self.log.debug("Loading C++ drivers for LMK SPI.")
- self.clock_regs = create_spidev_iface(self._spi_nodes['lmk'])
- self.lmk = LMK04828Mg(self.clock_regs, self.spi_lock)
self.mykonos = self._device.get_radio_ctrl()
self.log.debug("Loaded C++ drivers.")
@@ -122,11 +145,31 @@ class Magnesium(DboardManagerBase):
Execute necessary init dance to bring up dboard
"""
+ def _init_spi_devices():
+ " Returns abstraction layers to all the SPI devices "
+ self.log.trace("Loading SPI interfaces...")
+ return {
+ key: self.spi_factories[key](self._spi_nodes[key])
+ for key in self._spi_nodes
+ }
def _init_clock_control(dboard_regs):
" Create a dboard clock control object and reset it "
dboard_clk_control = DboardClockControl(dboard_regs, self.log)
dboard_clk_control.reset_mmcm()
return dboard_clk_control
+ def _init_lmk(slot_idx, lmk_spi, ref_clk_freq,
+ pdac_spi, init_phase_dac_word):
+ """
+ Sets the phase DAC to initial value, and then brings up the LMK
+ according to the selected ref clock frequency.
+ Will throw if something fails.
+ """
+ self.log.trace("Initializing Phase DAC to d{}.".format(
+ init_phase_dac_word
+ ))
+ pdac_spi.poke16(0x0, init_phase_dac_word)
+ self.spi_lock = self._device.get_spi_lock()
+ return LMK04828Mg(lmk_spi, self.spi_lock, ref_clk_freq, slot_idx)
self.log.info("init() called with args `{}'".format(
@@ -134,12 +177,19 @@ class Magnesium(DboardManagerBase):
))
+ self._spi_ifaces = _init_spi_devices()
+ self.log.info("Loaded SPI interfaces!")
self.dboard_clk_control = _init_clock_control(self.radio_regs)
- self.lmk.init()
- self.lmk.config()
+ self.lmk = _init_lmk(
+ self.slot_idx,
+ self._spi_ifaces['lmk'],
+ self.ref_clock_freq,
+ self._spi_ifaces['phase_dac'],
+ self.INIT_PHASE_DAC_WORD,
+ )
self.dboard_clk_control.enable_mmcm()
- self.log.info("Clocking Configured Successfully!")
+ self.log.info("Sample Clocks and Phase DAC Configured Successfully!")
self.init_jesd(self.radio_regs)