diff options
author | djepson1 <daniel.jepson@ni.com> | 2017-10-09 11:26:20 -0500 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2017-12-22 15:04:02 -0800 |
commit | 4e0600b00a053b23dadd02ac99d89db9d50e1f34 (patch) | |
tree | 0cabfacab9bc9494000a0a57d8ac4109f8aafc83 /mpm | |
parent | 6858b05357c8d5a84334d06d1b7ccf607deb42d3 (diff) | |
download | uhd-4e0600b00a053b23dadd02ac99d89db9d50e1f34.tar.gz uhd-4e0600b00a053b23dadd02ac99d89db9d50e1f34.tar.bz2 uhd-4e0600b00a053b23dadd02ac99d89db9d50e1f34.zip |
mg: Updated JESD204b init seq and documentation.
- Based on feedback from ADI, updated SYSREF sequencing for
meeting deterministic latency requirements.
- Changed majority of register addresses in nijesdcore.py to
constants.
- Corrected write data to SYSREF_CAPTURE_CONTROL to produce
the correct SYSREF toggle rate inside the FPGA.
Signed-off-by: djepson1 <daniel.jepson@ni.com>
Diffstat (limited to 'mpm')
-rw-r--r-- | mpm/python/usrp_mpm/dboard_manager/magnesium.py | 62 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/nijesdcore.py | 44 |
2 files changed, 65 insertions, 41 deletions
diff --git a/mpm/python/usrp_mpm/dboard_manager/magnesium.py b/mpm/python/usrp_mpm/dboard_manager/magnesium.py index bf0bc0409..7dc1f4b29 100644 --- a/mpm/python/usrp_mpm/dboard_manager/magnesium.py +++ b/mpm/python/usrp_mpm/dboard_manager/magnesium.py @@ -273,64 +273,76 @@ class Magnesium(DboardManagerBase): def init_jesd(self, uio): """ - Bring up the JESD link between Mykonos and the N310 + Bring up the JESD link between Mykonos and the N310. """ - self.log.trace("Creating jesdcore object") - self.jesdcore = nijesdcore.NIMgJESDCore(uio) + # CPLD Register Definition + MYKONOS_CONTROL = 0x13 - self.log.trace("Checking JESD core...") + self.log.trace("Creating jesdcore object") + self.jesdcore = nijesdcore.NIMgJESDCore(uio, self.slot_idx) self.jesdcore.check_core() - self.log.trace("Initializing LMK...") self.jesdcore.unreset_qpll() - self.jesdcore.init() - self.log.trace("Resetting Mykonos...") - - # 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("Pulsing Mykonos Hard Reset...") + self.cpld_regs.poke16(MYKONOS_CONTROL, 0x1) + time.sleep(0.001) # No spec here, but give it some time to reset. + self.cpld_regs.poke16(MYKONOS_CONTROL, 0x0) + time.sleep(0.001) # No spec here, but give it some time to enable. self.log.trace("Initializing Mykonos...") self.mykonos.begin_initialization() + # Multi-chip Sync requires two SYSREF pulses at least 17us apart. self.jesdcore.send_sysref_pulse() + time.sleep(0.001) self.jesdcore.send_sysref_pulse() self.mykonos.finish_initialization() - self.log.trace("Starting Mykonos framer...") - self.mykonos.start_jesd_tx() - self.jesdcore.send_sysref_pulse() - self.log.trace("Resetting FPGA deframer...") - self.jesdcore.init_deframer() - self.log.trace("Resetting FPGA framer...") + self.log.trace("Starting JESD204b Link Initialization...") + # Generally, enable the source before the sink. Start with the DAC side. + self.log.trace("Starting FPGA framer...") self.jesdcore.init_framer() self.log.trace("Starting Mykonos deframer...") self.mykonos.start_jesd_rx() - - self.log.trace("Enable LMFC and send") + # Now for the ADC link. Note that the Mykonos framer will not start issuing CGS + # characters until SYSREF is received by the framer. Therefore we enable the + # framer in Mykonos and the FPGA, send a SYSREF pulse to everyone, and then + # start the deframer in the FPGA. + self.log.trace("Starting Mykonos framer...") + self.mykonos.start_jesd_tx() + self.log.trace("Enable FPGA SYSREF Receiver.") self.jesdcore.enable_lmfc() self.jesdcore.send_sysref_pulse() - time.sleep(0.2) + self.log.trace("Starting FPGA deframer...") + self.jesdcore.init_deframer() + + # Allow a bit of time for CGS/ILA to complete. + time.sleep(0.100) + if not self.jesdcore.get_framer_status(): + self.log.error("FPGA Framer Error!") raise Exception('JESD Core Framer is not synced!') if ((self.mykonos.get_deframer_status() & 0x7F) != 0x28): + self.log.error("Mykonos Deframer Error: 0x{:X}".format((self.mykonos.get_deframer_status() & 0x7F))) raise Exception('Mykonos Deframer is not synced!') if not self.jesdcore.get_deframer_status(): + self.log.error("FPGA Deframer Error!") raise Exception('JESD Core Deframer is not synced!') - if (self.mykonos.get_framer_status() & 0xFF) != 0x3E: + if ((self.mykonos.get_framer_status() & 0xFF) != 0x3E): + self.log.error("Mykonos Framer Error: 0x{:X}".format((self.mykonos.get_framer_status() & 0xFF))) raise Exception('Mykonos Framer is not synced!') - if (self.mykonos.get_multichip_sync_status() & 0xB) != 0xB: + if ((self.mykonos.get_multichip_sync_status() & 0xB) != 0xB): raise Exception('Mykonos multi chip sync failed!') + self.log.info("JESD204B Link Initialization & Training Complete") - self.log.trace("JESD fully synced and ready") def dump_jesd_core(self): + radio_regs = UIO(label="dboard-regs-{}".format(self.slot_idx)) for i in range(0x2000, 0x2110, 0x10): print(("0x%04X " % i), end=' ') for j in range(0, 0x10, 0x4): - print(("%08X" % self.radio_regs.peek32(i + j)), end=' ') + print(("%08X" % radio_regs.peek32(i + j)), end=' ') print("") diff --git a/mpm/python/usrp_mpm/nijesdcore.py b/mpm/python/usrp_mpm/nijesdcore.py index 519f7822c..c3f1342db 100644 --- a/mpm/python/usrp_mpm/nijesdcore.py +++ b/mpm/python/usrp_mpm/nijesdcore.py @@ -31,6 +31,17 @@ class NIMgJESDCore(object): Arguments: regs -- regs class to use for peek/poke """ + + MGT_RECEIVER_CONTROL = 0x2040 + MGT_RX_DESCRAMBLER_CONTROL = 0x2050 + MGT_TRANSMITTER_CONTROL = 0x2060 + MGT_TX_TRANSCEIVER_CONTROL = 0x2064 + MGT_TX_SCRAMBLER_CONTROL = 0x2068 + SYSREF_CAPTURE_CONTROL = 0x2078 + JESD_SIGNATURE_REG = 0x2100 + JESD_REVISION_REG = 0x2104 + + def __init__(self, regs, slot_idx=0): self.regs = regs self.log = get_logger("NIMgJESDCore-{}".format(slot_idx)) @@ -47,11 +58,11 @@ class NIMgJESDCore(object): Verify JESD core returns correct ID """ self.log.trace("Checking JESD Core...") - if self.regs.peek32(0x2100) != 0x4A455344: + if self.regs.peek32(self.JESD_SIGNATURE_REG) != 0x4A455344: raise Exception('JESD Core signature mismatch! Check that core is mapped correctly') - #if self.regs.peek32(0x2104) != 0xFF + #if self.regs.peek32(JESD_REVISION_REG) != 0xFF #error here for date revision mismatch - self.log.trace("JESD Core build code: {0}".format(hex(self.regs.peek32(0x2104)))) + self.log.trace("JESD Core build code: {0}".format(hex(self.regs.peek32(self.JESD_REVISION_REG)))) self.log.trace("DB Slot #: {}".format( (self.regs.peek32(0x630) & 0x10000) >> 16 )) self.log.trace("DB PID: {:X}".format( self.regs.peek32(0x630) & 0xFFFF )) return True @@ -59,34 +70,34 @@ class NIMgJESDCore(object): def init_deframer(self): " Initialize deframer " self.log.trace("Initializing deframer...") - self.regs.poke32(0x2040, 0x2) - self.regs.poke32(0x2050, 0x0) + self.regs.poke32(self.MGT_RECEIVER_CONTROL, 0x2) + self.regs.poke32(self.MGT_RX_DESCRAMBLER_CONTROL, 0x0) self._gt_reset('rx', reset_only=False) - self.regs.poke32(0x2040, 0x0) + self.regs.poke32(self.MGT_RECEIVER_CONTROL, 0x0) def init_framer(self): " Initialize framer " self.log.trace("Initializing framer...") # Disable DAC Sync from requesting CGS & Stop Deframer - self.regs.poke32(0x2060, 0x2002) + self.regs.poke32(self.MGT_TRANSMITTER_CONTROL, 0x2002) # Reset, unreset, and check the GTs self._gt_reset('tx', reset_only=False) # MGT phy control... enable TX Driver Swing - self.regs.poke32(0x2064, 0xF0000) + self.regs.poke32(self.MGT_TX_TRANSCEIVER_CONTROL, 0xF0000) time.sleep(0.001) # Bypass scrambler and disable char replacement - self.regs.poke32(0x2068, 0x1) + self.regs.poke32(self.MGT_TX_SCRAMBLER_CONTROL, 0x1) # Check for Framer in Idle state - rb = self.regs.peek32(0x2060) + rb = self.regs.peek32(self.MGT_TRANSMITTER_CONTROL) if rb & 0x100 != 0x100: raise Exception('TX Framer is not idle after reset') # Enable the framer and incoming DAC Sync - self.regs.poke32(0x2060, 0x1000) - self.regs.poke32(0x2060, 0x0001) + self.regs.poke32(self.MGT_TRANSMITTER_CONTROL, 0x1000) + self.regs.poke32(self.MGT_TRANSMITTER_CONTROL, 0x0001) def get_framer_status(self): " Return True if framer is in good status " - rb = self.regs.peek32(0x2060) + rb = self.regs.peek32(self.MGT_TRANSMITTER_CONTROL) self.log.trace("FPGA Framer status: {0}".format(hex(rb & 0xFF0))) if rb & (0b1 << 8) == 0b1 << 8: self.log.warning("Framer warning: Framer is Idle!") @@ -98,7 +109,7 @@ class NIMgJESDCore(object): def get_deframer_status(self): " Return True if deframer is in good status " - rb = self.regs.peek32(0x2040) + rb = self.regs.peek32(self.MGT_RECEIVER_CONTROL) self.log.trace("FPGA Deframer status: {0}".format(hex(rb & 0xFFFFFFFF))) if rb & (0b1 << 2) == 0b0 << 2: self.log.warning("Deframer warning: Code Group Sync failed to complete!") @@ -117,13 +128,14 @@ 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) + # Disable SYSREF Sampler + self.regs.poke32(self.SYSREF_CAPTURE_CONTROL, 0x9800040) def enable_lmfc(self): """ Enable LMFC generator in FPGA. This step is woefully incomplete, but this call will work for now. """ - self.regs.poke32(0x2078, 0) + self.regs.poke32(self.SYSREF_CAPTURE_CONTROL, 0x9800000) def send_sysref_pulse(self): """ |