Example #1
0
 def set_clk_safe_state(self):
     """
     Disable all components that could react badly to a sudden change in
     clocking. After calling this method, all clocks will be off. Calling
     _reinit() will turn them on again.
     """
     if self._init_args is None:
         # Then we're already in a safe state
         return
     # Put the ADC and the DAC in a safe state because they receive a LMK's clock.
     # The DAC37J82 datasheet only recommends disabling its analog output before
     # a clock is provided to the chip.
     self.dac.tx_enable(False)
     self.adc.power_down_channel(True)
     with open_uio(
         label="dboard-regs-{}".format(self.slot_idx),
         read_only=False
     ) as radio_regs:
         # Clear the Sample Clock enables and place the MMCM in reset.
         db_clk_control = DboardClockControl(radio_regs, self.log)
         db_clk_control.reset_mmcm()
         # Place the JESD204b core in reset, mainly to reset QPLL/CPLLs.
         jesdcore = nijesdcore.NIJESDCore(radio_regs, self.slot_idx,
                                          **RhodiumInitManager.JESD_DEFAULT_ARGS)
         jesdcore.reset()
Example #2
0
 def _full_init(self, slot_idx, master_clock_rate, ref_clock_freq, args):
     """
     Run the full initialization sequence. This will bring everything up
     from scratch: The LMK, JESD cores, the AD9371, calibrations, and
     anything else that is clocking-related.
     Depending on the settings, this can take a fair amount of time.
     """
     # Init some more periphs:
     # The following peripherals are only used during init, so we don't
     # want to hang on to them for the full lifetime of the Magnesium
     # class. This helps us close file descriptors associated with the
     # UIO objects.
     with open_uio(
         label="dboard-regs-{}".format(slot_idx),
         read_only=False
     ) as dboard_ctrl_regs:
         self.log.trace("Creating jesdcore object...")
         jesdcore = nijesdcore.NIJESDCore(dboard_ctrl_regs, slot_idx, **self.JESD_DEFAULT_ARGS)
         # Now get cracking with the actual init sequence:
         self.log.trace("Creating dboard clock control object...")
         db_clk_control = DboardClockControl(dboard_ctrl_regs, self.log)
         self.log.debug("Reset Dboard Clocking and JESD204B interfaces...")
         db_clk_control.reset_mmcm()
         jesdcore.reset()
         self.log.trace("Initializing LMK...")
         self.mg_class.lmk = self._init_lmk(
             self._spi_ifaces['lmk'],
             ref_clock_freq,
             master_clock_rate,
             self._spi_ifaces['phase_dac'],
             self.INIT_PHASE_DAC_WORD,
             self.PHASE_DAC_SPI_ADDR,
         )
         db_clk_control.enable_mmcm()
         # Synchronize DB Clocks
         self._sync_db_clock(
             dboard_ctrl_regs,
             master_clock_rate,
             ref_clock_freq,
             args)
         self.log.debug(
             "Sample Clocks and Phase DAC Configured Successfully!")
         # Clocks and PPS are now fully active!
         if args.get('skip_rfic', None) is None:
             async_exec(self.mykonos, "set_master_clock_rate", master_clock_rate)
             self.init_jesd(jesdcore, master_clock_rate, args)
         jesdcore = None # Help with garbage collection
         # That's all that requires access to the dboard regs!
     return True
Example #3
0
    def set_clk_safe_state(self):
        """
        Disable all components that could react badly to a sudden change in
        clocking. After calling this method, all clocks will be off. Calling
        _reinit() will turn them on again.

        The only downstream receiver of the clock that is not reset here are the
        lowband LOs, which are controlled through the host UHD interface.
        """
        if self._init_args is None:
            # Then we're already in a safe state
            return
        # Reset Mykonos, since it receives a copy of the clock from the LMK.
        self.cpld.reset_mykonos(keep_in_reset=True)
        with open_uio(label="dboard-regs-{}".format(self.slot_idx),
                      read_only=False) as dboard_ctrl_regs:
            # Clear the Sample Clock enables and place the MMCM in reset.
            db_clk_control = DboardClockControl(dboard_ctrl_regs, self.log)
            db_clk_control.reset_mmcm()
            # Place the JESD204b core in reset, mainly to reset QPLL/CPLLs.
            jesdcore = nijesdcore.NIJESDCore(
                dboard_ctrl_regs, self.slot_idx,
                **MagnesiumInitManager.JESD_DEFAULT_ARGS)
            jesdcore.reset()
