def write(self, data): """Write SPI data to shift register register and start transfer. * The ``data`` register and the shift register are 32 bits wide. * Data writes take one ``ref_period`` cycle. * A transaction consisting of a single transfer (``SPI_END``) takes :attr:`xfer_duration_mu` ``=(n + 1)*div`` cycles RTIO time where ``n`` is the number of bits and ``div`` is the SPI clock divider. * Transfers in a multi-transfer transaction take up to one SPI clock cycle less time depending on multiple parameters. Advanced users may rewind the timeline appropriately to achieve faster multi-transfer transactions. * The SPI core will be busy for the duration of the SPI transfer. * For bit alignment and bit ordering see :meth:`set_config`. * The SPI core can only be written to when it is idle or waiting for the next transfer data. Writing (:meth:`set_config`, :meth:`set_config_mu` or :meth:`write`) when the core is busy will result in an RTIO busy error being logged. This method advances the timeline by the duration of one single-transfer SPI transaction (:attr:`xfer_duration_mu`). :param data: SPI output data to be written. """ rtio_output((self.channel << 8) | SPI_DATA_ADDR, data) delay_mu(self.xfer_duration_mu)
def write(self, data=0): """Write data to data register. * The ``data`` register and the shift register are 32 bits wide. If there are no writes to the register, ``miso`` data reappears on ``mosi`` after 32 cycles. * A wishbone data register write is acknowledged when the transfer has been written to the intermediate buffer. It will be started when there are no other transactions being executed, either beginning a new SPI transfer of chained to an in-flight transfer. * Writes take three ``ref_period`` cycles unless another chained transfer is pending and the transfer being executed is not complete. * The SPI ``data`` register is double-buffered: Once a transfer has started, new write data can be written, queuing a new transfer. Transfers submitted this way are chained and executed without deasserting ``cs`` in between. Once a transfer completes, the previous transfer's read data is available in the ``data`` register. * For bit alignment and bit ordering see :meth:`set_config`. This method advances the timeline by the duration of the SPI transfer. If a transfer is to be chained, the timeline needs to be rewound. """ rtio_output(now_mu(), self.channel, SPI_DATA_ADDR, data) delay_mu(self.xfer_period_mu + self.write_period_mu)
def set_iq_en(self, i_enable: TInt32, q_enable: TInt32): """Enable I/Q data on this DAC channel. Every pair of SAWG channels forms a buddy pair. The ``iq_en`` configuration controls which DDS data is emitted to the DACs. Refer to the documentation of :class:`SAWG` for a mathematical description of ``i_enable`` and ``q_enable``. .. note:: Quadrature data from the buddy channel is currently a technological preview only. The data is ignored in the SAWG gateware and not added to the DAC output. This is equivalent to the ``q_enable`` switch always being ``0``. :param i_enable: Controls adding the in-phase DUC-DDS data of *this* SAWG channel to *this* DAC channel. Default: ``1``. :param q_enable: controls adding the quadrature DUC-DDS data of this SAWG's *buddy* channel to *this* DAC channel. Default: ``0``. """ rtio_output(now_mu(), self.channel, _SAWG_IQ_EN, i_enable | (q_enable << 1)) delay_mu(self._rtio_interval)
def write(self, addr, data): """Write data to a Fastino register. :param addr: Address to write to. :param data: Data to write. """ rtio_output(self.channel | addr, data)
def set_iq_en(self, i_enable: TInt32, q_enable: TInt32): """Enable I/Q data on this DAC channel. Every pair of SAWG channels forms a buddy pair. The ``iq_en`` configuration controls which DDS data is emitted to the DACs. Refer to the documentation of :class:`SAWG` for a mathematical description of ``i_enable`` and ``q_enable``. .. note:: Quadrature data from the buddy channel is currently a technological preview only. The data is ignored in the SAWG gateware and not added to the DAC output. This is equivalent to the ``q_enable`` switch always being ``0``. :param i_enable: Controls adding the in-phase DUC-DDS data of *this* SAWG channel to *this* DAC channel. Default: ``1``. :param q_enable: controls adding the quadrature DUC-DDS data of this SAWG's *buddy* channel to *this* DAC channel. Default: ``0``. """ rtio_output((self.channel << 8) | _SAWG_IQ_EN, i_enable | (q_enable << 1)) delay_mu(self._rtio_interval)
def set_config_mu(self, flags, length, div, cs): """Set the ``config`` register (in SPI bus machine units). .. seealso:: :meth:`set_config` :param flags: A bit map of `SPI_*` flags. :param length: Number of bits to write during the next transfer. (reset=1) :param div: Counter load value to divide the RTIO clock by to generate the SPI clock. (minimum=2, reset=2) ``f_rtio_clk/f_spi == div``. If ``div`` is odd, the setup phase of the SPI clock is one coarse RTIO clock cycle longer than the hold phase. :param cs: Bit pattern of chip selects to assert. Or number of the chip select to assert if ``cs`` is decoded downstream. (reset=0) """ if length > 32 or length < 1: raise ValueError("Invalid SPI transfer length") if div > 257 or div < 2: raise ValueError("Invalid SPI clock divider") rtio_output((self.channel << 8) | SPI_CONFIG_ADDR, flags | ((length - 1) << 8) | ((div - 2) << 16) | (cs << 24)) self.update_xfer_duration_mu(div, length) delay_mu(self.ref_period_mu)
def set_config_mu(self, flags, length, div, cs): """Set the ``config`` register (in SPI bus machine units). .. seealso:: :meth:`set_config` :param flags: A bit map of `SPI_*` flags. :param length: Number of bits to write during the next transfer. (reset=1) :param div: Counter load value to divide the RTIO clock by to generate the SPI clock. (minimum=2, reset=2) ``f_rtio_clk/f_spi == div``. If ``div`` is odd, the setup phase of the SPI clock is one coarse RTIO clock cycle longer than the hold phase. :param cs: Bit pattern of chip selects to assert. Or number of the chip select to assert if ``cs`` is decoded downstream. (reset=0) """ if length > 32 or length < 1: raise ValueError("Invalid SPI transfer length") if div > 257 or div < 2: raise ValueError("Invalid SPI clock divider") rtio_output( (self.channel << 8) | SPI_CONFIG_ADDR, flags | ((length - 1) << 8) | ((div - 2) << 16) | (cs << 24)) self.update_xfer_duration_mu(div, length) delay_mu(self.ref_period_mu)
def write8(self, addr, data): """Write data to FPGA register. :param addr: Address to write to (7 bit) :param data: Data to write (8 bit) """ rtio_output((self.channel_base << 8) | (addr & 0x7f) | 0x80, data) delay_mu(int64(self.t_frame))
def measure_frame_timestamp(self): """Measure the timestamp of an arbitrary frame and store it in `self.frame_tstamp`. To be used as reference for aligning updates to the FastLink frames. See `get_next_frame_mu()`. """ rtio_output(self.channel_base << 8, 0) # read any register self.frame_tstamp = rtio_input_timestamp(now_mu() + 4 * self.t_frame, self.channel_base) delay(100 * us)
def enable_source(self, adr, idx): self.core.break_realtime() rtio_output(self.channel << 8 | (adr + 2) << 1 | 0, 0) delay_mu(8) value = rtio_input_data(self.channel) delay_mu(10000) value |= (1 << idx) rtio_output(self.channel << 8 | (adr + 2) << 1 | 1, value) delay_mu(8)
def read(self, addr): """Read parameter This method does not advance the timeline but consumes all slack. :param addr: Memory location address. """ rtio_output((self.channel << 8) | addr, 0) return rtio_input_data(self.channel)
def set_amplitude_phase_mu(self, asf=0x7fff, pow=0, clr=0): """Set Phaser MultiDDS amplitude, phase offset and accumulator clear. :param asf: Amplitude (15 bit) :param pow: Phase offset word (16 bit) :param clr: Clear the phase accumulator (persistent) """ data = (asf & 0x7fff) | ((clr & 1) << 15) | (pow << 16) rtio_output(self.base_addr + (1 << 8), data)
def read(self, addr): """Read from servo memory. This method does not advance the timeline but consumes all slack. :param addr: Memory location address. """ rtio_output(now_mu(), self.channel, addr, 0) return rtio_input_data(self.channel)
def read8(self, addr) -> TInt32: """Read from FPGA register. :param addr: Address to read from (7 bit) :return: Data read (8 bit) """ rtio_output((self.channel_base << 8) | (addr & 0x7f), 0) response = rtio_input_data(self.channel_base) return response >> self.miso_delay
def read(self, addr): """Read from Fastino register. TODO: untested :param addr: Address to read from. :return: The data read. """ rtio_output(self.channel | addr | 0x80) return rtio_input_data(self.channel >> 8)
def write(self, addr, value): """Write parameter. This method advances the timeline by one coarse RTIO cycle. :param addr: parameter address. :param value: Data to be written. """ rtio_output((self.channel << 8) | addr, value) delay_mu(self.ref_period_mu)
def write(self, addr, value): """Write to servo memory. This method advances the timeline by one coarse RTIO cycle. :param addr: Memory location address. :param value: Data to be written. """ rtio_output(now_mu(), self.channel, addr | WE, value) delay_mu(self.ref_period_mu)
def set(self, en_out, en_iir=0, profile=0): """Operate channel. This method does not advance the timeline. :param en_out: RF switch enable :param en_iir: IIR updates enable :param profile: Active profile (0-31) """ rtio_output(now_mu(), self.channel, 0, en_out | (en_iir << 1) | (profile << 2))
def set(self, value: TFloat): """Set spline value. :param value: Spline value relative to full-scale. """ if self.width > 32: l = [int32(0)] * 2 self.pack_coeff_mu([self.to_mu64(value)], l) rtio_output_wide(now_mu(), self.channel, 0, l) else: rtio_output(now_mu(), self.channel, 0, self.to_mu(value))
def read(self, addr): """Read from servo memory. This method does not advance the timeline but consumes all slack. :param addr: Memory location address. """ value = (addr >> 8) << COEFF_WIDTH addr = addr & 0xff rtio_output((self.channel << 8) | addr, value) return rtio_input_data(self.channel)
def set(self, value: TFloat): """Set spline value. :param value: Spline value relative to full-scale. """ if self.width > 32: l = [int32(0)] * 2 self.pack_coeff_mu([self.to_mu64(value)], l) rtio_output_wide(self.channel << 8, l) else: rtio_output(self.channel << 8, self.to_mu(value))
def read_async(self): """Trigger an asynchronous read from the ``data`` register. Reads always finish in two cycles. Every data register read triggered by a :meth:`read_async` must be matched by a :meth:`input_async` to retrieve the data. This method advances the timeline by the duration of the RTIO-to-Wishbone bus transaction (three RTIO clock cycles). """ rtio_output(now_mu(), self.channel, SPI_DATA_ADDR | SPI_RT2WB_READ, 0) delay_mu(3 * self.ref_period_mu)
def watch_stay_on(self): """Checks that the input is at a high level at the position of the time cursor and keep checking until :meth:`watch_done` is called. Returns ``True`` if the input is high. A call to this function must always be followed by an eventual call to :meth:`watch_done` (use e.g. a try/finally construct to ensure this). The time cursor is not modified by this function. """ rtio_output(self.target_sample, 2) # gate falling return rtio_input_data(self.channel) == 1
def read_async(self): """Trigger an asynchronous read from the ``data`` register. Reads always finish in two cycles. Every data register read triggered by a :meth:`read_async` must be matched by a :meth:`input_async` to retrieve the data. This method advances the timeline by the duration of the RTIO-to-Wishbone bus transaction (three RTIO clock cycles). """ rtio_output(now_mu(), self.channel, SPI_DATA_ADDR | SPI_RT2WB_READ, 0) delay_mu(3*self.ref_period_mu)
def write(self, addr, value): """Write to servo memory. This method advances the timeline by one coarse RTIO cycle. :param addr: Memory location address. :param value: Data to be written. """ addr |= WE value |= (addr >> 8) << COEFF_WIDTH addr = addr & 0xff rtio_output((self.channel << 8) | addr, value) delay_mu(self.ref_period_mu)
def set_duc_max_mu(self, limit: TInt32): """Set the digital up-converter (DUC) I and Q data summing junctions upper limit. In machine units. The default limits are chosen to reach maximum and minimum DAC output amplitude. For a description of the limiter functions in normalized units see: .. seealso:: :meth:`set_duc_max` """ rtio_output((self.channel << 8) | _SAWG_DUC_MAX, limit) delay_mu(self._rtio_interval)
def set_duc_max_mu(self, limit: TInt32): """Set the digital up-converter (DUC) I and Q data summing junctions upper limit. In machine units. The default limits are chosen to reach maximum and minimum DAC output amplitude. For a description of the limiter functions in normalized units see: .. seealso:: :meth:`set_duc_max` """ rtio_output(now_mu(), self.channel, _SAWG_DUC_MAX, limit) delay_mu(self._rtio_interval)
def set(self, en_out, en_iir=0, profile=0): """Operate channel. This method does not advance the timeline. Output RF switch setting takes effect immediately. IIR updates take place once the RF switch has been enabled for the configured delay and the profile setting has been stable. :param en_out: RF switch enable :param en_iir: IIR updates enable :param profile: Active profile (0-31) """ rtio_output(now_mu(), self.channel, 0, en_out | (en_iir << 1) | (profile << 2))
def write(self, addr, value): """Write to servo memory. This method advances the timeline by one coarse RTIO cycle. :param addr: Memory location address. :param value: Data to be written. """ addr |= WE value &= (1 << COEFF_WIDTH) - 1 value |= (addr >> 8) << COEFF_WIDTH addr = addr & 0xff rtio_output((self.channel << 8) | addr, value) delay_mu(self.ref_period_mu)
def read(self, addr): """Read parameter. This method does not advance the timeline but consumes all slack. Args: addr: Memory location address. Returns: Value of the ``Entangler`` setting (register) that you are querying. """ rtio_output((self.channel << 8) | addr, 0) return rtio_input_data(self.channel)
def set_div(self, div: TInt32, n: TInt32=0): """Set the spline evolution divider and current counter value. The divider and the spline evolution are synchronized across all spline channels within a SAWG channel. The DDS/DUC phase accumulators always evolves at full speed. .. note:: The spline evolution divider has not been tested extensively and is currently considered a technological preview only. :param div: Spline evolution divider, such that ``t_sawg_spline/t_rtio_coarse = div + 1``. Default: ``0``. :param n: Current value of the counter. Default: ``0``. """ rtio_output(now_mu(), self.channel, _SAWG_DIV, div | (n << 16)) delay_mu(self._rtio_interval)
def set_config_mu(self, flags=0, write_div=6, read_div=6): """Set the ``config`` register (in SPI bus machine units). .. seealso:: :meth:`set_config` :param write_div: Counter load value to divide the RTIO clock by to generate the SPI write clk. (minimum=2, reset=2) ``f_rtio_clk/f_spi_write == write_div``. If ``write_div`` is odd, the setup phase of the SPI clock is biased to longer lengths by one RTIO clock cycle. :param read_div: Ditto for the read clock. """ rtio_output(now_mu(), self.channel, SPI_CONFIG_ADDR, flags | ((write_div - 2) << 16) | ((read_div - 2) << 24)) self.write_period_mu = int(write_div * self.ref_period_mu) self.read_period_mu = int(read_div * self.ref_period_mu) delay_mu(3 * self.ref_period_mu)
def set_div(self, div: TInt32, n: TInt32 = 0): """Set the spline evolution divider and current counter value. The divider and the spline evolution are synchronized across all spline channels within a SAWG channel. The DDS/DUC phase accumulators always evolves at full speed. .. note:: The spline evolution divider has not been tested extensively and is currently considered a technological preview only. :param div: Spline evolution divider, such that ``t_sawg_spline/t_rtio_coarse = div + 1``. Default: ``0``. :param n: Current value of the counter. Default: ``0``. """ rtio_output((self.channel << 8) | _SAWG_DIV, div | (n << 16)) delay_mu(self._rtio_interval)
def set(self, en_out, en_iir=0, profile=0): """Operate channel. This method does not advance the timeline. Output RF switch setting takes effect immediately and is independent of any other activity (profile settings, other channels). The RF switch behaves like :class:`artiq.coredevice.ttl.TTLOut`. RTIO event replacement is supported. IIR updates take place once the RF switch has been enabled for the configured delay and the profile setting has been stable. Profile changes take between one and two servo cycles to reach the DDS. :param en_out: RF switch enable :param en_iir: IIR updates enable :param profile: Active profile (0-31) """ rtio_output(self.channel << 8, en_out | (en_iir << 1) | (profile << 2))
def watch_done(self): """Stop watching the input at the position of the time cursor. Returns ``True`` if the input has not changed state while it was being watched. The time cursor is not modified by this function. This function always makes the slack negative. """ rtio_output(now_mu(), self.channel, 2, 0) success = True try: while rtio_input_timestamp(now_mu(), self.channel) != -1: success = False except RTIOOverflow: success = False return success
def watch_done(self): """Stop watching the input at the position of the time cursor. Returns ``True`` if the input has not changed state while it was being watched. The time cursor is not modified by this function. This function always makes the slack negative. """ rtio_output(self.target_sens, 0) success = True try: while rtio_input_timestamp(now_mu() + self.gate_latency_mu, self.channel) != -1: success = False except RTIOOverflow: success = False return success
def gate_roi(self, mask): """ Defines which ROI engines produce input events. At the end of each video frame, the output from each ROI engine that has been enabled by the mask is enqueued into the RTIO input FIFO. This function sets the mask at the current position of the RTIO time cursor. Setting the mask using this function is atomic; in other words, if the system is in the middle of processing a frame and the mask is changed, the processing will complete using the value of the mask that it started with. :param mask: bitmask enabling or disabling each ROI engine. """ rtio_output((self.channel_base + 1) << 8, mask)
def set_mu(self, frequency): """Set the frequency of the clock, in machine units, at the current position of the time cursor. This also sets the phase, as the time of the first generated rising edge corresponds to the time of the call. The clock generator contains a 24-bit phase accumulator operating on the RTIO clock. At each RTIO clock tick, the frequency tuning word is added to the phase accumulator. The most significant bit of the phase accumulator is connected to the TTL line. Setting the frequency tuning word has the additional effect of setting the phase accumulator to 0x800000. Due to the way the clock generator operates, frequency tuning words that are not powers of two cause jitter of one RTIO clock cycle at the output.""" rtio_output(self.target, frequency)
def set_xfer(self, chip_select=0, write_length=0, read_length=0): """Set the ``xfer`` register. * Every transfer consists of a write of ``write_length`` bits immediately followed by a read of ``read_length`` bits. * ``cs_n`` is asserted at the beginning and deasserted at the end of the transfer if there is no other transfer pending. * ``cs_n`` handling is agnostic to whether it is one-hot or decoded somewhere downstream. If it is decoded, "``cs_n`` all deasserted" should be handled accordingly (no slave selected). If it is one-hot, asserting multiple slaves should only be attempted if ``miso`` is either not connected between slaves, or open collector, or correctly multiplexed externally. * For 4-wire SPI only the sum of ``read_length`` and ``write_length`` matters. The behavior is the same (except for clock speeds) no matter how the total transfer length is divided between the two. For 3-wire SPI, the direction of ``mosi`` is switched from output to input after ``write_length`` bits. * Data output on ``mosi`` in 4-wire SPI during the read cycles is what is found in the data register at the time. Data in the ``data`` register outside the least/most (depending on ``config.lsb_first``) significant ``read_length`` bits is what is seen on ``miso`` (or ``mosi`` if ``config.half_duplex``) during the write cycles. * Writes to ``xfer`` are synchronized to the start of the next (possibly chained) transfer. This method advances the timeline by the duration of the RTIO-to-Wishbone bus transaction (three RTIO clock cycles). :param chip_select: Bit mask of chip selects to assert. Or number of the chip select to assert if ``cs`` is decoded downstream. (reset=0) :param write_length: Number of bits to write during the next transfer. (reset=0) :param read_length: Number of bits to read during the next transfer. (reset=0) """ rtio_output(now_mu(), self.channel, SPI_XFER_ADDR, chip_select | (write_length << 16) | (read_length << 24)) self.xfer_period_mu = int(write_length*self.write_period_mu + read_length*self.read_period_mu) delay_mu(3*self.ref_period_mu)
def set_clr(self, clr0: TInt32, clr1: TInt32, clr2: TInt32): """Set the accumulator clear mode for the three phase accumulators. When the ``clr`` bit for a given DDS/DUC phase accumulator is set, that phase accumulator will be cleared with every phase offset RTIO command and the output phase of the DDS/DUC will be exactly the phase RTIO value ("absolute phase update mode"). .. math:: q^\prime(t) = p^\prime + (t - t^\prime) f^\prime In turn, when the bit is cleared, the phase RTIO channels determine a phase offset to the current (carrier-) value of the DDS/DUC phase accumulator. This "relative phase update mode" is sometimes also called “continuous phase mode”. .. math:: q^\prime(t) = q(t^\prime) + (p^\prime - p) + (t - t^\prime) f^\prime Where: * :math:`q`, :math:`q^\prime`: old/new phase accumulator * :math:`p`, :math:`p^\prime`: old/new phase offset * :math:`f^\prime`: new frequency * :math:`t^\prime`: timestamp of setting new :math:`p`, :math:`f` * :math:`t`: running time :param clr0: Auto-clear phase accumulator of the ``phase0``/ ``frequency0`` DUC. Default: ``True`` :param clr1: Auto-clear phase accumulator of the ``phase1``/ ``frequency1`` DDS. Default: ``True`` :param clr2: Auto-clear phase accumulator of the ``phase2``/ ``frequency2`` DDS. Default: ``True`` """ rtio_output(now_mu(), self.channel, _SAWG_CLR, clr0 | (clr1 << 1) | (clr2 << 2)) delay_mu(self._rtio_interval)
def setup_roi(self, n, x0, y0, x1, y1): """ Defines the coordinates of a ROI. The coordinates are set around the current position of the RTIO time cursor. The user must keep the ROI engine disabled for the duration of more than one video frame after calling this function, as the output generated for that video frame is undefined. Advances the timeline by 4 coarse RTIO cycles. """ c = int64(self.core.ref_multiplier) rtio_output((self.channel_base << 8) | (4*n+0), x0) delay_mu(c) rtio_output((self.channel_base << 8) | (4*n+1), y0) delay_mu(c) rtio_output((self.channel_base << 8) | (4*n+2), x1) delay_mu(c) rtio_output((self.channel_base << 8) | (4*n+3), y1) delay_mu(c)
def _get_xfer_sync(self): rtio_output(now_mu(), self.channel, SPI_XFER_ADDR | SPI_RT2WB_READ, 0) return rtio_input_data(self.channel)
def set_mu(self, value: TInt32): """Set spline value (machine units). :param value: Spline value in integer machine units. """ rtio_output(self.channel << 8, value)
def set_oe(self, oe): rtio_output(now_mu(), self.channel, 1, 1 if oe else 0)
def watch_stay_off(self): """Like :meth:`watch_stay_on`, but for low levels.""" rtio_output(self.target_sample, 1) # gate rising return rtio_input_data(self.channel) == 0
def _set_sensitivity(self, value): rtio_output(now_mu(), self.channel, 2, value) self.i_previous_timestamp = now_mu()
def set_o(self, o): rtio_output(now_mu(), self.channel, 0, 1 if o else 0) self.o_previous_timestamp = now_mu()
def set_out_max_mu(self, limit: TInt32): """.. seealso:: :meth:`set_duc_max_mu`""" rtio_output((self.channel << 8) | _SAWG_OUT_MAX, limit) delay_mu(self._rtio_interval)
def set_o(self, o): rtio_output(self.target_o, 1 if o else 0)
def write(self, addr, data): rtio_output((self.bus_channel << 8) | addr, data) delay_mu(self.write_duration_mu)
def _get_config_sync(self): rtio_output(now_mu(), self.channel, SPI_CONFIG_ADDR | SPI_RT2WB_READ, 0) return rtio_input_data(self.channel)
def set_out_min_mu(self, limit: TInt32): """.. seealso:: :meth:`set_duc_max_mu`""" rtio_output(now_mu(), self.channel, _SAWG_OUT_MIN, limit) delay_mu(self._rtio_interval)