Пример #1
0
 def catalina_tune(self, which, freq):
     """
     Async call to catalina tune
     """
     self.log.trace("Tuning {} {}".format(which, freq))
     async_exec(lib.ad9361, "tune", self.catalina, which, freq)
     return self.catalina.get_freq(which)
Пример #2
0
 def init_rf_cal(self, args):
     " Setup RF CAL "
     self.log.debug("Setting up RF CAL...")
     try:
         self._init_cals_mask = \
                 self._parse_and_convert_cal_args(
                     INIT_CALIBRATION_TABLE,
                     args.get('init_cals', 'DEFAULT')
                 )
         self._tracking_cals_mask = \
                 self._parse_and_convert_cal_args(
                     TRACKING_CALIBRATION_TABLE,
                     args.get('tracking_cals', 'DEFAULT')
                 )
         self._init_cals_timeout = int(
             args.get('init_cals_timeout',
                      str(self.mykonos.DEFAULT_INIT_CALS_TIMEOUT)), 0)
     except ValueError as ex:
         self.log.warning("init() args missing or error using default \
                          value seeing following exception print out.")
         self.log.warning("{}".format(ex))
         self._init_cals_mask = self._parse_and_convert_cal_args(
             INIT_CALIBRATION_TABLE, 'DEFAULT')
         self._tracking_cals_mask = self._parse_and_convert_cal_args(
             TRACKING_CALIBRATION_TABLE, 'DEFAULT')
         self._init_cals_timeout = self.mykonos.DEFAULT_INIT_CALS_TIMEOUT
     self.log.debug("args[init_cals]=0x{:02X}".format(self._init_cals_mask))
     self.log.debug("args[tracking_cals]=0x{:02X}".format(
         self._tracking_cals_mask))
     async_exec(self.mykonos, "setup_cal", self._init_cals_mask,
                self._tracking_cals_mask, self._init_cals_timeout)
Пример #3
0
 def catalina_tune(self, which, freq):
     """
     Async call to catalina tune
     """
     self.log.trace("Tuning {} {}".format(which, freq))
     async_exec(lib.ad9361, "tune", self.catalina, which, freq)
     return self.catalina.get_freq(which)
Пример #4
0
 def set_catalina_clock_rate(self, rate):
     """
     Async call to catalina set_clock_rate
     """
     self.log.trace("Setting Clock rate to {}".format(rate))
     async_exec(lib.ad9361, "set_clock_rate", self.catalina, rate)
     return rate
Пример #5
0
 def set_catalina_clock_rate(self, rate):
     """
     Async call to catalina set_clock_rate
     """
     self.log.trace("Setting Clock rate to {}".format(rate))
     async_exec(lib.ad9361, "set_clock_rate", self.catalina, rate)
     return rate
Пример #6
0
    def init_rf_cal(self, args):
        """ Setup RF CAL """
        def _parse_and_convert_cal_args(table, cal_args):
            """Parse calibration string and convert it to a number

            Arguments:
                table {dictionary} -- a look up table that map a type of calibration
                                      to its bit mask.(defined in AD9375-UG992)
                cal_args {string} --  string arguments from user in form of "CAL1|CAL2|CAL3"
                                      or "CAL1 CAL2 CAL3"  or "CAL1;CAL2;CAL3"

            Returns:
                int -- calibration value bit mask.
            """
            value = 0
            try:
                return int(cal_args, 0)
            except ValueError:
                pass
            for key in re.split(r'[;|\s]\s*', cal_args):
                value_tmp = table.get(key.upper())
                if (value_tmp) != None:
                    value |= value_tmp
                else:
                    self.log.warning(
                        "Calibration key `%s' is not in calibration table. "
                        "Ignoring this key.", key.upper())
            return value

        ## Go, go, go!
        self.log.trace("Setting up RF CAL...")
        try:
            init_cals_mask = _parse_and_convert_cal_args(
                INIT_CALIBRATION_TABLE, args.get('init_cals', 'DEFAULT'))
            tracking_cals_mask = _parse_and_convert_cal_args(
                TRACKING_CALIBRATION_TABLE, args.get('tracking_cals',
                                                     'DEFAULT'))
            init_cals_timeout = int(
                args.get('init_cals_timeout',
                         str(self.mykonos.DEFAULT_INIT_CALS_TIMEOUT)), 0)
        except ValueError as ex:
            self.log.warning("init() args missing or error using default \
                             value seeing following exception print out.")
            self.log.warning("{}".format(ex))
            init_cals_mask = _parse_and_convert_cal_args(
                INIT_CALIBRATION_TABLE, 'DEFAULT')
            tracking_cals_mask = _parse_and_convert_cal_args(
                TRACKING_CALIBRATION_TABLE, 'DEFAULT')
            init_cals_timeout = self.mykonos.DEFAULT_INIT_CALS_TIMEOUT
        self.log.debug("args[init_cals]=0x{:02X}".format(init_cals_mask))
        self.log.debug(
            "args[tracking_cals]=0x{:02X}".format(tracking_cals_mask))
        async_exec(self.mykonos, "setup_cal", init_cals_mask,
                   tracking_cals_mask, init_cals_timeout)