Example #4
0
    def init(self, args):
        """
        Run the full initialization sequence. This will bring everything up
        from scratch: The LMK, JESD cores, the AD9695, the DAC37J82, and
        anything else that is clocking-related.
        Depending on the settings, this can take a fair amount of time.
        """
        # Input validation on RX margin tests (@ FPGA and DAC)
        # By accepting the rx_eyescan/tx_prbs argument being str or bool, one may
        # request an eyescan measurement to be performed from either the USRP's
        # shell (i.e. using --default-args) or from the host's MPM shell.
        perform_rx_eyescan = False
        if 'rx_eyescan' in args:
            perform_rx_eyescan = (args['rx_eyescan']
                                  == 'True') or (args['rx_eyescan'] == True)
        if perform_rx_eyescan:
            self.log.trace("Adding RX eye scan PMA enable to JESD args.")
            self.JESD_DEFAULT_ARGS["enable_rx_eyescan"] = True
        perform_tx_prbs = False
        if 'tx_prbs' in args:
            perform_tx_prbs = (args['tx_prbs'] == 'True') or (args['tx_prbs']
                                                              == True)

        # Latency across the JESD204B TX/RX links should remain constant and
        # deterministic across the supported sampling_clock_rate values.
        # After testing the roundtrip latency (i.e. FPGA -> TX -> RX -> FPGA),
        # it was found that a different set of SYSREF delay values are required
        # for sampling_clock_rate = 400 MSPS to achieve latency consistency.
        self.JESD_DEFAULT_ARGS['rx_sysref_delay'] = \
          self.RX_SYSREF_DLY_DIC[self.rh_class.sampling_clock_rate]

        # Bringup Sequence.
        #   1. Prerequisites (include opening mmaps)
        #   2. Initialize LMK and bringup clocks.
        #   3. Synchronize DB Clocks.
        #   4. Initialize FPGA JESD IP.
        #   5. DAC Configuration.
        #   6. ADC Configuration.
        #   7. JESD204B Initialization.
        #   8. CPLD Gain Tables Initialization.

        # 1. Prerequisites
        # Open FPGA IP (Clock control and JESD core).
        self.log.trace("Creating gain table object...")
        self.gain_table_loader = GainTableRh(
            self._spi_ifaces['cpld'], self._spi_ifaces['cpld_gain_loader'],
            self.log)

        with open_uio(label="dboard-regs-{}".format(self.rh_class.slot_idx),
                      read_only=False) as radio_regs:
            self.log.trace("Creating dboard clock control object")
            db_clk_control = DboardClockControl(radio_regs, self.log)
            self.log.trace("Creating jesdcore object")
            jesdcore = nijesdcore.NIJESDCore(radio_regs,
                                             self.rh_class.slot_idx,
                                             **self.JESD_DEFAULT_ARGS)

            # 2. Initialize LMK and bringup clocks.
            # Disable FPGA MMCM's outputs, and assert its reset.
            db_clk_control.reset_mmcm()
            # Always place the JESD204b cores in reset before modifying the clocks,
            # otherwise high power or erroneous conditions could exist in the FPGA!
            jesdcore.reset()
            # Configure and bringup the LMK's clocks.
            self.log.trace("Initializing LMK...")
            self.rh_class.lmk = self._init_lmk(
                self._spi_ifaces['lmk'], self.rh_class.ref_clock_freq,
                self.rh_class.sampling_clock_rate,
                self._spi_ifaces['phase_dac'], self.INIT_PHASE_DAC_WORD,
                self.PHASE_DAC_SPI_ADDR)
            self.log.trace("LMK Initialized!")
            # Deassert FPGA's MMCM reset, poll for lock, and enable outputs.
            db_clk_control.enable_mmcm()

            # 3. Synchronize DB Clocks.
            # The clock synchronzation driver receives the master_clock_rate, which for
            # Rhodium is half the sampling_clock_rate.
            self._sync_db_clock(radio_regs, self.rh_class.ref_clock_freq,
                                self.rh_class.sampling_clock_rate / 2, args)

            # 4. DAC Configuration.
            self.dac.config()

            # 5. ADC Configuration.
            self.adc.config()

            # 6-7. JESD204B Initialization.
            self.init_jesd(jesdcore, self.rh_class.sampling_clock_rate)
            # [Optional] Perform RX eyescan.
            if perform_rx_eyescan:
                self.log.info("Performing RX eye scan on ADC to FPGA link...")
                self._rx_eyescan(jesdcore, args)
            # [Optional] Perform TX PRBS test.
            if perform_tx_prbs:
                self.log.info(
                    "Performing TX PRBS-31 test on FPGA to DAC link...")
                self._tx_prbs_test(jesdcore, args)
            # Direct the garbage collector by removing our references
            jesdcore = None
            db_clk_control = None

        # 8. CPLD Gain Tables Initialization.
        self.gain_table_loader.init()

        return True