diff options
author | DJ Epson <daniel.jepson@ni.com> | 2017-09-01 15:20:09 -0700 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2017-12-22 15:04:01 -0800 |
commit | f141f71180e397fa21d23385f154da138bef0a81 (patch) | |
tree | dd68c27564157cbe8ecaac0056008ec286ddd704 | |
parent | 04b0f414b9235d36e7572b8c6644630d77de4aab (diff) | |
download | uhd-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.py | 212 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/dboard_manager/magnesium.py | 177 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/nijesdcore.py | 12 |
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. |