Пример #7
0
    def set_freq(self, which, freq, wait_for_lock):
        """
        Perform asynchronous tuning. This will, under the hood, call set_freq()
        on the AD937X object, but will spin it out into an asynchronous
        execution. We do this because under some circumstances, the set_freq()
        call can take a long time to execute, and we want to release the GIL
        during that time.

        Note: This overrides the set_freq() call provided from self.mykonos.
        """
        self.log.trace("Tuning {} {} {}".format(which, freq, wait_for_lock))
        async_exec(self.mykonos, "set_freq", which, freq, wait_for_lock)
        return self.mykonos.get_freq(which)
Пример #8
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
Пример #9
0
    def init_jesd(self, jesdcore, args):
        """
        Bring up the JESD link between Mykonos and the N310.
        All clocks must be set up and stable before starting this routine.
        """
        jesdcore.check_core()

        # JESD Lane Rate only depends on the master_clock_rate selection, since all
        # other link parameters (LMFS,N) remain constant.
        L = 4
        M = 4
        F = 2
        S = 1
        N = 16
        new_rate = self.master_clock_rate * M * N * (10.0 / 8) / L / S
        self.log.trace("Calculated JESD204b lane rate is {} Gbps".format(
            new_rate / 1e9))
        self.set_jesd_rate(jesdcore, new_rate)

        self.log.trace("Pulsing Mykonos Hard Reset...")
        self.cpld.reset_mykonos()
        self.log.trace("Initializing Mykonos...")
        self.init_lo_source(args)
        self.mykonos.begin_initialization()
        # Multi-chip Sync requires two SYSREF pulses at least 17us apart.
        jesdcore.send_sysref_pulse()
        time.sleep(0.001)  # 17us... ish.
        jesdcore.send_sysref_pulse()
        async_exec(self.mykonos, "finish_initialization")
        # TODO:can we call this after JESD?
        self.init_rf_cal(args)
        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...")
        jesdcore.init_framer()
        self.log.trace("Starting Mykonos deframer...")
        self.mykonos.start_jesd_rx()
        # 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()
        jesdcore.enable_lmfc(True)
        jesdcore.send_sysref_pulse()
        # Allow a bit of time for SYSREF to reach Mykonos and then CGS to appear. In
        # several experiments this time requirement was only in the 100s of nanoseconds.
        time.sleep(0.001)
        self.log.trace("Starting FPGA deframer...")
        jesdcore.init_deframer()

        # Allow a bit of time for CGS/ILA to complete.
        time.sleep(0.100)
        error_flag = False
        if not jesdcore.get_framer_status():
            self.log.error("JESD204b FPGA Core Framer is not synced!")
            error_flag = True
        if not self.check_mykonos_deframer_status():
            self.log.error("Mykonos JESD204b Deframer is not synced!")
            error_flag = True
        if not jesdcore.get_deframer_status():
            self.log.error("JESD204b FPGA Core Deframer is not synced!")
            error_flag = True
        if not self.check_mykonos_framer_status():
            self.log.error("Mykonos JESD204b Framer is not synced!")
            error_flag = True
        if (self.mykonos.get_multichip_sync_status() & 0xB) != 0xB:
            self.log.error("Mykonos Multi-chip Sync failed!")
            error_flag = True
        if error_flag:
            raise RuntimeError(
                'JESD204B Link Initialization Failed. See MPM logs for details.'
            )
        self.log.debug("JESD204B Link Initialization & Training Complete")
