Exemplo n.º 1
0
    def trf_write(self, data, readback=False):
        """Write 32 bits to quadrature upconverter register.

        :param data: Register data (32 bit) containing encoded address
        :param readback: Whether to return the read back MISO data
        """
        div = 34  # 50 ns min period
        t_xfer = self.phaser.core.seconds_to_mu((8 + 1) * div * 4 * ns)
        read = 0
        end = 0
        clk_phase = 0
        if readback:
            clk_phase = 1
        for i in range(4):
            if i == 0 or i == 3:
                if i == 3:
                    end = 1
                self.phaser.spi_cfg(select=PHASER_SEL_TRF0 << self.index,
                                    div=div,
                                    lsb_first=1,
                                    clk_phase=clk_phase,
                                    end=end)
            self.phaser.spi_write(data)
            data >>= 8
            delay_mu(t_xfer)
            if readback:
                read >>= 8
                read |= self.phaser.spi_read() << 24
                delay(20 * us)  # slack
        return read
Exemplo n.º 2
0
    def set_dac_mu(self, values, channels=list(range(40))):
        """Program multiple DAC channels and pulse LDAC to update the DAC
        outputs.

        This method does not advance the timeline; write events are scheduled
        in the past. The DACs will synchronously start changing their output
        levels `now`.

        If no LDAC device was defined, the LDAC pulse is skipped.

        See :meth load:.

        :param values: list of DAC values to program
        :param channels: list of DAC channels to program. If not specified,
          we program the DAC channels sequentially, starting at 0.
        """
        t0 = now_mu()

        # t10: max busy period after writing to DAC registers
        t_10 = self.core.seconds_to_mu(1500 * ns)
        # compensate all delays that will be applied
        delay_mu(-t_10 - len(values) * self.bus.xfer_duration_mu)
        for i in range(len(values)):
            self.write_dac_mu(channels[i], values[i])
        delay_mu(t_10)
        self.load()
        at_mu(t0)
Exemplo n.º 3
0
    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)
Exemplo n.º 4
0
Arquivo: spi.py Projeto: cjbe/artiq
    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)
Exemplo n.º 5
0
    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)
Exemplo n.º 6
0
 def write32(self, addr, data):
     self.bus.set_xfer(self.chip_select, 8, 0)
     self.bus.write(addr << 24)
     delay_mu(-self.bus.xfer_period_mu)
     self.bus.set_xfer(self.chip_select, 32, 0)
     self.bus.write(data)
     delay_mu(self.bus.xfer_period_mu - self.bus.write_period_mu)
Exemplo n.º 7
0
Arquivo: spi2.py Projeto: m-labs/artiq
    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)
Exemplo n.º 8
0
Arquivo: spi2.py Projeto: m-labs/artiq
    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)
Exemplo n.º 9
0
    def test_not_deep_parallel(self):
        # Deep parallel does not match the timing model of ARTIQ, see https://github.com/m-labs/artiq/issues/1555
        # But DAX.sim implements deep parallel! The parallel semantics of ARTIQ and DAX.sim differ here!

        for i in range(_NUM_SAMPLES):
            with self.subTest('parallel sub test', i=i):
                # Reference time
                ref_time = now_mu()

                # Block duration
                block_duration = 0
                with parallel:
                    for _ in range(10):  # Only the for-loop is a top-level statement, not the content inside the loop!
                        # with sequential:  # The implicit sequential context will be added here
                        # Random duration
                        duration = self.rnd.randrange(1000000000)
                        # Delay
                        delay_mu(duration)
                        # Update block duration
                        block_duration += duration  # Add duration to block duration, implicit sequential

                # Update ref time
                ref_time += block_duration
                # Compare to reference time
                self.assertEqual(now_mu(), ref_time, 'Reference does not match now_mu()')
