Esempio n. 1
0
File: eiscat.py Progetto: w0xel/uhd
 def _sync_db_clock():
     " Synchronizes the DB clock to the common reference "
     synchronizer = ClockSynchronizer(
         self.dboard_clk_control,
         self.lmk,
         self._spi_ifaces['phase_dac'],
         0,  # register offset value.
         104e6,  # TODO don't hardcode
         self.ref_clock_freq,
         1.9E-12,  # fine phase shift. TODO don't hardcode. This should live in the EEPROM
         self.INIT_PHASE_DAC_WORD,
         0x3,
         3,  # External PPS pipeline delay from the PPS captured at the FPGA to TDC input
         self.slot_idx)
     # The radio clock traces on the motherboard are 69 ps longer for Daughterboard B
     # than Daughterboard A. We want both of these clocks to align at the converters
     # on each board, so adjust the target value for DB B. This is an N3xx series
     # peculiarity and will not apply to other motherboards.
     trace_delay_offset = {0: 0.0e-0, 1: 69.0e-12}[self.slot_idx]
     offset = synchronizer.run(num_meas=[512, 128],
                               target_offset=trace_delay_offset)
     offset_error = abs(offset)
     if offset_error > 100e-12:
         self.log.error(
             "Clock synchronizer measured an offset of {:.1f} ps!".
             format(offset_error * 1e12))
         raise RuntimeError(
             "Clock synchronizer measured an offset of {:.1f} ps!".
             format(offset_error * 1e12))
     else:
         self.log.debug(
             "Residual synchronization error: {:.1f} ps.".format(
                 offset_error * 1e12))
     synchronizer = None
     self.log.debug("Clock Synchronization Complete!")
Esempio n. 2
0
 def _sync_db_clock(
         self,
         dboard_ctrl_regs,
         master_clock_rate,
         ref_clock_freq,
         args):
     """ Synchronizes the DB clock to the common reference """
     reg_offset = 0x200
     ext_pps_delay = self.EXT_PPS_DELAY
     if args.get('time_source', self.mg_class.default_time_source) == 'sfp0':
         reg_offset = 0x400
         ref_clock_freq = 62.5e6
         ext_pps_delay = 1 # only 1 flop between the WR core output and the TDC input
     synchronizer = ClockSynchronizer(
         dboard_ctrl_regs,
         self.mg_class.lmk,
         self._spi_ifaces['phase_dac'],
         reg_offset,
         master_clock_rate,
         ref_clock_freq,
         860E-15, # fine phase shift. TODO don't hardcode. This should live in the EEPROM
         self.INIT_PHASE_DAC_WORD,
         self.PHASE_DAC_SPI_ADDR,
         ext_pps_delay,
         self.N3XX_INT_PPS_DELAY,
         self.slot_idx
     )
     # The radio clock traces on the motherboard are 69 ps longer for
     # Daughterboard B than Daughterboard A. We want both of these clocks to
     # align at the converters on each board, so adjust the target value for
     # DB B. This is an N3xx series peculiarity and will not apply to other
     # motherboards.
     trace_delay_offset = {0:  0.0e-0,
                           1: 69.0e-12}[self.slot_idx]
     offset = synchronizer.run(
         num_meas=[512, 128],
         target_offset=trace_delay_offset)
     offset_error = abs(offset)
     if offset_error > 100e-12:
         self.log.error("Clock synchronizer measured an offset of {:.1f} ps!".format(
             offset_error*1e12
         ))
         raise RuntimeError("Clock synchronizer measured an offset of {:.1f} ps!".format(
             offset_error*1e12
         ))
     else:
         self.log.debug("Residual synchronization error: {:.1f} ps.".format(
             offset_error*1e12
         ))
     synchronizer = None # Help garbage collector
     self.log.debug("Sample Clock Synchronization Complete!")
Esempio n. 3
0
File: eiscat.py Progetto: zwm152/uhd
 def _sync_db_clock():
     " Synchronizes the DB clock to the common reference "
     reg_offset = 0x200
     ext_pps_delay = self.EXT_PPS_DELAY
     #from outdated inst of ClockSync
     #2.496e9,     # lmk_vco_freq
     synchronizer = ClockSynchronizer(
         self.radio_regs,
         self.lmk,
         self._spi_ifaces['phase_dac'],
         reg_offset,
         self.master_clock_rate,
         self.ref_clock_freq,
         1.9E-12,  # fine phase shift. TODO don't hardcode. This should live in the EEPROM
         self.INIT_PHASE_DAC_WORD,
         self.PHASE_DAC_SPI_ADDR,
         ext_pps_delay,
         self.N3XX_INT_PPS_DELAY,
         self.slot_idx)
     # The radio clock traces on the motherboard are 69 ps longer for Daughterboard B
     # than Daughterboard A. We want both of these clocks to align at the converters
     # on each board, so adjust the target value for DB B. This is an N3xx series
     # peculiarity and will not apply to other motherboards.
     trace_delay_offset = {0: 0.0e-0, 1: 69.0e-12}[self.slot_idx]
     offset = synchronizer.run(num_meas=[512, 128],
                               target_offset=trace_delay_offset)
     offset_error = abs(offset)
     if offset_error > 100e-12:
         self.log.error(
             "Clock synchronizer measured an offset of {:.1f} ps!".
             format(offset_error * 1e12))
         raise RuntimeError(
             "Clock synchronizer measured an offset of {:.1f} ps!".
             format(offset_error * 1e12))
     else:
         self.log.debug(
             "Residual synchronization error: {:.1f} ps.".format(
                 offset_error * 1e12))
     synchronizer = None
     self.log.debug("Clock Synchronization Complete!")
