From a233877f6554fa4d19dfcc4105e904414ea2ad1c Mon Sep 17 00:00:00 2001 From: Daniel Jepson Date: Tue, 30 May 2017 18:16:37 -0700 Subject: mpm/eiscat: Updated bringup procedure for dual-synched dboards --- mpm/python/usrp_mpm/dboard_manager/eiscat.py | 374 ++++++++++++++++----------- 1 file changed, 228 insertions(+), 146 deletions(-) (limited to 'mpm/python/usrp_mpm/dboard_manager/eiscat.py') diff --git a/mpm/python/usrp_mpm/dboard_manager/eiscat.py b/mpm/python/usrp_mpm/dboard_manager/eiscat.py index 98cea47ce..14b0acd49 100644 --- a/mpm/python/usrp_mpm/dboard_manager/eiscat.py +++ b/mpm/python/usrp_mpm/dboard_manager/eiscat.py @@ -19,27 +19,15 @@ EISCAT rx board implementation module """ import time -from six import iteritems from ..mpmlog import get_logger from ..uio import UIO from . import lib from .base import DboardManagerBase from .lmk_eiscat import LMK04828EISCAT +from usrp_mpm.cores import ClockSynchronizer N_CHANS = 8 # Chans per dboard -# Power enable pins -POWER_ENB = 0x200C # Address of the power enable register -PWR_CHAN_EN_2V5 = [(1< 100e-12: + self.log.error("Clock synchronizer measured an offset of {} ps!".format( + offset_error*1e12 + )) + raise RuntimeError("Clock synchronizer measured an offset of {} ps!".format( + offset_error*1e12 + )) + self.log.info("Clock Synchronization Complete!") + def _check_jesd_cores(db_clk_control, jesd_cores): + " Checks clocks are enabled; init the JESD core; throw on failure. " + if not db_clk_control.check_refclk(): + self.log.error("JESD Cores not getting a MGT RefClk!") + raise RuntimeError("JESD Cores not getting a MGT RefClk") + for jesd_core in jesd_cores: + jesd_core.init() + def _init_and_reset_adcs(spi_ifaces): + " Create ADC control objects; reset ADCs " + adcs = [ADS54J56(spi_iface, self.log) for spi_iface in spi_ifaces] + for adc in adcs: + adc.reset() + return adcs + # Go, go, go! self.log.info("init() called with args `{}'".format( ",".join(['{}={}'.format(x, args[x]) for x in args]) )) - self.log.trace("Getting uio...") - self.radio_regs = UIO( - label="dboard-regs-{}".format(self.slot_idx), - read_only=False - ) - # Create JESD cores. They will also test the UIO regs on initialization. - self.jesd_cores = [ - JesdCoreEiscat( - self.radio_regs, - self.slot_idx, - core_idx, - self.log - ) for core_idx in xrange(2) - ] + self.radio_regs = _init_dboard_regs() + self.jesd_cores = _init_jesd_cores(self.radio_regs, self.slot_idx) self.log.info("Radio-register UIO object successfully generated!") - - self.radio_regs.poke32(ADC_RESET, 0x0000) # TODO put this somewhere else - - # Load SPI devices. Note: They won't be usable until _init_power() was called. - self.log.trace("Loading SPI interfaces...") - self._spi_ifaces = { - key: self.spi_factories[key](self._spi_nodes[key]) - for key in self._spi_nodes - } + self._spi_ifaces = _init_spi_devices() # Chips don't have power yet! self.log.info("Loaded SPI interfaces!") + self._init_power(self.radio_regs) # Now, we can talk to chips via SPI + self.dboard_clk_control = _init_clock_control(self.radio_regs) + 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!") + # Synchronize DB Clocks + self.clock_synchronizer = ClockSynchronizer( + self.radio_regs, + self.dboard_clk_control, + self.lmk, + self._spi_ifaces['phase_dac'], + 0, # TODO this might not actually be zero + 104e6, # TODO don't hardcode + self.ref_clock_freq, + 1.9E-12, # TODO don't hardcode. This should live in the EEPROM + self.INIT_PHASE_DAC_WORD, + self.log + ) + _sync_db_clock(self.clock_synchronizer) + _check_jesd_cores( + self.dboard_clk_control, + self.jesd_cores + ) + self.adc0, self.adc1 = _init_and_reset_adcs(( + self._spi_ifaces['adc0'], self._spi_ifaces['adc1'], + )) + self.log.trace("ADC Reset Sequence Complete!") - # Initialize Clocking - self.mmcm = MMCM(self.radio_regs, self.log) - self._init_power(self.radio_regs) - self.mmcm.reset() - self.lmk = LMK04828EISCAT(self._spi_ifaces['lmk'], self.ref_clock_freq, "A") # Initializes LMK - if not self.mmcm.enable(): - self.log.error("Could not re-enable MMCM!") - raise RuntimeError("Could not re-enable MMCM!") - self.log.info("MMCM enabled!") - # Initialize ADCs and JESD cores - if not self.jesd_cores[0].check_refclk(): - self.log.error("JESD Core {} not getting a refclk!".format(0)) - raise RuntimeError("JESD Core {} not getting a refclk!".format(0)) - for i in xrange(2): - self.jesd_cores[i].init() - self.adc0 = ADS54J56(self._spi_ifaces['adc0'], self.log) - self.adc1 = ADS54J56(self._spi_ifaces['adc1'], self.log) - self.adc0.reset() - self.adc1.reset() - self.log.info("ADCs resetted!") - - def send_sysref(): - """ - TODO this is a temp way of sending sysref - need to replace with timed command - """ - SYSREF = 1<<13 - old_val = 0x1FFF - self.radio_regs.poke32(POWER_ENB, old_val | SYSREF) - time.sleep(0.001) - self.radio_regs.poke32(POWER_ENB, old_val) - send_sysref() + def send_sysref(self): + """ + TODO this is a temp way of sending sysref + need to replace with timed command + """ + self.log.trace("Sending SYSREF via MPM...") + self.radio_regs.poke32(self.SYSREF_CONTROL, 0x0) + time.sleep(0.001) + self.radio_regs.poke32(self.SYSREF_CONTROL, 0x1) + time.sleep(0.001) + self.radio_regs.poke32(self.SYSREF_CONTROL, 0x0) + def init_adcs_and_deframers(self): + """ + Initialize the ADCs and the JESD deframers. Assumption is that they were + SYSREF'd before. + """ self.adc0.setup() self.adc1.setup() - self.log.info("ADCs set up!") - for i in xrange(2): - self.jesd_cores[i].init_deframer() + self.log.info("ADC Initialization Complete!") + for jesd_core in self.jesd_cores: + jesd_core.init_deframer() - send_sysref() + def check_deframer_status(self): + """ + Checks the JESD deframer status. This is done after initialization and + sending a second SYSREF pulse. - for i in xrange(2): - if not self.jesd_cores[i].check_deframer_status(): - raise RuntimeError("JESD Core {}: Deframer status not lookin' so good!".format(i)) - self.log.info("JESD core initialized, link up!") + Calling this function is required to signal a completion of the + initialization sequence. - self.phase_dac = self._spi_ifaces['phase_dac'] - ## END OF THE JEPSON SEQUENCE ## + Will throw on failure. + """ + for jesd_idx, jesd_core in enumerate(self.jesd_cores): + if not jesd_core.check_deframer_status(): + raise RuntimeError( + "JESD204B Core {} Error: Failed to Link. " \ + "Don't ignore this, please tell someone!".format(jesd_idx) + ) + self.log.info("JESD Core Initialized, link up! (woohoo!)") self.initialized = True def shutdown(self): @@ -494,32 +585,23 @@ class EISCAT(DboardManagerBase): """ Turn on power to the dboard. - After this function, we should never touch this register again (other - than turning it off again). + After this function, we should never touch this group again (other + than turning it off, maybe). """ - reg_val = PWR2_5V_DC_CTRL_ENB - self.log.trace("Asserting power ctrl enable ({:x})...".format((reg_val))) - regs.poke32(POWER_ENB, reg_val) - time.sleep(0.001) - reg_val = reg_val \ - | PWR2_5V_DC_CTRL_ENB \ - | PWR2_5V_DC_PWR_EN \ - | PWR2_5V_LNA_CTRL_EN \ - | PWR2_5V_LMK_SPI_EN | PWR2_5V_ADC0_SPI_EN #| PWR2_5V_ADC1_SPI_EN - regs.poke32(POWER_ENB, reg_val) - self.log.trace("Asserting power enable for all the chips ({:x})...".format((reg_val))) - time.sleep(0.1) - for chan in xrange(8): - reg_val = reg_val | PWR_CHAN_EN_2V5[chan] - self.log.trace("Asserting power enable for all the channels ({:x})...".format((reg_val))) - regs.poke32(POWER_ENB, reg_val) + regs.poke32(self.DB_ENABLES, 0x01000000) + regs.poke32(self.DB_ENABLES, 0x00010101) + regs.poke32(self.ADC_CONTROL, 0x00010000) + time.sleep(0.100) + regs.poke32(self.DB_CH_ENABLES, 0x000000FF) # Enable all channels def _deinit_power(self, regs): """ - Turn off power to the dboard. + Turn off power to the dboard. Sequence is reverse of init_power. """ self.log.trace("Disabling power to the daughterboard...") - regs.poke32(POWER_ENB, 0x0000) + regs.poke32(self.DB_CH_ENABLES, 0x00000000) # Disable all channels + regs.poke32(self.ADC_CONTROL, 0x00100000) + regs.poke32(self.DB_ENABLES, 0x10101010) def update_ref_clock_freq(self, freq): """ -- cgit v1.2.3