Exemplo n.º 10
0
    def test_explicit_shallow_parallel(self):
        # Shallow parallel matches the timing model of ARTIQ, see https://github.com/m-labs/artiq/issues/1555

        for i in range(_NUM_SAMPLES):
            with self.subTest('parallel sub test', i=i):
                # Reference time
                ref_time = now_mu()

                # Block duration
                block_duration = 0
                # Single random duration
                duration = self.rnd.randrange(1000000000)

                with parallel:
                    # Delay
                    delay_mu(duration)
                    # Update block duration
                    block_duration = max(duration, block_duration)  # Top-level statement, so parallel

                    if True:
                        # We are not a top level statement anymore, so timing is sequential
                        with sequential:  # Add an explicit sequential context!
                            sequential_duration = 0
                            for _ in range(10):
                                delay_mu(duration)
                                sequential_duration += duration

                            # Parallelize the sequential block with other parallel top-level statements
                            block_duration = max(sequential_duration, block_duration)

                # Update ref time
                ref_time += block_duration
                # Compare to reference time
                self.assertEqual(now_mu(), ref_time, 'Reference does not match now_mu()')
Exemplo n.º 11
0
    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)
Exemplo n.º 12
0
    def set_dac_mu(self, values, channels=list(range(40))):
        """Program multiple DAC channels and pulse LDAC to update the DAC
        outputs.

        This method does not advance the timeline; write events are scheduled
        in the past. The DACs will synchronously start changing their output
        levels `now`.

        If no LDAC device was defined, the LDAC pulse is skipped.

        See :meth load:.

        :param values: list of DAC values to program
        :param channels: list of DAC channels to program. If not specified,
          we program the DAC channels sequentially, starting at 0.
        """
        t0 = now_mu()

        # t10: max busy period after writing to DAC registers
        t_10 = self.core.seconds_to_mu(1500*ns)
        # compensate all delays that will be applied
        delay_mu(-t_10-len(values)*self.bus.xfer_duration_mu)
        for i in range(len(values)):
            self.write_dac_mu(channels[i], values[i])
        delay_mu(t_10)
        self.load()
        at_mu(t0)
Exemplo n.º 13
0
    def write(self, data):
        """Write 24 bits of data.

        This method advances the timeline by the duration of the SPI transfer
        and the required CS high time.
        """
        self.bus.write(data << 8)
        delay_mu(self.bus.ref_period_mu)  # get to 20ns min cs high
Exemplo n.º 14
0
    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))
Exemplo n.º 15
0
    def set_mu(self,
               ftw,
               pow_=0,
               asf=0x3fff,
               phase_mode=_PHASE_MODE_DEFAULT,
               ref_time_mu=int64(-1),
               profile=0):
        """Set profile 0 data in machine units.

        This uses machine units (FTW, POW, ASF). The frequency tuning word
        width is 32, the phase offset word width is 16, and the amplitude
        scale factor width is 12.

        After the SPI transfer, the shared IO update pin is pulsed to
        activate the data.

        .. seealso: :meth:`set_phase_mode` for a definition of the different
            phase modes.

        :param ftw: Frequency tuning word: 32 bit.
        :param pow_: Phase tuning word: 16 bit unsigned.
        :param asf: Amplitude scale factor: 14 bit unsigned.
        :param phase_mode: If specified, overrides the default phase mode set
            by :meth:`set_phase_mode` for this call.
        :param ref_time_mu: Fiducial time used to compute absolute or tracking
            phase updates. In machine units as obtained by `now_mu()`.
        :param profile: Profile number to set (0-7, default: 0).
        :return: Resulting phase offset word after application of phase
            tracking offset. When using :const:`PHASE_MODE_CONTINUOUS` in
            subsequent calls, use this value as the "current" phase.
        """
        if phase_mode == _PHASE_MODE_DEFAULT:
            phase_mode = self.phase_mode
        # Align to coarse RTIO which aligns SYNC_CLK. I.e. clear fine TSC
        # This will not cause a collision or sequence error.
        at_mu(now_mu() & ~7)
        if phase_mode != PHASE_MODE_CONTINUOUS:
            # Auto-clear phase accumulator on IO_UPDATE.
            # This is active already for the next IO_UPDATE
            self.set_cfr1(phase_autoclear=1)
            if phase_mode == PHASE_MODE_TRACKING and ref_time_mu < 0:
                # set default fiducial time stamp
                ref_time_mu = 0
            if ref_time_mu >= 0:
                # 32 LSB are sufficient.
                # Also no need to use IO_UPDATE time as this
                # is equivalent to an output pipeline latency.
                dt = int32(now_mu()) - int32(ref_time_mu)
                pow_ += dt * ftw * self.sysclk_per_mu >> 16
        self.write64(_AD9910_REG_PROFILE0 + profile,
                     (asf << 16) | (pow_ & 0xffff), ftw)
        delay_mu(int64(self.sync_data.io_update_delay))
        self.cpld.io_update.pulse_mu(8)  # assumes 8 mu > t_SYN_CCLK
        at_mu(now_mu() & ~7)  # clear fine TSC again
        if phase_mode != PHASE_MODE_CONTINUOUS:
            self.set_cfr1()
            # future IO_UPDATE will activate
        return pow_
