def set_time_source(self, time_source): " Set a time source " assert time_source in self.get_time_sources() self._time_source = time_source self.mboard_regs_control.set_time_source(time_source, self.get_ref_clock_freq()) if time_source == 'sfp0': # This error is specific to slave and master mode for White Rabbit. # Grand Master mode will require the external or gpsdo sources (not supported). if (time_source == 'sfp0' or time_source == 'sfp1') and \ self.get_clock_source() != 'internal': error_msg = "Time source sfp(0|1) requires the internal clock source!" self.log.error(error_msg) raise RuntimeError(error_msg) if self.updateable_components['fpga']['type'] != 'WX': self.log.error("{} time source requires 'WX' FPGA type" \ .format(time_source)) raise RuntimeError("{} time source requires 'WX' FPGA type" \ .format(time_source)) # Only open UIO to the WR core once we're guaranteed it exists. wr_regs_control = WhiteRabbitRegsControl( self.wr_regs_label, self.log) # Wait for time source to become ready. Only applies to SFP0/1. All other # targets start their PPS immediately. self.log.debug("Waiting for {} timebase to lock..." \ .format(time_source)) if not poll_with_timeout( lambda: wr_regs_control.get_time_lock_status(), 40000, # Try for x ms... this number is set from a few benchtop tests 1000, # Poll every... second! why not? ): self.log.error("{} timebase failed to lock within 40 seconds. Status: 0x{:X}" \ .format(time_source, wr_regs_control.get_time_lock_status())) raise RuntimeError("Failed to lock SFP timebase.")
def set_sync_source(self, args): """ Selects reference clock and PPS sources. Unconditionally re-applies the time source to ensure continuity between the reference clock and time rates. """ clock_source = args.get('clock_source', self._clock_source) assert clock_source in self.get_clock_sources() time_source = args.get('time_source', self._time_source) assert time_source in self.get_time_sources() if (clock_source == self._clock_source) and (time_source == self._time_source): # Nothing change no need to do anything self.log.trace("New sync source assignment matches" "previous assignment. Ignoring update command.") return assert (clock_source, time_source) in self.valid_sync_sources # Start setting sync source self.log.debug("Setting clock source to `{}'".format(clock_source)) # Place the DB clocks in a safe state to allow reference clock # transitions. This leaves all the DB clocks OFF. for slot, dboard in enumerate(self.dboards): if hasattr(dboard, 'set_clk_safe_state'): self.log.trace( "Setting dboard %d components to safe clocking state...", slot) dboard.set_clk_safe_state() # Disable the Ref Clock in the FPGA before throwing the external switches. self.mboard_regs_control.enable_ref_clk(False) # Set the external switches to bring in the new source. if clock_source == 'internal': self._gpios.set("CLK-MAINSEL-EX_B") self._gpios.set("CLK-MAINSEL-25MHz") self._gpios.reset("CLK-MAINSEL-GPS") elif clock_source == 'gpsdo': self._gpios.set("CLK-MAINSEL-EX_B") self._gpios.reset("CLK-MAINSEL-25MHz") self._gpios.set("CLK-MAINSEL-GPS") else: # external self._gpios.reset("CLK-MAINSEL-EX_B") self._gpios.reset("CLK-MAINSEL-GPS") # SKY13350 needs to be in known state self._gpios.set("CLK-MAINSEL-25MHz") self._clock_source = clock_source self.log.debug("Reference clock source is: {}" \ .format(self._clock_source)) self.log.debug("Reference clock frequency is: {} MHz" \ .format(self.get_ref_clock_freq()/1e6)) # Enable the Ref Clock in the FPGA after giving it a chance to # settle. The settling time is a guess. time.sleep(0.100) self.mboard_regs_control.enable_ref_clk(True) self.log.debug("Setting time source to `{}'".format(time_source)) self._time_source = time_source ref_clk_freq = self.get_ref_clock_freq() self.mboard_regs_control.set_time_source(time_source, ref_clk_freq) if time_source == 'sfp0': # This error is specific to slave and master mode for White Rabbit. # Grand Master mode will require the external or gpsdo # sources (not supported). if time_source in ('sfp0', 'sfp1') \ and self.get_clock_source() != 'internal': error_msg = "Time source {} requires `internal` clock source!".format( time_source) self.log.error(error_msg) raise RuntimeError(error_msg) sfp_time_source_images = ('WX', ) if self.updateable_components['fpga'][ 'type'] not in sfp_time_source_images: self.log.error("{} time source requires FPGA types {}" \ .format(time_source, sfp_time_source_images)) raise RuntimeError("{} time source requires FPGA types {}" \ .format(time_source, sfp_time_source_images)) # Only open UIO to the WR core once we're guaranteed it exists. wr_regs_control = WhiteRabbitRegsControl(self.wr_regs_label, self.log) # Wait for time source to become ready. Only applies to SFP0/1. All other # targets start their PPS immediately. self.log.debug("Waiting for {} timebase to lock..." \ .format(time_source)) if not poll_with_timeout( lambda: wr_regs_control.get_time_lock_status(), 40000, # Try for x ms... this number is set from a few benchtop tests 1000, # Poll every... second! why not? ): self.log.error("{} timebase failed to lock within 40 seconds. Status: 0x{:X}" \ .format(time_source, wr_regs_control.get_time_lock_status())) raise RuntimeError("Failed to lock SFP timebase.") # Update the DB with the correct Ref Clock frequency and force a re-init. for slot, dboard in enumerate(self.dboards): self.log.trace( "Updating reference clock on dboard %d to %f MHz...", slot, ref_clk_freq / 1e6) dboard.update_ref_clock_freq(ref_clk_freq, time_source=time_source, clock_source=clock_source, skip_rfic=args.get('skip_rfic', None))
def set_sync_source(self, args): """ Selects reference clock and PPS sources. Unconditionally re-applies the time source to ensure continuity between the reference clock and time rates. """ clock_source = args.get('clock_source', self._clock_source) assert clock_source in self.get_clock_sources() time_source = args.get('time_source', self._time_source) assert time_source in self.get_time_sources() if (clock_source == self._clock_source) and (time_source == self._time_source): # Nothing change no need to do anything self.log.trace("New sync source assignment matches" "previous assignment. Ignoring update command.") return assert (clock_source, time_source) in self.valid_sync_sources # Start setting sync source self.log.debug("Setting clock source to `{}'".format(clock_source)) # Place the DB clocks in a safe state to allow reference clock # transitions. This leaves all the DB clocks OFF. for slot, dboard in enumerate(self.dboards): if hasattr(dboard, 'set_clk_safe_state'): self.log.trace( "Setting dboard %d components to safe clocking state...", slot) dboard.set_clk_safe_state() # Disable the Ref Clock in the FPGA before throwing the external switches. self.mboard_regs_control.enable_ref_clk(False) # Set the external switches to bring in the new source. if clock_source == 'internal': self._gpios.set("CLK-MAINSEL-EX_B") self._gpios.set("CLK-MAINSEL-25MHz") self._gpios.reset("CLK-MAINSEL-GPS") elif clock_source == 'gpsdo': self._gpios.set("CLK-MAINSEL-EX_B") self._gpios.reset("CLK-MAINSEL-25MHz") self._gpios.set("CLK-MAINSEL-GPS") else: # external self._gpios.reset("CLK-MAINSEL-EX_B") self._gpios.reset("CLK-MAINSEL-GPS") # SKY13350 needs to be in known state self._gpios.set("CLK-MAINSEL-25MHz") self._clock_source = clock_source self.log.debug("Reference clock source is: {}" \ .format(self._clock_source)) self.log.debug("Reference clock frequency is: {} MHz" \ .format(self.get_ref_clock_freq()/1e6)) # Enable the Ref Clock in the FPGA after giving it a chance to # settle. The settling time is a guess. time.sleep(0.100) self.mboard_regs_control.enable_ref_clk(True) self.log.debug("Setting time source to `{}'".format(time_source)) self._time_source = time_source ref_clk_freq = self.get_ref_clock_freq() self.mboard_regs_control.set_time_source(time_source, ref_clk_freq) if time_source == 'sfp0': # This error is specific to slave and master mode for White Rabbit. # Grand Master mode will require the external or gpsdo # sources (not supported). if time_source in ('sfp0', 'sfp1') \ and self.get_clock_source() != 'internal': error_msg = "Time source {} requires `internal` clock source!".format( time_source) self.log.error(error_msg) raise RuntimeError(error_msg) sfp_time_source_images = ('WX',) if self.updateable_components['fpga']['type'] not in sfp_time_source_images: self.log.error("{} time source requires FPGA types {}" \ .format(time_source, sfp_time_source_images)) raise RuntimeError("{} time source requires FPGA types {}" \ .format(time_source, sfp_time_source_images)) # Only open UIO to the WR core once we're guaranteed it exists. wr_regs_control = WhiteRabbitRegsControl( self.wr_regs_label, self.log) # Wait for time source to become ready. Only applies to SFP0/1. All other # targets start their PPS immediately. self.log.debug("Waiting for {} timebase to lock..." \ .format(time_source)) if not poll_with_timeout( lambda: wr_regs_control.get_time_lock_status(), 40000, # Try for x ms... this number is set from a few benchtop tests 1000, # Poll every... second! why not? ): self.log.error("{} timebase failed to lock within 40 seconds. Status: 0x{:X}" \ .format(time_source, wr_regs_control.get_time_lock_status())) raise RuntimeError("Failed to lock SFP timebase.") # Update the DB with the correct Ref Clock frequency and force a re-init. for slot, dboard in enumerate(self.dboards): self.log.trace( "Updating reference clock on dboard %d to %f MHz...", slot, ref_clk_freq/1e6 ) dboard.update_ref_clock_freq( ref_clk_freq, time_source=time_source, clock_source=clock_source, skip_rfic=args.get('skip_rfic', None) )