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()
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
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