Exemplo n.º 16
0
    def load(self):
        """Pulse the LDAC line.

        This method advances the timeline by two RTIO clock periods (16 ns).
        """
        self.ldac.off()
        # t13 = 10ns ldac pulse width low
        delay_mu(2*self.bus.ref_period_mu)
        self.ldac.on()
Exemplo n.º 17
0
 def read32(self, addr):
     self.bus.set_xfer(self.chip_select, 8, 0)
     self.bus.write((addr | 0x80) << 24)
     delay_mu(-self.bus.xfer_period_mu)
     self.bus.set_xfer(self.chip_select, 0, 32)
     self.bus.write(0)
     delay_mu(2 * self.bus.xfer_period_mu)
     data = self.bus.read_sync()
     return data
Exemplo n.º 18
0
 def write(self, addr, data, length=1):
     assert length > 0
     assert length <= 4
     self.bus.set_xfer(self.chip_select, 16, 0)
     self.bus.write((addr | ((length - 1) << 13)) << 16)
     delay_mu(-self.bus.xfer_period_mu)
     self.bus.set_xfer(self.chip_select, length * 8, 0)
     self.bus.write(data << (32 - length * 8))
     delay_mu(self.bus.xfer_period_mu - self.bus.write_period_mu)
Exemplo n.º 19
0
 def write64(self, addr, data_high, data_low):
     self.bus.set_xfer(self.chip_select, 8, 0)
     self.bus.write(addr << 24)
     t = self.bus.xfer_period_mu
     delay_mu(-t)
     self.bus.set_xfer(self.chip_select, 32, 0)
     self.bus.write(data_high)
     self.bus.write(data_low)
     delay_mu(t - 2 * self.bus.write_period_mu)
Exemplo n.º 20
0
Arquivo: spi.py Projeto: olsonse/pdq
    def set_reg(self, adr, data, board):
        """Set a PDQ register.

        :param adr: Address of the register (``_PDQ_ADR_CONFIG``,
            ``_PDQ_ADR_FRAME``, ``_PDQ_ADR_CRC``).
        :param data: Register data (8 bit).
        :param board: Board to access, ``0xf`` to write to all boards.
        """
        self.bus.write((PDQ_CMD(board, 0, adr, 1) << 24) | (data << 16))
        delay_mu(self.bus.ref_period_mu)  # get to 20ns min cs high
Exemplo n.º 21
0
    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)
Exemplo n.º 22
0
Arquivo: spi.py Projeto: m-labs/pdq2
    def set_reg(self, adr, data, board):
        """Set a PDQ register.

        :param adr: Address of the register (``_PDQ_ADR_CONFIG``,
            ``_PDQ_ADR_FRAME``, ``_PDQ_ADR_CRC``).
        :param data: Register data (8 bit).
        :param board: Board to access, ``0xf`` to write to all boards.
        """
        self.bus.write((PDQ_CMD(board, 0, adr, 1) << 24) | (data << 16))
        delay_mu(self.bus.ref_period_mu)  # get to 20ns min cs high