Esempio n. 4
0
 def _get_clock_synchronizer():
     " Return a clock synchronizer object "
     # Future Work: target_value needs to be tweaked to support
     # heterogeneous rate sync.
     target_value = {
         122.88e6: 128e-9,
         125e6: 128e-9,
         153.6e6: 122e-9
     }[self.master_clock_rate]
     return ClockSynchronizer(
         dboard_ctrl_regs,
         self.lmk,
         self._spi_ifaces['phase_dac'],
         0, # register offset value. future work.
         self.master_clock_rate,
         self.ref_clock_freq,
         860E-15, # fine phase shift. TODO don't hardcode. This should live in the EEPROM
         self.INIT_PHASE_DAC_WORD,
         [target_value,],   # target_values
         0x0,         # spi_addr TODO: make this a constant and replace in _sync_db_clock as well
         self.slot_idx
     )
Esempio n. 5
0
File: eiscat.py Progetto: w0xel/uhd
    def init(self, args):
        """
        Execute necessary actions to bring up the daughterboard:
        - Initializes all the software controls for all the chips and registers
        - Turns on the power
        - Initializes clocking
        - Synchronizes clocks to reference
        - Forwards PPS to the radio block

        This assumes that an appropriate overlay was loaded. If not, this will
        fail loudly complaining about missing devices.

        For operation (streaming), the ADCs and deframers still need to be
        initialized. See init_jesd_core_reset_adcs(), init_adcs_and_deframers(),
        and check_deframer_status().

        Note that this function will do nothing if the device was previously
        initialized, unless force_init was specified in the init args.
        """
        def _init_dboard_regs():
            " Create a UIO object to talk to dboard regs "
            self.log.trace("Getting uio...")
            return UIO(label="dboard-regs-{}".format(self.slot_idx),
                       read_only=False)

        def _init_jesd_cores(dboard_regs, slot_idx):
            " Init abstraction layer for JESD cores. Will also test registers. "
            return [
                JesdCoreEiscat(dboard_regs, slot_idx, core_idx, self.log)
                for core_idx in range(2)
            ]

        def _init_spi_devices():
            " Returns abstraction layers to all the SPI devices "
            self.log.trace("Loading SPI interfaces...")
            return {
                key: self.spi_factories[key](self._spi_nodes[key])
                for key in self._spi_nodes
            }

        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

        def _init_lmk(slot_idx, lmk_spi, ref_clk_freq, pdac_spi,
                      init_phase_dac_word):
            """
            Sets the phase DAC to initial value, and then brings up the LMK
            according to the selected ref clock frequency.
            Will throw if something fails.
            """
            self.log.trace(
                "Initializing Phase DAC to d{}.".format(init_phase_dac_word))
            pdac_spi.poke16(0x3, init_phase_dac_word)
            return LMK04828EISCAT(lmk_spi, ref_clk_freq, slot_idx)

        def _sync_db_clock():
            " Synchronizes the DB clock to the common reference "
            synchronizer = ClockSynchronizer(
                self.dboard_clk_control,
                self.lmk,
                self._spi_ifaces['phase_dac'],
                0,  # register offset value.
                104e6,  # TODO don't hardcode
                self.ref_clock_freq,
                1.9E-12,  # fine phase shift. TODO don't hardcode. This should live in the EEPROM
                self.INIT_PHASE_DAC_WORD,
                0x3,
                3,  # External PPS pipeline delay from the PPS captured at the FPGA to TDC input
                self.slot_idx)
            # The radio clock traces on the motherboard are 69 ps longer for Daughterboard B
            # than Daughterboard A. We want both of these clocks to align at the converters
            # on each board, so adjust the target value for DB B. This is an N3xx series
            # peculiarity and will not apply to other motherboards.
            trace_delay_offset = {0: 0.0e-0, 1: 69.0e-12}[self.slot_idx]
            offset = synchronizer.run(num_meas=[512, 128],
                                      target_offset=trace_delay_offset)
            offset_error = abs(offset)
            if offset_error > 100e-12:
                self.log.error(
                    "Clock synchronizer measured an offset of {:.1f} ps!".
                    format(offset_error * 1e12))
                raise RuntimeError(
                    "Clock synchronizer measured an offset of {:.1f} ps!".
                    format(offset_error * 1e12))
            else:
                self.log.debug(
                    "Residual synchronization error: {:.1f} ps.".format(
                        offset_error * 1e12))
            synchronizer = None
            self.log.debug("Clock Synchronization Complete!")

        # Go, go, go!
        if args.get("force_init", False):
            self.log.info("Forcing re-initialization of dboard.")
        self.initialized = args.get("force_init", self.initialized)
        if self.initialized:
            self.log.debug(
                "Dboard was previously initialized; skipping init. " \
                "Specify force_init=1 to force initialization."
            )
            return True
        self.log.debug("init() called with args `{}'".format(",".join(
            ['{}={}'.format(x, args[x]) for x in args])))
        self.radio_regs = _init_dboard_regs()
        self.jesd_cores = _init_jesd_cores(self.radio_regs, self.slot_idx)
        self.log.debug("Radio-register UIO object successfully generated!")
        self._spi_ifaces = _init_spi_devices()  # Chips don't have power yet!
        self.log.debug("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.adcs = [
            ADS54J56(self._spi_ifaces[spi_iface], self.log)
            for spi_iface in ('adc0', 'adc1')
        ]
        self.dboard_clk_control.enable_mmcm()
        self.log.debug("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,
            2.496e9,  # lmk_vco_freq
            0x3,  # spi_addr
            self.slot_idx)
        _sync_db_clock(self.clock_synchronizer)
        # Clocks and PPS are now fully active!
        return True