aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDJ Epson <daniel.jepson@ni.com>2017-09-01 15:20:09 -0700
committerMartin Braun <martin.braun@ettus.com>2017-12-22 15:04:01 -0800
commitf141f71180e397fa21d23385f154da138bef0a81 (patch)
treedd68c27564157cbe8ecaac0056008ec286ddd704
parent04b0f414b9235d36e7572b8c6644630d77de4aab (diff)
downloaduhd-f141f71180e397fa21d23385f154da138bef0a81.tar.gz
uhd-f141f71180e397fa21d23385f154da138bef0a81.tar.bz2
uhd-f141f71180e397fa21d23385f154da138bef0a81.zip
mpm: Streaming-related improvements to Magnesium controls
-rw-r--r--mpm/python/usrp_mpm/dboard_manager/lmk_mg.py212
-rw-r--r--mpm/python/usrp_mpm/dboard_manager/magnesium.py177
-rw-r--r--mpm/python/usrp_mpm/nijesdcore.py12
3 files changed, 320 insertions, 81 deletions
diff --git a/mpm/python/usrp_mpm/dboard_manager/lmk_mg.py b/mpm/python/usrp_mpm/dboard_manager/lmk_mg.py
index 6c2660521..b295874a1 100644
--- a/mpm/python/usrp_mpm/dboard_manager/lmk_mg.py
+++ b/mpm/python/usrp_mpm/dboard_manager/lmk_mg.py
@@ -18,7 +18,7 @@
LMK04828 driver for use with Magnesium
"""
-from time import sleep
+import time
from builtins import zip
from builtins import hex
from ..mpmlog import get_logger
@@ -33,66 +33,160 @@ class LMK04828Mg(LMK04828):
assert hasattr(self.spi_lock, 'unlock')
def init(self):
- # Reset the LMK
- self.log.trace("lock?")
- self.spi_lock.lock()
- self.log.trace("locked")
-
- addrs = (0x000, 0x000, 0x002, 0x14A)
- vals = (0x90, 0x10, 0x00, 0x33)
-
- for addr, val in zip(addrs, vals):
- #self.log.trace("send {0}, {1}".format(hex(addr), hex(val),))
- self.regs_iface.poke8(addr, val)
-
- # Re-verify chip ID
- self.log.trace("check chip id")
+ """
+ Basic init. Turns it on. Let's read SPI.
+ """
+ self.log.info("Reset LMK & Verify")
+ self.pokes8((
+ (0x000, 0x90), # Assert reset
+ (0x000, 0x10), # De-assert reset
+ (0x002, 0x00), # De-assert power down
+ (0x148, 0x33), # Clock Select as SDO
+ ))
if not self.verify_chip_id():
raise Exception("Unable to locate LMK04828")
- # Write the configuration (10 MHz reference, 125 MHz outputs)
- addrs = (0x100, 0x101, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10B, 0x10C, 0x10D, 0x10E, 0x10F, 0x110, 0x111, 0x113, 0x114, 0x115, 0x116, 0x117, 0x118, 0x119, 0x11B, 0x11C, 0x11D, 0x11E, 0x11F, 0x120, 0x121, 0x123, 0x124, 0x125, 0x126, 0x127, 0x128, 0x129, 0x12B, 0x12C, 0x12D, 0x12E, 0x12F, 0x130, 0x131, 0x133, 0x134, 0x135, 0x136, 0x137, 0x138, 0x139, 0x13A, 0x13B, 0x13C, 0x13D, 0x13E, 0x13F, 0x140, 0x141, 0x142, 0x143, 0x144, 0x145, 0x146, 0x147, 0x148, 0x149, 0x14B, 0x14C, 0x14D, 0x14E, 0x14F, 0x150, 0x151, 0x152, 0x153, 0x154, 0x155, 0x156, 0x157, 0x158, 0x159, 0x15A, 0x15B, 0x15C, 0x15D, 0x15E, 0x15F, 0x160, 0x161, 0x162, 0x163, 0x164, 0x165, 0x171, 0x172, 0x17C, 0x17D, 0x166, 0x167, 0x168, 0x169, 0x16A, 0x16B, 0x16C, 0x16D, 0x16E, 0x173)
- vals = (0x78, 0x55, 0x00, 0x20, 0x00, 0xF2, 0x55, 0x7E, 0x55, 0x00, 0x00, 0x00, 0xF0, 0x55, 0x61, 0x55, 0x00, 0x00, 0x00, 0xF9, 0x00, 0x78, 0x55, 0x00, 0x20, 0x00, 0xF1, 0x00, 0x78, 0x55, 0x00, 0x20, 0x00, 0xF2, 0x55, 0x78, 0x55, 0x00, 0x00, 0x00, 0xF0, 0x50, 0x78, 0x55, 0x00, 0x20, 0x00, 0xF1, 0x05, 0x30, 0x00, 0x01, 0xE0, 0x00, 0x08, 0x00, 0x09, 0x00, 0x00, 0x00, 0xD1, 0x00, 0x7F, 0x10, 0x1A, 0x01, 0x01, 0x01, 0xF6, 0x00, 0x00, 0x7F, 0x03, 0x02, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x01, 0x00, 0x7D, 0xCF, 0x03, 0xE8, 0x00, 0x0B, 0x00, 0x04, 0xA4, 0x00, 0x00, 0x19, 0xAA, 0x02, 0x15, 0x33, 0x00, 0x00, 0x19, 0x51, 0x27, 0x10, 0x00, 0x00, 0x13, 0x00)
-
- self.log.trace("send init sequence")
- for addr, val in zip(addrs, vals):
- self.regs_iface.poke8(addr, val)
-
- self.spi_lock.unlock()
- sleep(0.1)
- self.spi_lock.lock()
-
- # Clear Lock Detect Sticky
- self.log.trace("clear lock sticky")
- addrs = (0x182, 0x182, 0x183, 0x183)
- vals = (0x01, 0x00, 0x01, 0x00)
-
- for addr, val in zip(addrs, vals):
- self.regs_iface.poke8(addr, val)
-
- self.spi_lock.unlock()
- sleep(0.1)
- self.spi_lock.lock()
-
- # Check Lock Detects
- self.log.trace("check lock status")
- pll1_lock_status = self.regs_iface.peek8(0x182)
- pll2_lock_status = self.regs_iface.peek8(0x183)
-
- if not pll1_lock_status == 0x02:
- self.log.error("LMK PLL1 did not lock. Status {0}".format(hex(pll1_lock_status)))
-
- if not pll2_lock_status == 0x02:
- self.log.error("LMK PLL2 did not lock. Status {0}".format(hex(pll2_lock_status)))
-
- # Toggle SYNC polarity to trigger SYNC event
- self.regs_iface.poke8(0x143, 0xF1)
- self.regs_iface.poke8(0x143, 0xD1)
- # Enable SYSREF pulses
- self.regs_iface.poke8(0x139, 0x02)
- self.regs_iface.poke8(0x144, 0xFF)
- self.regs_iface.poke8(0x143, 0x52)
- self.spi_lock.unlock()
- self.log.trace("LMK init'd and locked")
+ def config(self):
+ """
+ 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
+ self.pokes8((
+ (0x100, 0x78), # CLKout Config
+ (0x101, 0x55), # CLKout Config
+ (0x102, 0x55), # 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)
+ (0x107, 0x15), # CLKout Config 0x15 = LVDS, 0x55 = LVPECL
+ (0x108, 0x7E), # CLKout Config
+ (0x109, 0x55), # CLKout Config
+ (0x10A, 0x55), # CLKout Config
+ (0x10B, 0x00), # CLKout Config
+ (0x10C, 0x00), # CLKout Config
+ (0x10D, 0x00), # CLKout Config
+ (0x10E, 0xF0), # CLKout Config
+ (0x10F, 0x55), # CLKout Config
+ (0x110, 0x61), # CLKout Config
+ (0x111, 0x55), # CLKout Config
+ (0x112, 0x55), # 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
+ (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
+ (0x123, 0x00), # CLKout Config
+ (0x124, 0x20), # CLKout Config
+ (0x125, 0x00), # CLKout Config
+ (0x126, 0xF2), # CLKout Config FPGA: (0xAB where A = SYSREF, B = CLK)
+ (0x127, 0x55), # CLKout Config 0x15 = LVDS, 0x55 = LVPECL
+ (0x128, 0x78), # CLKout Config
+ (0x129, 0x55), # CLKout Config
+ (0x12A, 0x55), # CLKout Config
+ (0x12B, 0x00), # CLKout Config
+ (0x12C, 0x00), # CLKout Config
+ (0x12D, 0x00), # CLKout Config
+ (0x12E, 0xF0), # CLKout Config
+ (0x12F, 0x50), # CLKout Config
+ (0x130, 0x78), # CLKout Config
+ (0x131, 0x55), # CLKout Config
+ (0x132, 0x55), # CLKout Config
+ (0x133, 0x00), # CLKout Config
+ (0x134, 0x20), # CLKout Config
+ (0x135, 0x00), # CLKout Config
+ (0x136, 0xF1), # CLKout Config
+ (0x137, 0x05), # CLKout Config
+ (0x138, 0x30), # VCO_MUX to VCO 1; OSCout off
+ (0x139, 0x00), # SYSREF Source = MUX; SYSREF MUX = Normal SYNC
+ (0x13A, 0x01), # SYSREF Divide [12:8]
+ (0x13B, 0xE0), # SYSREF Divide [7:0]
+ (0x13C, 0x00), # SYSREF DDLY [12:8]
+ (0x13D, 0x08), # SYSREF DDLY [7:0] ... 8 is default, <8 is reserved
+ (0x13E, 0x00), # SYSREF Pulse Count = 1 pulse/request
+ (0x13F, 0x09), # Feedback Mux: Enabled, DCLKout6, drives PLL1N divider
+ (0x140, 0x00), # POWERDOWN options
+ (0x141, 0x00), # Dynamic digital delay enable
+ (0x142, 0x00), # Dynamic digital delay step
+ (0x143, 0xD1), # SYNC edge sensitive; SYSREF_CLR; SYNC Enabled; SYNC from pin no pulser
+ (0x144, 0x00), # Enable SYNC on all outputs including sysref
+ (0x145, 0x7F), # Always program to d127
+ (0x146, 0x10), # CLKin Type & En
+ (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
+ (0x14B, 0x01), # Holdover & DAC Manual Mode
+ (0x14C, 0xF6), # DAC Manual Mode
+ (0x14D, 0x00), # DAC Settings (defaults)
+ (0x14E, 0x00), # DAC Settings (defaults)
+ (0x14F, 0x7F), # DAC Settings (defaults)
+ (0x150, 0x03), # Holdover Settings (defaults)
+ (0x151, 0x02), # Holdover Settings (defaults)
+ (0x152, 0x00), # Holdover Settings (defaults)
+ (0x153, 0x00), # CLKin0_R divider [13:8], default = 0
+ (0x154, clkin0_r_divider), # CLKin0_R divider [7:0], default = d120
+ (0x155, 0x00), # CLKin1_R divider [13:8], default = 0
+ (0x156, clkin0_r_divider), # CLKin1_R divider [7:0], default = d120
+ (0x157, 0x00), # CLKin2_R divider [13:8], default = 0
+ (0x158, 0x01), # CLKin2_R divider [7:0], default = d120
+ (0x159, 0x00), # PLL1 N divider [13:8], default = 0
+ (0x15A, 0x7D), # PLL1 N divider [7:0], default = d120
+ (0x15B, 0xCF), # PLL1 PFD
+ (0x15C, 0x27), # PLL1 DLD Count [13:8]
+ (0x15D, 0x10), # PLL1 DLD Count [7:0]
+ (0x15E, 0x00), # PLL1 R/N delay, defaults = 0
+ (0x15F, 0x0B), # Status LD1 pin = PLL1 LD, push-pull output
+ (0x160, 0x00), # PLL2 R divider [11:8];
+ (0x161, 0x04), # PLL2 R divider [7:0]
+ (0x162, 0xA4), # PLL2 prescaler; OSCin freq
+ (0x163, 0x00), # PLL2 Cal = PLL2 normal val
+ (0x164, 0x00), # PLL2 Cal = PLL2 normal val
+ (0x165, 0x19), # PLL2 Cal = PLL2 normal val
+ (0x171, 0xAA), # Write this val after x165
+ (0x172, 0x02), # Write this val after x165
+ (0x17C, 0x15), # VCo1 Cal; write before x168
+ (0x17D, 0x33), # VCo1 Cal; write before x168
+ (0x166, 0x00), # PLL2 N[17:16]
+ (0x167, 0x00), # PLL2 N[15:8]
+ (0x168, 0x19), # PLL2 N[7:0]
+ (0x169, 0x51), # PLL2 PFD
+ (0x16A, 0x27), # PLL2 DLD Count [13:8] = default d32
+ (0x16B, 0x10), # PLL2 DLD Count [7:0] = default d0
+ (0x16C, 0x00), # PLL2 Loop filter r = 200 ohm
+ (0x16D, 0x00), # PLL2 loop filter c = 10 pF
+ (0x16E, 0x13), # Status LD2 pin = Output push-pull, PLL2 DLD
+ (0x173, 0x00), # Do not power down PLL2 or prescaler
+ ))
+ time.sleep(1.0) # Increased time to wait for DAC and VCXO to settle.
+ self.pokes8((
+ (0x182, 0x1), # Clear Lock Detect Sticky
+ (0x182, 0x0), # Clear Lock Detect Sticky
+ (0x183, 0x1), # Clear Lock Detect Sticky
+ (0x183, 0x0), # Clear Lock Detect Sticky
+ ))
+ time.sleep(0.1)
+ if not self.check_plls_locked():
+ raise RuntimeError("At least one LMK PLL did not lock! Check the logs for details.")
+ self.log.trace("Setting SYNC and SYSREF config...")
+ self.pokes8((
+ (0x143, 0xF1), # toggle SYNC polarity to trigger SYNC event
+ (0x143, 0xD1), # toggle SYNC polarity to trigger SYNC event
+ (0x139, 0x02), # SYSREF Source = MUX; SYSREF MUX = pulser
+ (0x144, 0xFF), # Disable SYNC on all outputs including sysref
+ (0x143, 0x52), # Pulser selected; SYNC enabled; 1 shot enabled
+ ))
+ self.log.info("LMK init'd and locked!")
diff --git a/mpm/python/usrp_mpm/dboard_manager/magnesium.py b/mpm/python/usrp_mpm/dboard_manager/magnesium.py
index 536503b62..55a53b984 100644
--- a/mpm/python/usrp_mpm/dboard_manager/magnesium.py
+++ b/mpm/python/usrp_mpm/dboard_manager/magnesium.py
@@ -49,6 +49,26 @@ def create_spidev_iface(dev_node):
SPI_WRIT_FLAG
)
+def create_spidev_iface_cpld(dev_node):
+ """
+ Create a regs iface from a spidev node
+ """
+ SPI_SPEED_HZ = 1000000
+ SPI_MODE = 0
+ SPI_ADDR_SHIFT = 16
+ SPI_DATA_SHIFT = 0
+ SPI_READ_FLAG = 1<<23
+ SPI_WRIT_FLAG = 0
+ return lib.spi.make_spidev_regs_iface(
+ dev_node,
+ SPI_SPEED_HZ,
+ SPI_MODE,
+ SPI_ADDR_SHIFT,
+ SPI_DATA_SHIFT,
+ SPI_READ_FLAG,
+ SPI_WRIT_FLAG
+ )
+
class Magnesium(DboardManagerBase):
"""
Holds all dboard specific information and methods of the magnesium dboard
@@ -61,36 +81,92 @@ class Magnesium(DboardManagerBase):
pids = [0x150]
# Maps the chipselects to the corresponding devices:
- spi_chipselect = {"lmk": 0, "mykonos": 1}
+ spi_chipselect = {"cpld": 0, "lmk": 1, "mykonos": 2}
+
+ def _get_mykonos_function(self, name):
+ mykfunc = getattr(self.mykonos, name)
+ def func(*args):
+ return mykfunc(*args)
+ func.__doc__ = mykfunc.__doc__
+ return func
def __init__(self, slot_idx, **kwargs):
super(Magnesium, self).__init__(slot_idx, **kwargs)
self.log = get_logger("Magnesium-{}".format(slot_idx))
self.log.trace("Initializing Magnesium daughterboard, slot index {}".format(self.slot_idx))
- def init(self, args):
- """
- Execute necessary init dance to bring up dboard
- """
- self.log.info("init() called with args `{}'".format(
- ",".join(['{}={}'.format(x, args[x]) for x in args])
- ))
- self.clock_regs = create_spidev_iface(self._spi_nodes['lmk'])
+ self.log.debug("Loading C++ drivers for CPLD SPI.")
+ self.cpld_regs = create_spidev_iface_cpld(self._spi_nodes['cpld'])
+
self.log.debug("Loading C++ drivers...")
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.")
- self.lmk = LMK04828Mg(self.clock_regs, self.spi_lock)
self.log.debug("Getting Mg A uio...")
- self.radio_regs = UIO(label="jesd204b-regs", read_only=False)
+ self.radio_regs = UIO(label="dboard-regs-0", read_only=False)
self.log.info("Radio-register UIO object successfully generated!")
+
+ for mykfuncname in [x for x in dir(self.mykonos) if not x.startswith("_") and callable(getattr(self.mykonos, x))]:
+ self.log.trace("adding {}".format(mykfuncname))
+ setattr(self, mykfuncname, self._get_mykonos_function(mykfuncname))
+
+ def init(self, args):
+ """
+ Execute necessary init dance to bring up dboard
+ """
+
+ 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
+
+
+ self.log.info("init() called with args `{}'".format(
+ ",".join(['{}={}'.format(x, args[x]) for x in args])
+ ))
+
+
+ self.dboard_clk_control = _init_clock_control(self.radio_regs)
+
+ self.lmk.init()
+ self.lmk.config()
+ self.dboard_clk_control.enable_mmcm()
+ self.log.info("Clocking Configured Successfully!")
+
self.init_jesd(self.radio_regs)
+
+ self.mykonos.start_radio()
+
return True
+
+
+ def cpld_peek16(self, addr):
+ return self.cpld_regs.peek16(addr)
+
+ def cpld_poke16(self, addr, data):
+ return self.cpld_regs.poke16(addr, data)
+
+ def lmk_peek(self, addr):
+ return self.lmk.peek8(addr)
+
+ def lmk_poke(self, addr, data):
+ return self.lmk.poke8(addr, data)
+
+ def lmk_setup_dbg(self):
+ self.lmk.init()
+ self.lmk.config()
+ return "LMK Init Success"
+
+
def init_jesd(self, uio):
"""
Bring up the JESD link between Mykonos and the N310
@@ -101,16 +177,17 @@ class Magnesium(DboardManagerBase):
self.log.trace("Checking JESD core...")
self.jesdcore.check_core()
self.log.trace("Initializing LMK...")
- self.lmk.init()
- self.radio_regs.poke32(0x2078, 0xA000040)
- self.log.trace("Verify LMK Chip ID...")
- self.lmk.verify_chip_id()
- self.jesdcore.unreset_mmcm()
+ self.jesdcore.unreset_qpll()
self.jesdcore.init()
self.log.trace("Resetting Mykonos...")
- self.jesdcore.reset_mykonos() #not sure who owns the reset
+
+ # YIKES!!! Where does this go?!? CPLD?
+ # self.jesdcore.reset_mykonos() #not sure who owns the reset
+ self.cpld_poke16(0x13, 0x1)
+ self.cpld_poke16(0x13, 0x0)
+
self.log.trace("Initializing Mykonos...")
self.mykonos.begin_initialization()
@@ -134,12 +211,15 @@ class Magnesium(DboardManagerBase):
time.sleep(0.2)
if not self.jesdcore.get_framer_status():
raise Exception('JESD Core Framer is not synced!')
+ if ((self.mykonos.get_deframer_status() & 0x7F) != 0x28):
+ raise Exception('Mykonos Deframer is not synced!')
if not self.jesdcore.get_deframer_status():
raise Exception('JESD Core Deframer is not synced!')
- if (self.mykonos.get_framer_status() & 0xFF != 0x3E):
+ if (self.mykonos.get_framer_status() & 0xFF) != 0x3E:
raise Exception('Mykonos Framer is not synced!')
- if (self.mykonos.get_deframer_status() & 0x7F != 0x28):
- raise Exception('Mykonos Deframer is not synced!')
+ if (self.mykonos.get_multichip_sync_status() & 0xB) != 0xB:
+ raise Exception('Mykonos multi chip sync failed!')
+
self.log.trace("JESD fully synced and ready")
def dump_jesd_core(self):
@@ -149,3 +229,60 @@ class Magnesium(DboardManagerBase):
print(("%08X" % self.radio_regs.peek32(i + j)), end=' ')
print("")
+
+
+class DboardClockControl(object):
+ """
+ Control the FPGA MMCM for Radio Clock control.
+ """
+ # Clocking Register address constants
+ RADIO_CLK_MMCM = 0x0020
+ PHASE_SHIFT_CONTROL = 0x0024
+ RADIO_CLK_ENABLES = 0x0028
+ MGT_REF_CLK_STATUS = 0x0030
+
+ def __init__(self, regs, log):
+ self.log = log
+ self.regs = regs
+ self.poke32 = self.regs.poke32
+ self.peek32 = self.regs.peek32
+
+ def enable_outputs(self, enable=True):
+ """
+ Enables or disables the MMCM outputs.
+ """
+ if enable:
+ self.poke32(self.RADIO_CLK_ENABLES, 0x011)
+ else:
+ self.poke32(self.RADIO_CLK_ENABLES, 0x000)
+
+ def reset_mmcm(self):
+ """
+ Uninitialize and reset the MMCM
+ """
+ self.log.trace("Disabling all Radio Clocks, then resetting MMCM...")
+ self.enable_outputs(False)
+ self.poke32(self.RADIO_CLK_MMCM, 0x1)
+
+ def enable_mmcm(self):
+ """
+ Unreset MMCM and poll lock indicators
+
+ If MMCM is not locked after unreset, an exception is thrown.
+ """
+ self.log.trace("Un-resetting MMCM...")
+ self.poke32(self.RADIO_CLK_MMCM, 0x2)
+ time.sleep(0.5) # Replace with poll and timeout TODO
+ mmcm_locked = bool(self.peek32(self.RADIO_CLK_MMCM) & 0x10)
+ if not mmcm_locked:
+ self.log.error("MMCM not locked!")
+ raise RuntimeError("MMCM not locked!")
+ self.log.trace("Enabling output MMCM clocks...")
+ self.enable_outputs(True)
+
+ def check_refclk(self):
+ """
+ Not technically a clocking reg, but related.
+ """
+ return bool(self.peek32(self.MGT_REF_CLK_STATUS) & 0x1)
+
diff --git a/mpm/python/usrp_mpm/nijesdcore.py b/mpm/python/usrp_mpm/nijesdcore.py
index b3f6af355..cb59f40ed 100644
--- a/mpm/python/usrp_mpm/nijesdcore.py
+++ b/mpm/python/usrp_mpm/nijesdcore.py
@@ -38,7 +38,7 @@ class NIMgJESDCore(object):
assert hasattr(self.regs, 'peek32')
assert hasattr(self.regs, 'poke32')
- def unreset_mmcm(self):
+ def unreset_qpll(self):
# new_val = self.regs.peek32(0x0) & ~0x8
# self.log.trace("Unresetting MMCM, writing value {:X}".format(new_val))
self.regs.poke32(0x0, 0x7)
@@ -52,6 +52,7 @@ class NIMgJESDCore(object):
raise Exception('JESD Core signature mismatch! Check that core is mapped correctly')
#if self.regs.peek32(0x2104) != 0xFF
#error here for date revision mismatch
+ self.log.trace("JESD Core build code: {0}".format(hex(self.regs.peek32(0x2104))))
return True
def init_deframer(self):
@@ -85,6 +86,12 @@ class NIMgJESDCore(object):
" Return True if deframer is in good status "
rb = self.regs.peek32(0x2040)
self.log.trace("Returning deframer status: {0}".format(hex(rb & 0xFFFFFFFF)))
+ if rb & 0b100 == 0b0:
+ self.log.warning("Deframer warning: Code Group Sync failed to complete!")
+ elif rb & 0b1000 == 0b0:
+ self.log.warning("Deframer warning: Channel Bonding failed to complete!")
+ elif rb & 0x200000 == 0b1:
+ self.log.warning("Deframer warning: Misc error!")
return rb & 0xFFFFFFFF == 0xF000001C
def init(self):
@@ -96,7 +103,8 @@ class NIMgJESDCore(object):
self._gt_reset('tx', reset_only=True)
self._gt_reset('rx', reset_only=True)
self._gt_pll_lock_control()
-
+ self.regs.poke32(0x2078, 0x40)
+
def enable_lmfc(self):
"""
Enable LMFC generator in FPGA. This step is woefully incomplete, but this call will work for now.