Exemplo n.º 23
0
    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)
Exemplo n.º 24
0
 def set_mu(self, ftw=int64(0), pow=int32(0)):
     # do a streaming transfer of FTW and POW
     self.bus.set_xfer(self.chip_select, 16, 0)
     self.bus.write((AD9912_POW1 << 16) | (3 << 29))
     delay_mu(-self.bus.xfer_period_mu)
     self.bus.set_xfer(self.chip_select, 32, 0)
     self.bus.write((pow << 16) | int32(ftw >> 32))
     self.bus.write(int32(ftw))
     delay_mu(self.bus.xfer_period_mu - self.bus.write_period_mu)
     self.cpld.io_update.pulse(10 * ns)
Exemplo n.º 25
0
    def set_att_mu(self, data):
        """Set channel attenuation.

        :param data: Attenuator data in machine units (8 bit)
        """
        div = 34  # 30 ns min period
        t_xfer = self.phaser.core.seconds_to_mu((8 + 1)*div*4*ns)
        self.phaser.spi_cfg(select=PHASER_SEL_ATT0 << self.index, div=div,
                            end=1)
        self.phaser.spi_write(data)
        delay_mu(t_xfer)
Exemplo n.º 26
0
    def set_mu(self, ftw, pow_=0, asf=0x3fff, phase_mode=_PHASE_MODE_DEFAULT,
               ref_time_mu=int64(-1), profile=0):
        """Set profile 0 data in machine units.

        This uses machine units (FTW, POW, ASF). The frequency tuning word
        width is 32, the phase offset word width is 16, and the amplitude
        scale factor width is 12.

        After the SPI transfer, the shared IO update pin is pulsed to
        activate the data.

        .. seealso: :meth:`set_phase_mode` for a definition of the different
            phase modes.

        :param ftw: Frequency tuning word: 32 bit.
        :param pow_: Phase tuning word: 16 bit unsigned.
        :param asf: Amplitude scale factor: 14 bit unsigned.
        :param phase_mode: If specified, overrides the default phase mode set
            by :meth:`set_phase_mode` for this call.
        :param ref_time_mu: Fiducial time used to compute absolute or tracking
            phase updates. In machine units as obtained by `now_mu()`.
        :param profile: Profile number to set (0-7, default: 0).
        :return: Resulting phase offset word after application of phase
            tracking offset. When using :const:`PHASE_MODE_CONTINUOUS` in
            subsequent calls, use this value as the "current" phase.
        """
        if phase_mode == _PHASE_MODE_DEFAULT:
            phase_mode = self.phase_mode
        # Align to coarse RTIO which aligns SYNC_CLK. I.e. clear fine TSC
        # This will not cause a collision or sequence error.
        at_mu(now_mu() & ~7)
        if phase_mode != PHASE_MODE_CONTINUOUS:
            # Auto-clear phase accumulator on IO_UPDATE.
            # This is active already for the next IO_UPDATE
            self.set_cfr1(phase_autoclear=1)
            if phase_mode == PHASE_MODE_TRACKING and ref_time_mu < 0:
                # set default fiducial time stamp
                ref_time_mu = 0
            if ref_time_mu >= 0:
                # 32 LSB are sufficient.
                # Also no need to use IO_UPDATE time as this
                # is equivalent to an output pipeline latency.
                dt = int32(now_mu()) - int32(ref_time_mu)
                pow_ += dt*ftw*self.sysclk_per_mu >> 16
        self.write64(_AD9910_REG_PROFILE0 + profile,
                     (asf << 16) | (pow_ & 0xffff), ftw)
        delay_mu(int64(self.io_update_delay))
        self.cpld.io_update.pulse_mu(8)  # assumes 8 mu > t_SYN_CCLK
        at_mu(now_mu() & ~7)  # clear fine TSC again
        if phase_mode != PHASE_MODE_CONTINUOUS:
            self.set_cfr1()
            # future IO_UPDATE will activate
        return pow_
