Source code for FIREQ_LL_API.trigger_generator_driver

"""Low-level driver for the FIREQ trigger generator IP."""

from ._utils import _FIREQDriver

__all__ = ["TriggerGeneratorDriver"]


[docs] class TriggerGeneratorDriver(_FIREQDriver): """Driver class for the trigger generator IP. Provides methods to set the generation time of pulses and acquisition events. """ bindto = ["user.org:user:axisTriggerGeneratorIP:1.0"] # Register offset definitions _ctrl = 0 _experiment_dur_l = 2 _experiment_dur_h = 3 _shots_num_l = 1 # Bit position definition _manual_trigger_pos = 31 # Port name of the fabric clock fabric_clock_port = "HS_axi_clock" def __init__(self, description: dict[str, object]) -> None: """Initialize the TriggerGeneratorDriver. :param description: Dictionary containing IP parameters and configuration :type description: dict """ super().__init__(description=description) # parse the number of channels of the trigger generator self.trigger_channels = int(description["parameters"]["TriggerWordWidth"]) # depth of the axi full interface, also equal to the total depth of internal memory mapped fifos self.fifo_interface_memory_depth = pow(2, int(description["parameters"]["C_S00_AXI_ADDR_WIDTH"])) # fifo depth in number of words self.channel_fifo_depth = pow(2, int(description["parameters"]["FifoAddressWidth"])) # fifo output width # self.fifo_output_width = int(description["parameters"]["DriveTimerWidth"]) # maximum drive delay self.drive_delay_max = pow(2, int(description["parameters"]["DriveTimerWidth"])) # experiment max self.experiment_timer_max = pow(2, int(description["parameters"]["ExperimentTimerWidth"])) # parse the size of the repetition counter self.max_hw_repetitions = pow(2, int(description["parameters"]["RepetitionWidth"]))
[docs] def reset_memory_and_registers(self) -> None: """Reset all memory and registers to 0.""" for offset in range(0, self._axi_lite_interface_mmio.length, 4): self._axi_lite_interface_mmio.write(offset, 0) for offset in range(0, self._axi_full_interface_mmio.length, 4): self._axi_full_interface_mmio.write(offset, 0)
[docs] def print_description(self, printer_func: callable) -> None: """Print the description of the trigger generator IP. :param: printer_func: Function to use to print the description :type printer_func: callable """ printer_func(f"trigger_channels: {self.trigger_channels}") printer_func(f"fifo_interface_axi_depth: {self.fifo_interface_memory_depth}") printer_func(f"fifo_channel_depth: {self.channel_fifo_depth}") printer_func(f"maximum_number_of_hardware_repetitions: {self.max_hw_repetitions}")
[docs] def init_axi_full_interface(self, base_address: int, axi_depth: int) -> None: """Initialize the AXI Full interface for this IP. :param base_address: Base address of the AXI Full interface :type base_address: int :param axi_depth: Depth of the AXI interface in bytes :type axi_depth: int """ super().init_axi_full_interface(base_address, axi_depth)
[docs] def init_axi_lite_interface(self, base_address: int, axi_depth: int) -> None: """Initialize the AXI Lite interface for this IP. :param base_address: Base address of the AXI Lite interface :type base_address: int :param axi_depth: Depth of the AXI interface in bytes :type axi_depth: int """ super().init_axi_lite_interface(base_address, axi_depth) # delete the mmio object created by PYNQ del self.mmio
[docs] def set_experiment_duration(self, duration: int) -> None: """Set the experiment duration for a single shot. :param duration: Duration in clock cycles :type duration: int """ # write duration LOW self._axi_lite_interface_mmio.write(self._experiment_dur_l * 4, duration & 0xFFFFFFFF) # write duration HIGH self._axi_lite_interface_mmio.write(self._experiment_dur_h * 4, duration >> 32) self.log.debug("Set the expreriment duration to %s", duration) return 0
[docs] def set_number_of_shots(self, value: int) -> int: """Set the number of shots to execute in hardware. :param value: Number of shots (must be between 1 and max_hw_repetitions) :type value: int :return: Error code (0 on success) :rtype: int """ if value < 1 or value > self.max_hw_repetitions: self.log.error("number of shots %s is outside of range 1 to %s", value, self.max_hw_repetitions) return -3 self._axi_lite_interface_mmio.write(self._shots_num_l * 4, int(value - 1)) self.log.debug("Set the number of hw shots to %s", value) return 0
[docs] def start_experiment(self) -> None: """Start the generation of triggers.""" self._axi_lite_interface_mmio.write(self._ctrl * 4, 1 << self._manual_trigger_pos) self.log.debug("Trigger generator started") return 0
[docs] def is_done(self) -> bool: """Check if the experiment is finished. :return: True if the experiment is finished, False if still running :rtype: bool """ control_register = self._axi_lite_interface_mmio.read(self._ctrl * 4) return (control_register & 0x40000000) == 0x40000000
[docs] def insert_delay(self, trigger_mask: int, ttype: bool, index: int, delay: int) -> int: """Insert a delay in the trigger generator at `index`. The ``trigger_mask`` input defines the triggers that will be set once the delay expires. :param trigger_mask: Trigger channels to activate (Fifthen bit mask, e.g. 0b0010 means channel 2) :type trigger_mask: int :param ttype: Trigger type (True for readout, False for drive) :type ttype: bool :param index: FIFO index (1 is the first delay) :type index: int :param delay: Delay in clock cycles (1 to drive_delay_max) :type delay: int :return: Error code (0 on success) :rtype: int """ if trigger_mask < 0 or trigger_mask > pow(2, self.trigger_channels) - 1: self.log.error(f"source {trigger_mask} is outside of range 0 to {pow(2,self.trigger_channels) - 1}") return -3 if index < 1 or index > self.channel_fifo_depth // 2: self.log.error(f"index {index} is outside of range 1 to {self.channel_fifo_depth // 2}") return -3 if delay < 1 or delay > self.drive_delay_max: self.log.error(f"delay {delay} is outside of range 1 to {self.drive_delay_max}") return -3 source_index = ((index - 1) * 2) + 0 delay_index = ((index - 1) * 2) + 1 mask = (int(ttype) << 15) | (trigger_mask & 0x7FFF) self._axi_full_interface_mmio.write(delay_index * 4, int(delay) - 1) self._axi_full_interface_mmio.write(source_index * 4, int(mask)) self.log.debug( "Inserted a delay with trigger_mask: %s, type: %s, index: %s and delay: %s, ", trigger_mask, ttype, index, delay, ) return 0