mirror of
https://github.com/saymrwulf/uhd.git
synced 2026-05-16 21:10:10 +00:00
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>
This commit is contained in:
parent
6858b05357
commit
4e0600b00a
2 changed files with 65 additions and 41 deletions
|
|
@ -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("")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
|||
Loading…
Reference in a new issue