Exemplo n.º 27
0
    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)
Exemplo n.º 28
0
 def read(self, addr, length=1):
     assert length > 0
     assert length <= 4
     self.bus.set_xfer(self.chip_select, 16, 0)
     self.bus.write((addr | ((length - 1) << 13) | 0x8000) << 16)
     delay_mu(-self.bus.xfer_period_mu)
     self.bus.set_xfer(self.chip_select, 0, length * 8)
     self.bus.write(0)
     delay_mu(2 * self.bus.xfer_period_mu)
     data = self.bus.read_sync()
     if length < 4:
         data &= (1 << (length * 8)) - 1
     return data
Exemplo n.º 29
0
    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)
Exemplo n.º 30
0
    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)
Exemplo n.º 31
0
    def load(self):
        """Pulse the LDAC line.

        Note that there is a <= 1.5us "BUSY" period (t10) after writing to a
        DAC input/gain/offset register. All DAC registers may be programmed
        normally during the busy period, however LDACs during the busy period
        cause the DAC output to change *after* the BUSY period has completed,
        instead of the usual immediate update on LDAC behaviour.

        This method advances the timeline by two RTIO clock periods.
        """
        self.ldac.off()
        delay_mu(2 * self.bus.ref_period_mu)  # t13 = 10ns ldac pulse width low
        self.ldac.on()
Exemplo n.º 32
0
    def test_shallow_parallel(self):
        # Shallow parallel matches the timing model of ARTIQ, see https://github.com/m-labs/artiq/issues/1555

        range_stop = 1000000000

        for i in range(_NUM_SAMPLES):
            with self.subTest('parallel sub test', i=i):
                # Reference time
                ref_time = now_mu()

                # Block duration
                block_duration = 0
                with parallel:
                    # Random duration
                    duration = self.rnd.randrange(range_stop)
                    # Delay
                    delay_mu(duration)
                    # Update block duration
                    block_duration = max(duration, block_duration)

                    # Manually repeat test code to keep them top-level statements in the shallow parallel context
                    duration = self.rnd.randrange(range_stop)
                    delay_mu(duration)
                    block_duration = max(duration, block_duration)
                    duration = self.rnd.randrange(range_stop)
                    delay_mu(duration)
                    block_duration = max(duration, block_duration)
                    duration = self.rnd.randrange(range_stop)
                    delay_mu(duration)
                    block_duration = max(duration, block_duration)

                # Update ref time
                ref_time += block_duration
                # Compare to reference time
                self.assertEqual(now_mu(), ref_time, 'Reference does not match now_mu()')
Exemplo n.º 33
0
    def test_delay_mu(self):
        # Reference time
        ref_time = now_mu()

        for i in range(_NUM_SAMPLES):
            # Random duration
            duration = self.rnd.randrange(1000000000)

            with self.subTest('delay_mu() sub test', i=i, duration=duration):
                # Insert the delay
                delay_mu(duration)
                # Compare to reference time
                ref_time += duration
                self.assertEqual(now_mu(), ref_time, 'Reference does not match now_mu()')