Пример #10
0
    def init_jesd(self, jesdcore, master_clock_rate, args):
        """
        Bring up the JESD link between Mykonos and the N310.
        All clocks must be set up and stable before starting this routine.
        """
        jesdcore.check_core()

        # JESD Lane Rate only depends on the master_clock_rate selection, since all
        # other link parameters (LMFS,N) remain constant.
        L = 4
        M = 4
        F = 2
        S = 1
        N = 16
        new_rate = master_clock_rate * M * N * (10.0/8) / L / S
        self.log.trace("Calculated JESD204b lane rate is {} Gbps".format(new_rate/1e9))
        self.mg_class.current_jesd_rate = \
            self.set_jesd_rate(
                jesdcore,
                new_rate,
                self.mg_class.current_jesd_rate)
        self.log.trace("Pulsing Mykonos Hard Reset...")
        self.mg_class.cpld.reset_mykonos()
        self.log.trace("Initializing Mykonos...")
        # TODO: If we can set the LO source after initialization, that would
        # enable us to switch LO sources without doing the entire JESD and
        # clocking bringup. For now, we'll keep it here, and every time the LO
        # source needs to be changed, we need to re-initialize (this is because
        # MYKONOS_initialize() takes in the entire device config, which includes
        # the LO source), but we can revisit this if we want to either
        # - speed up init when the only change is the LO source, or
        # - we want to make the LO source runtime-configurable.
        self.init_lo_source(args)
        self.mykonos.begin_initialization()
        # Multi-chip Sync requires two SYSREF pulses at least 17us apart.
        jesdcore.send_sysref_pulse()
        time.sleep(0.001) # 17us... ish.
        jesdcore.send_sysref_pulse()
        async_exec(self.mykonos, "finish_initialization")
        # According to the AD9371 user guide, p.57, the RF cal must come before
        # the framer/deframer init. We tried otherwise, and failed. So don't
        # move this anywhere else.
        self.init_rf_cal(args)
        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...")
        jesdcore.init_framer()
        self.log.trace("Starting Mykonos deframer...")
        self.mykonos.start_jesd_rx()
        # 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()
        jesdcore.enable_lmfc(True)
        jesdcore.send_sysref_pulse()
        # Allow a bit of time for SYSREF to reach Mykonos and then CGS to
        # appear. In several experiments this time requirement was only in the
        # 100s of nanoseconds.
        time.sleep(0.001)
        self.log.trace("Starting FPGA deframer...")
        jesdcore.init_deframer()

        # Allow a bit of time for CGS/ILA to complete.
        time.sleep(0.100)
        error_flag = False
        if not jesdcore.get_framer_status():
            self.log.error("JESD204b FPGA Core Framer is not synced!")
            error_flag = True
        if not self.check_mykonos_deframer_status():
            self.log.error("Mykonos JESD204b Deframer is not synced!")
            error_flag = True
        if not jesdcore.get_deframer_status():
            self.log.error("JESD204b FPGA Core Deframer is not synced!")
            error_flag = True
        if not self.check_mykonos_framer_status():
            self.log.error("Mykonos JESD204b Framer is not synced!")
            error_flag = True
        if (self.mykonos.get_multichip_sync_status() & 0xB) != 0xB:
            self.log.error("Mykonos Multi-chip Sync failed!")
            error_flag = True
        if error_flag:
            raise RuntimeError('JESD204B Link Initialization Failed. See MPM logs for details.')
        self.log.debug("JESD204B Link Initialization & Training Complete")
Пример #11
0
    def init_rf_cal(self, args):
        """ Setup RF CAL """
        def _parse_and_convert_cal_args(table, cal_args):
            """Parse calibration string and convert it to a number

            Arguments:
                table {dictionary} -- a look up table that map a type of calibration
                                      to its bit mask.(defined in AD9375-UG992)
                cal_args {string} --  string arguments from user in form of "CAL1|CAL2|CAL3"
                                      or "CAL1 CAL2 CAL3"  or "CAL1;CAL2;CAL3"

            Returns:
                int -- calibration value bit mask.
            """
            value = 0
            try:
                return int(cal_args, 0)
            except ValueError:
                pass
            for key in re.split(r'[;|\s]\s*', cal_args):
                value_tmp = table.get(key.upper())
                if (value_tmp) != None:
                    value |= value_tmp
                else:
                    self.log.warning(
                        "Calibration key `%s' is not in calibration table. "
                        "Ignoring this key.",
                        key.upper()
                    )
            return value
        ## Go, go, go!
        self.log.trace("Setting up RF CAL...")
        try:
            init_cals_mask = _parse_and_convert_cal_args(
                INIT_CALIBRATION_TABLE,
                args.get('init_cals', 'DEFAULT')
            )
            tracking_cals_mask = _parse_and_convert_cal_args(
                TRACKING_CALIBRATION_TABLE,
                args.get('tracking_cals', 'DEFAULT')
            )
            init_cals_timeout = int(
                args.get(
                    'init_cals_timeout',
                    str(self.mykonos.DEFAULT_INIT_CALS_TIMEOUT)
                ), 0
            )
        except ValueError as ex:
            self.log.warning("init() args missing or error using default \
                             value seeing following exception print out.")
            self.log.warning("{}".format(ex))
            init_cals_mask = _parse_and_convert_cal_args(
                INIT_CALIBRATION_TABLE, 'DEFAULT')
            tracking_cals_mask = _parse_and_convert_cal_args(
                TRACKING_CALIBRATION_TABLE, 'DEFAULT')
            init_cals_timeout = self.mykonos.DEFAULT_INIT_CALS_TIMEOUT
        self.log.debug("args[init_cals]=0x{:02X}".format(init_cals_mask))
        self.log.debug("args[tracking_cals]=0x{:02X}".format(tracking_cals_mask))
        async_exec(
            self.mykonos,
            "setup_cal",
            init_cals_mask,
            tracking_cals_mask,
            init_cals_timeout
        )