Exemplo n.º 34
0
Arquivo: spi.py Projeto: olsonse/pdq
    def read_mem(self, mem, adr, data, board=0xf, buffer=8):
        """Read from DAC channel waveform data memory.

        :param mem: DAC channel memory to access (0 to 2).
        :param adr: Start address.
        :param data: Memory data. List of 16 bit integers.
        :param board: Board to access (0-15) with ``0xf = 15`` being broadcast
            to all boards.
        """
        n = len(data)
        if not n:
            return
        self.bus.set_xfer(self.chip_select, 24, 8)
        self.bus.write((PDQ_CMD(board, 1, mem, 0) << 24)
                       | ((adr & 0x00ff) << 16) | (adr & 0xff00))
        delay_mu(-self.bus.write_period_mu - 3 * self.bus.ref_period_mu)
        self.bus.set_xfer(self.chip_select, 0, 16)
        for i in range(n):
            self.bus.write(0)
            delay_mu(-self.bus.read_period_mu)
            if i > 0:
                delay_mu(-3 * self.bus.ref_period_mu)
                self.bus.read_async()
            if i > buffer:
                data[i - 1 - buffer] = self.bus.input_async() & 0xffff
        delay_mu(self.bus.read_period_mu)
        self.bus.set_xfer(self.chip_select, 16, 0)
        self.bus.read_async()
        for i in range(max(0, n - buffer - 1), n):
            data[i] = self.bus.input_async() & 0xffff
Exemplo n.º 35
0
    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)
Exemplo n.º 36
0
    def load(self):
        """Pulse the LDAC line.

        Note that there is a <= 1.5us "BUSY" period (t10) after writing to a
        DAC input/gain/offset register. All DAC registers may be programmed
        normally during the busy period, however LDACs during the busy period
        cause the DAC output to change *after* the BUSY period has completed,
        instead of the usual immediate update on LDAC behaviour.

        This method advances the timeline by two RTIO clock periods.
        """
        self.ldac.off()
        delay_mu(2*self.bus.ref_period_mu)  # t13 = 10ns ldac pulse width low
        self.ldac.on()
Exemplo n.º 37
0
Arquivo: spi.py Projeto: m-labs/pdq2
    def read_mem(self, mem, adr, data, board=0xf, buffer=8):
        """Read from DAC channel waveform data memory.

        :param mem: DAC channel memory to access (0 to 2).
        :param adr: Start address.
        :param data: Memory data. List of 16 bit integers.
        :param board: Board to access (0-15) with ``0xf = 15`` being broadcast
            to all boards.
        """
        n = len(data)
        if not n:
            return
        self.bus.set_xfer(self.chip_select, 24, 8)
        self.bus.write((PDQ_CMD(board, 1, mem, 0) << 24) |
                       ((adr & 0x00ff) << 16) | (adr & 0xff00))
        delay_mu(-self.bus.write_period_mu-3*self.bus.ref_period_mu)
        self.bus.set_xfer(self.chip_select, 0, 16)
        for i in range(n):
            self.bus.write(0)
            delay_mu(-self.bus.read_period_mu)
            if i > 0:
                delay_mu(-3*self.bus.ref_period_mu)
                self.bus.read_async()
            if i > buffer:
                data[i - 1 - buffer] = self.bus.input_async() & 0xffff
        delay_mu(self.bus.read_period_mu)
        self.bus.set_xfer(self.chip_select, 16, 0)
        self.bus.read_async()
        for i in range(max(0, n - buffer - 1), n):
            data[i] = self.bus.input_async() & 0xffff
Exemplo n.º 38
0
Arquivo: spi.py Projeto: olsonse/pdq
    def get_reg(self, adr, board):
        """Get a PDQ register.

        :param adr: Address of the register (``_PDQ_ADR_CONFIG``,
          ``_PDQ_ADR_FRAME``, ``_PDQ_ADR_CRC``).
        :param board: Board to access, ``0xf`` to write to all boards.

        :return: Register data (8 bit).
        """
        self.bus.set_xfer(self.chip_select, 16, 8)
        self.bus.write(PDQ_CMD(board, 0, adr, 0) << 24)
        delay_mu(self.bus.ref_period_mu)  # get to 20ns min cs high
        self.bus.read_async()
        self.bus.set_xfer(self.chip_select, 16, 0)
        return int(self.bus.input_async() & 0xff)  # FIXME: m-labs/artiq#713