Пример #12
0
    def init_jesd(self, jesdcore, master_clock_rate, args):
        """
        Bring up the JESD link between Mykonos and the N310.
        All clocks must be set up and stable before starting this routine.
        """
        jesdcore.check_core()

        # JESD Lane Rate only depends on the master_clock_rate selection, since all
        # other link parameters (LMFS,N) remain constant.
        L = 4
        M = 4
        F = 2
        S = 1
        N = 16
        new_rate = master_clock_rate * M * N * (10.0 / 8) / L / S
        self.log.trace("Calculated JESD204b lane rate is {} Gbps".format(
            new_rate / 1e9))
        self.mg_class.current_jesd_rate = \
            self.set_jesd_rate(
                jesdcore,
                new_rate,
                self.mg_class.current_jesd_rate)
        self.log.trace("Pulsing Mykonos Hard Reset...")
        self.mg_class.cpld.reset_mykonos()
        self.log.trace("Initializing Mykonos...")
        # TODO: If we can set the LO source after initialization, that would
        # enable us to switch LO sources without doing the entire JESD and
        # clocking bringup. For now, we'll keep it here, and every time the LO
        # source needs to be changed, we need to re-initialize (this is because
        # MYKONOS_initialize() takes in the entire device config, which includes
        # the LO source), but we can revisit this if we want to either
        # - speed up init when the only change is the LO source, or
        # - we want to make the LO source runtime-configurable.
        self.init_lo_source(args)
        self.mykonos.begin_initialization()
        # Multi-chip Sync requires two SYSREF pulses at least 17us apart.
        jesdcore.send_sysref_pulse()
        time.sleep(0.001)  # 17us... ish.
        jesdcore.send_sysref_pulse()
        async_exec(self.mykonos, "finish_initialization")
        # According to the AD9371 user guide, p.57, the RF cal must come before
        # the framer/deframer init. We tried otherwise, and failed. So don't
        # move this anywhere else.
        self.init_rf_cal(args)
        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...")
        jesdcore.init_framer()
        self.log.trace("Starting Mykonos deframer...")
        self.mykonos.start_jesd_rx()
        # 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()
        jesdcore.enable_lmfc(True)
        jesdcore.send_sysref_pulse()
        # Allow a bit of time for SYSREF to reach Mykonos and then CGS to
        # appear. In several experiments this time requirement was only in the
        # 100s of nanoseconds.
        time.sleep(0.001)
        self.log.trace("Starting FPGA deframer...")
        jesdcore.init_deframer()

        # Allow a bit of time for CGS/ILA to complete.
        time.sleep(0.100)
        error_flag = False
        if not jesdcore.get_framer_status():
            self.log.error("JESD204b FPGA Core Framer is not synced!")
            error_flag = True
        if not self.check_mykonos_deframer_status():
            self.log.error("Mykonos JESD204b Deframer is not synced!")
            error_flag = True
        if not jesdcore.get_deframer_status():
            self.log.error("JESD204b FPGA Core Deframer is not synced!")
            error_flag = True
        if not self.check_mykonos_framer_status():
            self.log.error("Mykonos JESD204b Framer is not synced!")
            error_flag = True
        if (self.mykonos.get_multichip_sync_status() & 0xB) != 0xB:
            self.log.error("Mykonos Multi-chip Sync failed!")
            error_flag = True
        if error_flag:
            raise RuntimeError(
                'JESD204B Link Initialization Failed. See MPM logs for details.'
            )
        self.log.debug("JESD204B Link Initialization & Training Complete")