Exemplo n.º 39
0
Arquivo: spi.py Projeto: m-labs/pdq2
    def get_reg(self, adr, board):
        """Get a PDQ register.

        :param adr: Address of the register (``_PDQ_ADR_CONFIG``,
          ``_PDQ_ADR_FRAME``, ``_PDQ_ADR_CRC``).
        :param board: Board to access, ``0xf`` to write to all boards.

        :return: Register data (8 bit).
        """
        self.bus.set_xfer(self.chip_select, 16, 8)
        self.bus.write(PDQ_CMD(board, 0, adr, 0) << 24)
        delay_mu(self.bus.ref_period_mu)  # get to 20ns min cs high
        self.bus.read_async()
        self.bus.set_xfer(self.chip_select, 16, 0)
        return int(self.bus.input_async() & 0xff)  # FIXME: m-labs/artiq#713
Exemplo n.º 40
0
Arquivo: spi.py Projeto: cjbe/artiq
    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)
Exemplo n.º 41
0
    def test_peek_negative_delay(self):
        delay(10 * us)
        self._test_all_not_set()

        # Set direction
        for ttl in self.sys.ttl_list:
            ttl.output()

        delay_mu(-1)
        self._test_all_not_set()

        delay_mu(1)
        for ttl in self.sys.ttl_list:
            self.assertEqual(self.sm.peek(ttl, 'direction'), 1)
            self.assertEqual(self.sm.peek(ttl, 'sensitivity'), 'z')
            self.assertEqual(self.sm.peek(ttl, 'state'), 'x')
Exemplo n.º 42
0
    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)
Exemplo n.º 43
0
Arquivo: spi.py Projeto: JQIamo/artiq
    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)
Exemplo n.º 44
0
Arquivo: spi.py Projeto: m-labs/pdq2
    def write_mem(self, mem, adr, data, board=0xf):  # FIXME: m-labs/artiq#714
        """Write to DAC channel waveform data memory.

        :param mem: DAC channel memory to access (0 to 2).
        :param adr: Start address.
        :param data: Memory data. List of 16 bit integers.
        :param board: Board to access (0-15) with ``0xf = 15`` being broadcast
            to all boards.
        """
        self.bus.set_xfer(self.chip_select, 24, 0)
        self.bus.write((PDQ_CMD(board, 1, mem, 1) << 24) |
                       ((adr & 0x00ff) << 16) | (adr & 0xff00))
        delay_mu(-self.bus.write_period_mu-3*self.bus.ref_period_mu)
        self.bus.set_xfer(self.chip_select, 16, 0)
        for i in data:
            self.bus.write(i << 16)
            delay_mu(-self.bus.write_period_mu)
        delay_mu(self.bus.write_period_mu + self.bus.ref_period_mu)
Exemplo n.º 45
0
    def set(self, values, op=_AD5360_CMD_DATA):
        """Write to several channels and pulse LDAC to update the channels.

        This method does not advance the timeline. Write events are scheduled
        in the past. The DACs will synchronously start changing their output
        levels `now`.

        :param values: List of 16 bit values to write to the channels.
        :param op: Operation to perform, one of :const:`_AD5360_CMD_DATA`,
          :const:`_AD5360_CMD_OFFSET`, :const:`_AD5360_CMD_GAIN`
          (default: :const:`_AD5360_CMD_DATA`).
        """
        # compensate all delays that will be applied
        delay_mu(-len(values)*(self.bus.xfer_period_mu +
                               self.bus.write_period_mu +
                               self.bus.ref_period_mu) -
                 3*self.bus.ref_period_mu -
                 self.core.seconds_to_mu(1.5*us))
        for i in range(len(values)):
            self.write_channel(i, values[i], op)
        delay_mu(3*self.bus.ref_period_mu +  # latency alignment ttl to spi
                 self.core.seconds_to_mu(1.5*us))  # t10 max busy low for one channel
        self.load()
        delay_mu(-2*self.bus.ref_period_mu)  # load(), t13