forked from M-Labs/artiq
doc: Formatting and link fixes in docstrings
This commit is contained in:
parent
0e1b29c5d9
commit
a4bfb0d5dd
@ -24,21 +24,21 @@ class _AppletRequestInterface:
|
||||
def set_dataset(self, key, value, unit=None, scale=None, precision=None, persist=None):
|
||||
"""
|
||||
Set a dataset.
|
||||
See documentation of ``artiq.language.environment.set_dataset``.
|
||||
See documentation of :meth:`~artiq.language.environment.HasEnvironment.set_dataset`.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def mutate_dataset(self, key, index, value):
|
||||
"""
|
||||
Mutate a dataset.
|
||||
See documentation of ``artiq.language.environment.mutate_dataset``.
|
||||
See documentation of :meth:`~artiq.language.environment.HasEnvironment.mutate_dataset`.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def append_to_dataset(self, key, value):
|
||||
"""
|
||||
Append to a dataset.
|
||||
See documentation of ``artiq.language.environment.append_to_dataset``.
|
||||
See documentation of :meth:`~artiq.language.environment.HasEnvironment.append_to_dataset`.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@ -49,8 +49,9 @@ class _AppletRequestInterface:
|
||||
|
||||
:param expurl: Experiment URL identifying the experiment in the dashboard. Example: 'repo:ArgumentsDemo'.
|
||||
:param key: Name of the argument in the experiment.
|
||||
:param value: Object representing the new temporary value of the argument. For ``Scannable`` arguments, this parameter
|
||||
should be a ``ScanObject``. The type of the ``ScanObject`` will be set as the selected type when this function is called.
|
||||
:param value: Object representing the new temporary value of the argument. For :class:`~artiq.language.scan.Scannable` arguments,
|
||||
this parameter should be a :class:`~artiq.language.scan.ScanObject`. The type of the :class:`~artiq.language.scan.ScanObject`
|
||||
will be set as the selected type when this function is called.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
""""RTIO driver for the Analog Devices AD53[67][0123] family of multi-channel
|
||||
"""RTIO driver for the Analog Devices AD53[67][0123] family of multi-channel
|
||||
Digital to Analog Converters.
|
||||
|
||||
Output event replacement is not supported and issuing commands at the same
|
||||
time is an error.
|
||||
time results in a collision error.
|
||||
"""
|
||||
|
||||
# Designed from the data sheets and somewhat after the linux kernel
|
||||
@ -131,10 +131,10 @@ class AD53xx:
|
||||
optimized for speed; datasheet says t22: 25ns min SCLK edge to SDO
|
||||
valid, and suggests the SPI speed for reads should be <=20 MHz)
|
||||
:param vref: DAC reference voltage (default: 5.)
|
||||
:param offset_dacs: Initial register value for the two offset DACs, device
|
||||
dependent and must be set correctly for correct voltage to mu
|
||||
conversions. Knowledge of his state is not transferred between
|
||||
experiments. (default: 8192)
|
||||
:param offset_dacs: Initial register value for the two offset DACs
|
||||
(default: 8192). Device dependent and must be set correctly for
|
||||
correct voltage-to-mu conversions. Knowledge of this state is
|
||||
not transferred between experiments.
|
||||
:param core_device: Core device name (default: "core")
|
||||
"""
|
||||
kernel_invariants = {"bus", "ldac", "clr", "chip_select", "div_write",
|
||||
@ -202,7 +202,7 @@ class AD53xx:
|
||||
:param op: Operation to perform, one of :const:`AD53XX_READ_X1A`,
|
||||
:const:`AD53XX_READ_X1B`, :const:`AD53XX_READ_OFFSET`,
|
||||
:const:`AD53XX_READ_GAIN` etc. (default: :const:`AD53XX_READ_X1A`).
|
||||
:return: The 16 bit register value
|
||||
:return: The 16-bit register value
|
||||
"""
|
||||
self.bus.write(ad53xx_cmd_read_ch(channel, op) << 8)
|
||||
self.bus.set_config_mu(SPI_AD53XX_CONFIG | spi.SPI_INPUT, 24,
|
||||
@ -309,7 +309,7 @@ class AD53xx:
|
||||
|
||||
This method does not advance the timeline; write events are scheduled
|
||||
in the past. The DACs will synchronously start changing their output
|
||||
levels `now`.
|
||||
levels ``now``.
|
||||
|
||||
If no LDAC device was defined, the LDAC pulse is skipped.
|
||||
|
||||
@ -364,8 +364,8 @@ class AD53xx:
|
||||
high) can be calibrated in this fashion.
|
||||
|
||||
:param channel: The number of the calibrated channel
|
||||
:params vzs: Measured voltage with the DAC set to zero-scale (0x0000)
|
||||
:params vfs: Measured voltage with the DAC set to full-scale (0xffff)
|
||||
:param vzs: Measured voltage with the DAC set to zero-scale (0x0000)
|
||||
:param vfs: Measured voltage with the DAC set to full-scale (0xffff)
|
||||
"""
|
||||
offset_err = voltage_to_mu(vzs, self.offset_dacs, self.vref)
|
||||
gain_err = voltage_to_mu(vfs, self.offset_dacs, self.vref) - (
|
||||
|
@ -114,27 +114,27 @@ class AD9910:
|
||||
(as configured through CFG_MASK_NU), 4-7 for individual channels.
|
||||
:param cpld_device: Name of the Urukul CPLD this device is on.
|
||||
:param sw_device: Name of the RF switch device. The RF switch is a
|
||||
TTLOut channel available as the :attr:`sw` attribute of this instance.
|
||||
TTLOut channel available as the ``sw`` attribute of this instance.
|
||||
:param pll_n: DDS PLL multiplier. The DDS sample clock is
|
||||
f_ref/clk_div*pll_n where f_ref is the reference frequency and
|
||||
clk_div is the reference clock divider (both set in the parent
|
||||
``f_ref / clk_div * pll_n`` where ``f_ref`` is the reference frequency and
|
||||
``clk_div`` is the reference clock divider (both set in the parent
|
||||
Urukul CPLD instance).
|
||||
:param pll_en: PLL enable bit, set to 0 to bypass PLL (default: 1).
|
||||
Note that when bypassing the PLL the red front panel LED may remain on.
|
||||
:param pll_cp: DDS PLL charge pump setting.
|
||||
:param pll_vco: DDS PLL VCO range selection.
|
||||
:param sync_delay_seed: SYNC_IN delay tuning starting value.
|
||||
To stabilize the SYNC_IN delay tuning, run :meth:`tune_sync_delay` once
|
||||
:param sync_delay_seed: ``SYNC_IN`` delay tuning starting value.
|
||||
To stabilize the ``SYNC_IN`` delay tuning, run :meth:`tune_sync_delay` once
|
||||
and set this to the delay tap number returned (default: -1 to signal no
|
||||
synchronization and no tuning during :meth:`init`).
|
||||
Can be a string of the form "eeprom_device:byte_offset" to read the
|
||||
value from a I2C EEPROM; in which case, `io_update_delay` must be set
|
||||
Can be a string of the form ``eeprom_device:byte_offset`` to read the
|
||||
value from a I2C EEPROM, in which case ``io_update_delay`` must be set
|
||||
to the same string value.
|
||||
:param io_update_delay: IO_UPDATE pulse alignment delay.
|
||||
To align IO_UPDATE to SYNC_CLK, run :meth:`tune_io_update_delay` and
|
||||
:param io_update_delay: ``IO_UPDATE`` pulse alignment delay.
|
||||
To align ``IO_UPDATE`` to ``SYNC_CLK``, run :meth:`tune_io_update_delay` and
|
||||
set this to the delay tap number returned.
|
||||
Can be a string of the form "eeprom_device:byte_offset" to read the
|
||||
value from a I2C EEPROM; in which case, `sync_delay_seed` must be set
|
||||
Can be a string of the form ``eeprom_device:byte_offset`` to read the
|
||||
value from a I2C EEPROM, in which case ``sync_delay_seed`` must be set
|
||||
to the same string value.
|
||||
"""
|
||||
|
||||
@ -188,9 +188,7 @@ class AD9910:
|
||||
|
||||
@kernel
|
||||
def set_phase_mode(self, phase_mode: TInt32):
|
||||
r"""Set the default phase mode.
|
||||
|
||||
for future calls to :meth:`set` and
|
||||
r"""Set the default phase mode for future calls to :meth:`set` and
|
||||
:meth:`set_mu`. Supported phase modes are:
|
||||
|
||||
* :const:`PHASE_MODE_CONTINUOUS`: the phase accumulator is unchanged
|
||||
@ -233,7 +231,7 @@ class AD9910:
|
||||
|
||||
@kernel
|
||||
def write16(self, addr: TInt32, data: TInt32):
|
||||
"""Write to 16 bit register.
|
||||
"""Write to 16-bit register.
|
||||
|
||||
:param addr: Register address
|
||||
:param data: Data to be written
|
||||
@ -244,7 +242,7 @@ class AD9910:
|
||||
|
||||
@kernel
|
||||
def write32(self, addr: TInt32, data: TInt32):
|
||||
"""Write to 32 bit register.
|
||||
"""Write to 32-bit register.
|
||||
|
||||
:param addr: Register address
|
||||
:param data: Data to be written
|
||||
@ -258,7 +256,7 @@ class AD9910:
|
||||
|
||||
@kernel
|
||||
def read16(self, addr: TInt32) -> TInt32:
|
||||
"""Read from 16 bit register.
|
||||
"""Read from 16-bit register.
|
||||
|
||||
:param addr: Register address
|
||||
"""
|
||||
@ -273,7 +271,7 @@ class AD9910:
|
||||
|
||||
@kernel
|
||||
def read32(self, addr: TInt32) -> TInt32:
|
||||
"""Read from 32 bit register.
|
||||
"""Read from 32-bit register.
|
||||
|
||||
:param addr: Register address
|
||||
"""
|
||||
@ -288,10 +286,10 @@ class AD9910:
|
||||
|
||||
@kernel
|
||||
def read64(self, addr: TInt32) -> TInt64:
|
||||
"""Read from 64 bit register.
|
||||
"""Read from 64-bit register.
|
||||
|
||||
:param addr: Register address
|
||||
:return: 64 bit integer register value
|
||||
:return: 64-bit integer register value
|
||||
"""
|
||||
self.bus.set_config_mu(
|
||||
urukul.SPI_CONFIG, 8,
|
||||
@ -311,10 +309,10 @@ class AD9910:
|
||||
|
||||
@kernel
|
||||
def write64(self, addr: TInt32, data_high: TInt32, data_low: TInt32):
|
||||
"""Write to 64 bit register.
|
||||
"""Write to 64-bit register.
|
||||
|
||||
:param addr: Register address
|
||||
:param data_high: High (MSB) 32 bits of the data
|
||||
:param data_high: High (MSB) 32 data bits
|
||||
:param data_low: Low (LSB) 32 data bits
|
||||
"""
|
||||
self.bus.set_config_mu(urukul.SPI_CONFIG, 8,
|
||||
@ -332,8 +330,9 @@ class AD9910:
|
||||
"""Write data to RAM.
|
||||
|
||||
The profile to write to and the step, start, and end address
|
||||
need to be configured before and separately using
|
||||
:meth:`set_profile_ram` and the parent CPLD `set_profile`.
|
||||
need to be configured in advance and separately using
|
||||
:meth:`set_profile_ram` and the parent CPLD
|
||||
:meth:`~artiq.coredevice.urukul.CPLD.set_profile`.
|
||||
|
||||
:param data: Data to be written to RAM.
|
||||
"""
|
||||
@ -354,7 +353,8 @@ class AD9910:
|
||||
|
||||
The profile to read from and the step, start, and end address
|
||||
need to be configured before and separately using
|
||||
:meth:`set_profile_ram` and the parent CPLD `set_profile`.
|
||||
:meth:`set_profile_ram` and the parent CPLD
|
||||
:meth:`~artiq.coredevice.urukul.CPLD.set_profile`.
|
||||
|
||||
:param data: List to be filled with data read from RAM.
|
||||
"""
|
||||
@ -392,7 +392,7 @@ class AD9910:
|
||||
select_auto_osk: TInt32 = 0):
|
||||
"""Set CFR1. See the AD9910 datasheet for parameter meanings.
|
||||
|
||||
This method does not pulse IO_UPDATE.
|
||||
This method does not pulse ``IO_UPDATE.``
|
||||
|
||||
:param power_down: Power down bits.
|
||||
:param phase_autoclear: Autoclear phase accumulator.
|
||||
@ -431,7 +431,7 @@ class AD9910:
|
||||
matched_latency_enable: TInt32 = 0):
|
||||
"""Set CFR2. See the AD9910 datasheet for parameter meanings.
|
||||
|
||||
This method does not pulse IO_UPDATE.
|
||||
This method does not pulse ``IO_UPDATE``.
|
||||
|
||||
:param asf_profile_enable: Enable amplitude scale from single tone profiles.
|
||||
:param drg_enable: Digital ramp enable.
|
||||
@ -456,14 +456,14 @@ class AD9910:
|
||||
"""Initialize and configure the DDS.
|
||||
|
||||
Sets up SPI mode, confirms chip presence, powers down unused blocks,
|
||||
configures the PLL, waits for PLL lock. Uses the
|
||||
IO_UPDATE signal multiple times.
|
||||
configures the PLL, waits for PLL lock. Uses the ``IO_UPDATE``
|
||||
signal multiple times.
|
||||
|
||||
:param blind: Do not read back DDS identity and do not wait for lock.
|
||||
"""
|
||||
self.sync_data.init()
|
||||
if self.sync_data.sync_delay_seed >= 0 and not self.cpld.sync_div:
|
||||
raise ValueError("parent cpld does not drive SYNC")
|
||||
raise ValueError("parent CPLD does not drive SYNC")
|
||||
if self.sync_data.sync_delay_seed >= 0:
|
||||
if self.sysclk_per_mu != self.sysclk * self.core.ref_period:
|
||||
raise ValueError("incorrect clock ratio for synchronization")
|
||||
@ -514,7 +514,7 @@ class AD9910:
|
||||
def power_down(self, bits: TInt32 = 0b1111):
|
||||
"""Power down DDS.
|
||||
|
||||
:param bits: Power down bits, see datasheet
|
||||
:param bits: Power-down bits, see datasheet
|
||||
"""
|
||||
self.set_cfr1(power_down=bits)
|
||||
self.cpld.io_update.pulse(1 * us)
|
||||
@ -534,23 +534,23 @@ class AD9910:
|
||||
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
|
||||
.. seealso: :meth:`AD9910.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 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()`.
|
||||
phase updates. In machine units as obtained by :meth:`~artiq.language.core.now_mu()`.
|
||||
:param profile: Single tone profile number to set (0-7, default: 7).
|
||||
Ineffective if `ram_destination` is specified.
|
||||
Ineffective if ``ram_destination`` is specified.
|
||||
:param ram_destination: RAM destination (:const:`RAM_DEST_FTW`,
|
||||
:const:`RAM_DEST_POW`, :const:`RAM_DEST_ASF`,
|
||||
:const:`RAM_DEST_POWASF`). If specified, write free DDS parameters
|
||||
to the ASF/FTW/POW registers instead of to the single tone profile
|
||||
register (default behaviour, see `profile`).
|
||||
register (default behaviour, see ``profile``).
|
||||
: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.
|
||||
@ -598,10 +598,10 @@ class AD9910:
|
||||
"""Get the frequency tuning word, phase offset word,
|
||||
and amplitude scale factor.
|
||||
|
||||
.. seealso:: :meth:`get`
|
||||
See also :meth:`AD9910.get`.
|
||||
|
||||
:param profile: Profile number to get (0-7, default: 7)
|
||||
:return: A tuple ``(ftw, pow, asf)``
|
||||
:return: A tuple (FTW, POW, ASF)
|
||||
"""
|
||||
|
||||
# Read data
|
||||
@ -850,7 +850,7 @@ class AD9910:
|
||||
ram_destination: TInt32 = -1) -> TFloat:
|
||||
"""Set DDS data in SI units.
|
||||
|
||||
.. seealso:: :meth:`set_mu`
|
||||
See also :meth:`AD9910.set_mu`.
|
||||
|
||||
:param frequency: Frequency in Hz
|
||||
:param phase: Phase tuning word in turns
|
||||
@ -871,10 +871,10 @@ class AD9910:
|
||||
) -> TTuple([TFloat, TFloat, TFloat]):
|
||||
"""Get the frequency, phase, and amplitude.
|
||||
|
||||
.. seealso:: :meth:`get_mu`
|
||||
See also :meth:`AD9910.get_mu`.
|
||||
|
||||
:param profile: Profile number to get (0-7, default: 7)
|
||||
:return: A tuple ``(frequency, phase, amplitude)``
|
||||
:return: A tuple (frequency, phase, amplitude)
|
||||
"""
|
||||
|
||||
# Get values
|
||||
@ -887,11 +887,10 @@ class AD9910:
|
||||
def set_att_mu(self, att: TInt32):
|
||||
"""Set digital step attenuator in machine units.
|
||||
|
||||
This method will write the attenuator settings of all four channels.
|
||||
This method will write the attenuator settings of all four channels. See also
|
||||
:meth:`CPLD.get_channel_att <artiq.coredevice.urukul.CPLD.set_att_mu>`.
|
||||
|
||||
.. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att_mu`
|
||||
|
||||
:param att: Attenuation setting, 8 bit digital.
|
||||
:param att: Attenuation setting, 8-bit digital.
|
||||
"""
|
||||
self.cpld.set_att_mu(self.chip_select - 4, att)
|
||||
|
||||
@ -899,9 +898,8 @@ class AD9910:
|
||||
def set_att(self, att: TFloat):
|
||||
"""Set digital step attenuator in SI units.
|
||||
|
||||
This method will write the attenuator settings of all four channels.
|
||||
|
||||
.. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att`
|
||||
This method will write the attenuator settings of all four channels. See also
|
||||
:meth:`CPLD.get_channel_att <artiq.coredevice.urukul.CPLD.set_att>`.
|
||||
|
||||
:param att: Attenuation in dB.
|
||||
"""
|
||||
@ -909,19 +907,17 @@ class AD9910:
|
||||
|
||||
@kernel
|
||||
def get_att_mu(self) -> TInt32:
|
||||
"""Get digital step attenuator value in machine units.
|
||||
"""Get digital step attenuator value in machine units. See also
|
||||
:meth:`CPLD.get_channel_att <artiq.coredevice.urukul.CPLD.get_channel_att_mu>`.
|
||||
|
||||
.. seealso:: :meth:`artiq.coredevice.urukul.CPLD.get_channel_att_mu`
|
||||
|
||||
:return: Attenuation setting, 8 bit digital.
|
||||
:return: Attenuation setting, 8-bit digital.
|
||||
"""
|
||||
return self.cpld.get_channel_att_mu(self.chip_select - 4)
|
||||
|
||||
@kernel
|
||||
def get_att(self) -> TFloat:
|
||||
"""Get digital step attenuator value in SI units.
|
||||
|
||||
.. seealso:: :meth:`artiq.coredevice.urukul.CPLD.get_channel_att`
|
||||
"""Get digital step attenuator value in SI units. See also
|
||||
:meth:`CPLD.get_channel_att <artiq.coredevice.urukul.CPLD.get_channel_att>`.
|
||||
|
||||
:return: Attenuation in dB.
|
||||
"""
|
||||
@ -943,16 +939,16 @@ class AD9910:
|
||||
window: TInt32,
|
||||
en_sync_gen: TInt32 = 0):
|
||||
"""Set the relevant parameters in the multi device synchronization
|
||||
register. See the AD9910 datasheet for details. The SYNC clock
|
||||
generator preset value is set to zero, and the SYNC_OUT generator is
|
||||
register. See the AD9910 datasheet for details. The ``SYNC`` clock
|
||||
generator preset value is set to zero, and the ``SYNC_OUT`` generator is
|
||||
disabled by default.
|
||||
|
||||
:param in_delay: SYNC_IN delay tap (0-31) in steps of ~75ps
|
||||
:param window: Symmetric SYNC_IN validation window (0-15) in
|
||||
:param in_delay: ``SYNC_IN`` delay tap (0-31) in steps of ~75ps
|
||||
:param window: Symmetric ``SYNC_IN`` validation window (0-15) in
|
||||
steps of ~75ps for both hold and setup margin.
|
||||
:param en_sync_gen: Whether to enable the DDS-internal sync generator
|
||||
(SYNC_OUT, cf. sync_sel == 1). Should be left off for the normal
|
||||
use case, where the SYNC clock is supplied by the core device.
|
||||
(``SYNC_OUT``, cf. ``sync_sel == 1``). Should be left off for the normal
|
||||
use case, where the ``SYNC`` clock is supplied by the core device.
|
||||
"""
|
||||
self.write32(_AD9910_REG_SYNC,
|
||||
(window << 28) | # SYNC S/H validation delay
|
||||
@ -965,9 +961,9 @@ class AD9910:
|
||||
|
||||
@kernel
|
||||
def clear_smp_err(self):
|
||||
"""Clear the SMP_ERR flag and enables SMP_ERR validity monitoring.
|
||||
"""Clear the ``SMP_ERR`` flag and enables ``SMP_ERR`` validity monitoring.
|
||||
|
||||
Violations of the SYNC_IN sample and hold margins will result in
|
||||
Violations of the ``SYNC_IN`` sample and hold margins will result in
|
||||
SMP_ERR being asserted. This then also activates the red LED on
|
||||
the respective Urukul channel.
|
||||
|
||||
@ -982,9 +978,9 @@ class AD9910:
|
||||
@kernel
|
||||
def tune_sync_delay(self,
|
||||
search_seed: TInt32 = 15) -> TTuple([TInt32, TInt32]):
|
||||
"""Find a stable SYNC_IN delay.
|
||||
"""Find a stable ``SYNC_IN`` delay.
|
||||
|
||||
This method first locates a valid SYNC_IN delay at zero validation
|
||||
This method first locates a valid ``SYNC_IN`` delay at zero validation
|
||||
window size (setup/hold margin) by scanning around `search_seed`. It
|
||||
then looks for similar valid delays at successively larger validation
|
||||
window sizes until none can be found. It then decreases the validation
|
||||
@ -993,7 +989,7 @@ class AD9910:
|
||||
|
||||
This method and :meth:`tune_io_update_delay` can be run in any order.
|
||||
|
||||
:param search_seed: Start value for valid SYNC_IN delay search.
|
||||
:param search_seed: Start value for valid ``SYNC_IN`` delay search.
|
||||
Defaults to 15 (half range).
|
||||
:return: Tuple of optimal delay and window size.
|
||||
"""
|
||||
@ -1040,16 +1036,16 @@ class AD9910:
|
||||
def measure_io_update_alignment(self, delay_start: TInt64,
|
||||
delay_stop: TInt64) -> TInt32:
|
||||
"""Use the digital ramp generator to locate the alignment between
|
||||
IO_UPDATE and SYNC_CLK.
|
||||
``IO_UPDATE`` and ``SYNC_CLK``.
|
||||
|
||||
The ramp generator is set up to a linear frequency ramp
|
||||
(dFTW/t_SYNC_CLK=1) and started at a coarse RTIO time stamp plus
|
||||
`delay_start` and stopped at a coarse RTIO time stamp plus
|
||||
`delay_stop`.
|
||||
``(dFTW/t_SYNC_CLK=1)`` and started at a coarse RTIO time stamp plus
|
||||
``delay_start`` and stopped at a coarse RTIO time stamp plus
|
||||
``delay_stop``.
|
||||
|
||||
:param delay_start: Start IO_UPDATE delay in machine units.
|
||||
:param delay_stop: Stop IO_UPDATE delay in machine units.
|
||||
:return: Odd/even SYNC_CLK cycle indicator.
|
||||
:param delay_start: Start ``IO_UPDATE`` delay in machine units.
|
||||
:param delay_stop: Stop ``IO_UPDATE`` delay in machine units.
|
||||
:return: Odd/even ``SYNC_CLK`` cycle indicator.
|
||||
"""
|
||||
# set up DRG
|
||||
self.set_cfr1(drg_load_lrr=1, drg_autoclear=1)
|
||||
@ -1081,19 +1077,19 @@ class AD9910:
|
||||
|
||||
@kernel
|
||||
def tune_io_update_delay(self) -> TInt32:
|
||||
"""Find a stable IO_UPDATE delay alignment.
|
||||
"""Find a stable ``IO_UPDATE`` delay alignment.
|
||||
|
||||
Scan through increasing IO_UPDATE delays until a delay is found that
|
||||
lets IO_UPDATE be registered in the next SYNC_CLK cycle. Return a
|
||||
IO_UPDATE delay that is as far away from that SYNC_CLK edge
|
||||
Scan through increasing ``IO_UPDATE`` delays until a delay is found that
|
||||
lets ``IO_UPDATE`` be registered in the next ``SYNC_CLK`` cycle. Return a
|
||||
``IO_UPDATE`` delay that is as far away from that ``SYNC_CLK`` edge
|
||||
as possible.
|
||||
|
||||
This method assumes that the IO_UPDATE TTLOut device has one machine
|
||||
This method assumes that the ``IO_UPDATE`` TTLOut device has one machine
|
||||
unit resolution (SERDES).
|
||||
|
||||
This method and :meth:`tune_sync_delay` can be run in any order.
|
||||
|
||||
:return: Stable IO_UPDATE delay to be passed to the constructor
|
||||
:return: Stable ``IO_UPDATE`` delay to be passed to the constructor
|
||||
:class:`AD9910` via the device database.
|
||||
"""
|
||||
period = self.sysclk_per_mu * 4 # SYNC_CLK period
|
||||
|
@ -11,7 +11,7 @@ from artiq.coredevice import urukul
|
||||
|
||||
class AD9912:
|
||||
"""
|
||||
AD9912 DDS channel on Urukul
|
||||
AD9912 DDS channel on Urukul.
|
||||
|
||||
This class supports a single DDS channel and exposes the DDS,
|
||||
the digital step attenuator, and the RF switch.
|
||||
@ -22,9 +22,9 @@ class AD9912:
|
||||
:param sw_device: Name of the RF switch device. The RF switch is a
|
||||
TTLOut channel available as the :attr:`sw` attribute of this instance.
|
||||
:param pll_n: DDS PLL multiplier. The DDS sample clock is
|
||||
f_ref/clk_div*pll_n where f_ref is the reference frequency and clk_div
|
||||
is the reference clock divider (both set in the parent Urukul CPLD
|
||||
instance).
|
||||
``f_ref / clk_div * pll_n`` where ``f_ref`` is the reference frequency and
|
||||
``clk_div`` is the reference clock divider (both set in the parent
|
||||
Urukul CPLD instance).
|
||||
:param pll_en: PLL enable bit, set to 0 to bypass PLL (default: 1).
|
||||
Note that when bypassing the PLL the red front panel LED may remain on.
|
||||
"""
|
||||
@ -101,7 +101,7 @@ class AD9912:
|
||||
|
||||
Sets up SPI mode, confirms chip presence, powers down unused blocks,
|
||||
and configures the PLL. Does not wait for PLL lock. Uses the
|
||||
IO_UPDATE signal multiple times.
|
||||
``IO_UPDATE`` signal multiple times.
|
||||
"""
|
||||
# SPI mode
|
||||
self.write(AD9912_SER_CONF, 0x99, length=1)
|
||||
@ -133,9 +133,9 @@ class AD9912:
|
||||
|
||||
This method will write the attenuator settings of all four channels.
|
||||
|
||||
.. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att_mu`
|
||||
See also :meth:`~artiq.coredevice.urukul.CPLD.set_att_mu`.
|
||||
|
||||
:param att: Attenuation setting, 8 bit digital.
|
||||
:param att: Attenuation setting, 8-bit digital.
|
||||
"""
|
||||
self.cpld.set_att_mu(self.chip_select - 4, att)
|
||||
|
||||
@ -145,7 +145,7 @@ class AD9912:
|
||||
|
||||
This method will write the attenuator settings of all four channels.
|
||||
|
||||
.. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att`
|
||||
See also :meth:`~artiq.coredevice.urukul.CPLD.set_att`.
|
||||
|
||||
:param att: Attenuation in dB. Higher values mean more attenuation.
|
||||
"""
|
||||
@ -155,9 +155,9 @@ class AD9912:
|
||||
def get_att_mu(self) -> TInt32:
|
||||
"""Get digital step attenuator value in machine units.
|
||||
|
||||
.. seealso:: :meth:`artiq.coredevice.urukul.CPLD.get_channel_att_mu`
|
||||
See also :meth:`~artiq.coredevice.urukul.CPLD.get_channel_att_mu`.
|
||||
|
||||
:return: Attenuation setting, 8 bit digital.
|
||||
:return: Attenuation setting, 8-bit digital.
|
||||
"""
|
||||
return self.cpld.get_channel_att_mu(self.chip_select - 4)
|
||||
|
||||
@ -165,7 +165,7 @@ class AD9912:
|
||||
def get_att(self) -> TFloat:
|
||||
"""Get digital step attenuator value in SI units.
|
||||
|
||||
.. seealso:: :meth:`artiq.coredevice.urukul.CPLD.get_channel_att`
|
||||
See also :meth:`~artiq.coredevice.urukul.CPLD.get_channel_att`.
|
||||
|
||||
:return: Attenuation in dB.
|
||||
"""
|
||||
@ -178,8 +178,8 @@ class AD9912:
|
||||
After the SPI transfer, the shared IO update pin is pulsed to
|
||||
activate the data.
|
||||
|
||||
:param ftw: Frequency tuning word: 48 bit unsigned.
|
||||
:param pow_: Phase tuning word: 16 bit unsigned.
|
||||
:param ftw: Frequency tuning word: 48-bit unsigned.
|
||||
:param pow_: Phase tuning word: 16-bit unsigned.
|
||||
"""
|
||||
# streaming transfer of FTW and POW
|
||||
self.bus.set_config_mu(urukul.SPI_CONFIG, 16,
|
||||
@ -197,9 +197,9 @@ class AD9912:
|
||||
def get_mu(self) -> TTuple([TInt64, TInt32]):
|
||||
"""Get the frequency tuning word and phase offset word.
|
||||
|
||||
.. seealso:: :meth:`get`
|
||||
See also :meth:`AD9912.get`.
|
||||
|
||||
:return: A tuple ``(ftw, pow)``.
|
||||
:return: A tuple (FTW, POW).
|
||||
"""
|
||||
|
||||
# Read data
|
||||
@ -247,7 +247,7 @@ class AD9912:
|
||||
def set(self, frequency: TFloat, phase: TFloat = 0.0):
|
||||
"""Set profile 0 data in SI units.
|
||||
|
||||
.. seealso:: :meth:`set_mu`
|
||||
See also :meth:`AD9912.set_mu`.
|
||||
|
||||
:param frequency: Frequency in Hz
|
||||
:param phase: Phase tuning word in turns
|
||||
@ -259,9 +259,9 @@ class AD9912:
|
||||
def get(self) -> TTuple([TFloat, TFloat]):
|
||||
"""Get the frequency and phase.
|
||||
|
||||
.. seealso:: :meth:`get_mu`
|
||||
See also :meth:`AD9912.get_mu`.
|
||||
|
||||
:return: A tuple ``(frequency, phase)``.
|
||||
:return: A tuple (frequency, phase).
|
||||
"""
|
||||
|
||||
# Get values
|
||||
|
@ -49,7 +49,7 @@ class AD9914:
|
||||
The time cursor is not modified by any function in this class.
|
||||
|
||||
Output event replacement is not supported and issuing commands at the same
|
||||
time is an error.
|
||||
time results in collision errors.
|
||||
|
||||
:param sysclk: DDS system frequency. The DDS system clock must be a
|
||||
phase-locked multiple of the RTIO clock.
|
||||
@ -134,7 +134,7 @@ class AD9914:
|
||||
timing margin.
|
||||
|
||||
:param sync_delay: integer from 0 to 0x3f that sets the value of
|
||||
SYNC_OUT (bits 3-5) and SYNC_IN (bits 0-2) delay ADJ bits.
|
||||
``SYNC_OUT`` (bits 3-5) and ``SYNC_IN`` (bits 0-2) delay ADJ bits.
|
||||
"""
|
||||
delay_mu(-self.init_sync_duration_mu)
|
||||
self.write(AD9914_GPIO, (1 << self.channel) << 1)
|
||||
|
@ -112,7 +112,7 @@ class ADF5356:
|
||||
|
||||
This method will write the attenuator settings of the channel.
|
||||
|
||||
.. seealso:: :meth:`artiq.coredevice.mirny.Mirny.set_att`
|
||||
See also :meth:`Mirny.set_att<artiq.coredevice.mirny.Mirny.set_att>`.
|
||||
|
||||
:param att: Attenuation in dB.
|
||||
"""
|
||||
@ -122,7 +122,7 @@ class ADF5356:
|
||||
def set_att_mu(self, att):
|
||||
"""Set digital step attenuator in machine units.
|
||||
|
||||
:param att: Attenuation setting, 8 bit digital.
|
||||
:param att: Attenuation setting, 8-bit digital.
|
||||
"""
|
||||
self.cpld.set_att_mu(self.channel, att)
|
||||
|
||||
@ -531,14 +531,14 @@ class ADF5356:
|
||||
@portable
|
||||
def _compute_pfd_frequency(self, r, d, t) -> TInt64:
|
||||
"""
|
||||
Calculate the PFD frequency from the given reference path parameters
|
||||
Calculate the PFD frequency from the given reference path parameters.
|
||||
"""
|
||||
return int64(self.sysclk * ((1 + d) / (r * (1 + t))))
|
||||
|
||||
@portable
|
||||
def _compute_reference_counter(self) -> TInt32:
|
||||
"""
|
||||
Determine the reference counter R that maximizes the PFD frequency
|
||||
Determine the reference counter R that maximizes the PFD frequency.
|
||||
"""
|
||||
d = ADF5356_REG4_R_DOUBLER_GET(self.regs[4])
|
||||
t = ADF5356_REG4_R_DIVIDER_GET(self.regs[4])
|
||||
@ -565,14 +565,15 @@ def calculate_pll(f_vco: TInt64, f_pfd: TInt64):
|
||||
"""
|
||||
Calculate fractional-N PLL parameters such that
|
||||
|
||||
``f_vco`` = ``f_pfd`` * (``n`` + (``frac1`` + ``frac2``/``mod2``) / ``mod1``)
|
||||
``f_vco = f_pfd * (n + (frac1 + frac2/mod2) / mod1)``
|
||||
|
||||
where
|
||||
``mod1 = 2**24`` and ``mod2 <= 2**28``
|
||||
|
||||
``mod1 = 2**24`` and ``mod2 <= 2**28``
|
||||
|
||||
:param f_vco: target VCO frequency
|
||||
:param f_pfd: PFD frequency
|
||||
:return: ``(n, frac1, (frac2_msb, frac2_lsb), (mod2_msb, mod2_lsb))``
|
||||
:return: (``n``, ``frac1``, ``(frac2_msb, frac2_lsb)``, ``(mod2_msb, mod2_lsb)``)
|
||||
"""
|
||||
f_pfd = int64(f_pfd)
|
||||
f_vco = int64(f_vco)
|
||||
|
@ -17,12 +17,12 @@ ALMAZNY_LEGACY_SPIT_WR = 32
|
||||
|
||||
class AlmaznyLegacy:
|
||||
"""
|
||||
Almazny (High frequency mezzanine board for Mirny)
|
||||
Almazny (High-frequency mezzanine board for Mirny)
|
||||
|
||||
This applies to Almazny hardware v1.1 and earlier.
|
||||
Use :class:`artiq.coredevice.almazny.AlmaznyChannel` for Almazny v1.2 and later.
|
||||
Use :class:`~artiq.coredevice.almazny.AlmaznyChannel` for Almazny v1.2 and later.
|
||||
|
||||
:param host_mirny: Mirny device Almazny is connected to
|
||||
:param host_mirny: :class:`~artiq.coredevice.mirny.Mirny` device Almazny is connected to
|
||||
"""
|
||||
|
||||
def __init__(self, dmgr, host_mirny):
|
||||
@ -121,12 +121,13 @@ class AlmaznyLegacy:
|
||||
|
||||
class AlmaznyChannel:
|
||||
"""
|
||||
One Almazny channel
|
||||
Driver for one Almazny channel.
|
||||
|
||||
Almazny is a mezzanine for the Quad PLL RF source Mirny that exposes and
|
||||
controls the frequency-doubled outputs.
|
||||
This driver requires Almazny hardware revision v1.2 or later
|
||||
and Mirny CPLD gateware v0.3 or later.
|
||||
Use :class:`artiq.coredevice.almazny.AlmaznyLegacy` for Almazny hardware v1.1 and earlier.
|
||||
Use :class:`~artiq.coredevice.almazny.AlmaznyLegacy` for Almazny hardware v1.1 and earlier.
|
||||
|
||||
:param host_mirny: Mirny CPLD device name
|
||||
:param channel: channel index (0-3)
|
||||
|
@ -21,9 +21,9 @@ class CoreCache:
|
||||
"""Extract a value from the core device cache.
|
||||
After a value is extracted, it cannot be replaced with another value using
|
||||
:meth:`put` until all kernel functions finish executing; attempting
|
||||
to replace it will result in a :class:`artiq.coredevice.exceptions.CacheError`.
|
||||
to replace it will result in a :class:`~artiq.coredevice.exceptions.CacheError`.
|
||||
|
||||
If the cache does not contain any value associated with ``key``, an empty list
|
||||
If the cache does not contain any value associated with `key`, an empty list
|
||||
is returned.
|
||||
|
||||
The value is not copied, so mutating it will change what's stored in the cache.
|
||||
|
@ -73,8 +73,8 @@ class Core:
|
||||
On platforms that use clock multiplication and SERDES-based PHYs,
|
||||
this is the period after multiplication. For example, with a RTIO core
|
||||
clocked at 125MHz and a SERDES multiplication factor of 8, the
|
||||
reference period is 1ns.
|
||||
The time machine unit is equal to this period.
|
||||
reference period is ``1 ns``.
|
||||
The machine time unit (``mu``) is equal to this period.
|
||||
:param ref_multiplier: ratio between the RTIO fine timestamp frequency
|
||||
and the RTIO coarse timestamp frequency (e.g. SERDES multiplication
|
||||
factor).
|
||||
@ -116,6 +116,8 @@ class Core:
|
||||
self.trigger_analyzer_proxy()
|
||||
|
||||
def close(self):
|
||||
"""Disconnect core device and close sockets.
|
||||
"""
|
||||
self.comm.close()
|
||||
|
||||
def compile(self, function, args, kwargs, set_result=None,
|
||||
@ -241,8 +243,8 @@ class Core:
|
||||
Similarly, modified values are not written back, and explicit RPC should be used
|
||||
to modify host objects.
|
||||
Carefully review the source code of drivers calls used in precompiled kernels, as
|
||||
they may rely on host object attributes being transfered between kernel calls.
|
||||
Examples include code used to control DDS phase, and Urukul RF switch control
|
||||
they may rely on host object attributes being transferred between kernel calls.
|
||||
Examples include code used to control DDS phase and Urukul RF switch control
|
||||
via the CPLD register.
|
||||
|
||||
The return value of the callable is the return value of the kernel, if any.
|
||||
@ -273,7 +275,7 @@ class Core:
|
||||
@portable
|
||||
def seconds_to_mu(self, seconds):
|
||||
"""Convert seconds to the corresponding number of machine units
|
||||
(RTIO cycles).
|
||||
(fine RTIO cycles).
|
||||
|
||||
:param seconds: time (in seconds) to convert.
|
||||
"""
|
||||
@ -281,7 +283,7 @@ class Core:
|
||||
|
||||
@portable
|
||||
def mu_to_seconds(self, mu):
|
||||
"""Convert machine units (RTIO cycles) to seconds.
|
||||
"""Convert machine units (fine RTIO cycles) to seconds.
|
||||
|
||||
:param mu: cycle count to convert.
|
||||
"""
|
||||
@ -296,7 +298,7 @@ class Core:
|
||||
for the actual value of the hardware register at the instant when
|
||||
execution resumes in the caller.
|
||||
|
||||
For a more detailed description of these concepts, see :doc:`/rtio`.
|
||||
For a more detailed description of these concepts, see :doc:`rtio`.
|
||||
"""
|
||||
return rtio_get_counter()
|
||||
|
||||
@ -315,7 +317,7 @@ class Core:
|
||||
def get_rtio_destination_status(self, destination):
|
||||
"""Returns whether the specified RTIO destination is up.
|
||||
This is particularly useful in startup kernels to delay
|
||||
startup until certain DRTIO destinations are up."""
|
||||
startup until certain DRTIO destinations are available."""
|
||||
return rtio_get_destination_status(destination)
|
||||
|
||||
@kernel
|
||||
@ -343,7 +345,7 @@ class Core:
|
||||
|
||||
Returns only after the dump has been retrieved from the device.
|
||||
|
||||
Raises IOError if no analyzer proxy has been configured, or if the
|
||||
Raises :exc:`IOError` if no analyzer proxy has been configured, or if the
|
||||
analyzer proxy fails. In the latter case, more details would be
|
||||
available in the proxy log.
|
||||
"""
|
||||
|
@ -76,11 +76,11 @@ class CoreDMA:
|
||||
|
||||
@kernel
|
||||
def record(self, name, enable_ddma=False):
|
||||
"""Returns a context manager that will record a DMA trace called ``name``.
|
||||
"""Returns a context manager that will record a DMA trace called `name`.
|
||||
Any previously recorded trace with the same name is overwritten.
|
||||
The trace will persist across kernel switches.
|
||||
|
||||
In DRTIO context, distributed DMA can be toggled with ``enable_ddma``.
|
||||
In DRTIO context, distributed DMA can be toggled with `enable_ddma`.
|
||||
Enabling it allows running DMA on satellites, rather than sending all
|
||||
events from the master.
|
||||
|
||||
@ -116,7 +116,7 @@ class CoreDMA:
|
||||
def playback_handle(self, handle):
|
||||
"""Replays a handle obtained with :meth:`get_handle`. Using this function
|
||||
is much faster than :meth:`playback` for replaying a set of traces repeatedly,
|
||||
but incurs the overhead of managing the handles onto the programmer."""
|
||||
but offloads the overhead of managing the handles onto the programmer."""
|
||||
(epoch, advance_mu, ptr, uses_ddma) = handle
|
||||
if self.epoch != epoch:
|
||||
raise DMAError("Invalid handle")
|
||||
|
@ -1,9 +1,9 @@
|
||||
"""Driver for RTIO-enabled TTL edge counter.
|
||||
|
||||
Like for the TTL input PHYs, sensitivity can be configured over RTIO
|
||||
(``gate_rising()``, etc.). In contrast to the former, however, the count is
|
||||
As for the TTL input PHYs, sensitivity can be configured over RTIO
|
||||
(:meth:`gate_rising<EdgeCounter.gate_rising>`, etc.). In contrast to the former, however, the count is
|
||||
accumulated in gateware, and only a single input event is generated at the end
|
||||
of each gate period::
|
||||
of each gate period: ::
|
||||
|
||||
with parallel:
|
||||
doppler_cool()
|
||||
@ -17,12 +17,12 @@ of each gate period::
|
||||
print("Readout counts:", self.pmt_counter.fetch_count())
|
||||
|
||||
For applications where the timestamps of the individual input events are not
|
||||
required, this has two advantages over ``TTLInOut.count()`` beyond raw
|
||||
throughput. First, it is easy to count events during multiple separate periods
|
||||
without blocking to read back counts in between, as illustrated in the above
|
||||
example. Secondly, as each count total only takes up a single input event, it
|
||||
is much easier to acquire counts on several channels in parallel without
|
||||
risking input FIFO overflows::
|
||||
required, this has two advantages over :meth:`TTLInOut.count<artiq.coredevice.ttl.TTLInOut.count>`
|
||||
beyond raw throughput. First, it is easy to count events during multiple separate
|
||||
periods without blocking to read back counts in between, as illustrated in the
|
||||
above example. Secondly, as each count total only takes up a single input event,
|
||||
it is much easier to acquire counts on several channels in parallel without
|
||||
risking input RTIO overflows: ::
|
||||
|
||||
# Using the TTLInOut driver, pmt_1 input events are only processed
|
||||
# after pmt_0 is done counting. To avoid RTIOOverflows, a round-robin
|
||||
@ -35,8 +35,6 @@ risking input FIFO overflows::
|
||||
counts_0 = self.pmt_0.count(now_mu()) # blocks
|
||||
counts_1 = self.pmt_1.count(now_mu())
|
||||
|
||||
#
|
||||
|
||||
# Using gateware counters, only a single input event each is
|
||||
# generated, greatly reducing the load on the input FIFOs:
|
||||
|
||||
@ -47,7 +45,7 @@ risking input FIFO overflows::
|
||||
counts_0 = self.pmt_0_counter.fetch_count() # blocks
|
||||
counts_1 = self.pmt_1_counter.fetch_count()
|
||||
|
||||
See :mod:`artiq.gateware.rtio.phy.edge_counter` and
|
||||
See the sources of :mod:`artiq.gateware.rtio.phy.edge_counter` and
|
||||
:meth:`artiq.gateware.eem.DIO.add_std` for the gateware components.
|
||||
"""
|
||||
|
||||
@ -176,13 +174,13 @@ class EdgeCounter:
|
||||
"""Emit an RTIO event at the current timeline position to set the
|
||||
gateware configuration.
|
||||
|
||||
For most use cases, the `gate_*` wrappers will be more convenient.
|
||||
For most use cases, the ``gate_*`` wrappers will be more convenient.
|
||||
|
||||
:param count_rising: Whether to count rising signal edges.
|
||||
:param count_falling: Whether to count falling signal edges.
|
||||
:param send_count_event: If `True`, an input event with the current
|
||||
:param send_count_event: If ``True``, an input event with the current
|
||||
counter value is generated on the next clock cycle (once).
|
||||
:param reset_to_zero: If `True`, the counter value is reset to zero on
|
||||
:param reset_to_zero: If ``True``, the counter value is reset to zero on
|
||||
the next clock cycle (once).
|
||||
"""
|
||||
config = int32(0)
|
||||
|
@ -137,7 +137,7 @@ class RTIOOverflow(Exception):
|
||||
|
||||
|
||||
class RTIODestinationUnreachable(Exception):
|
||||
"""Raised with a RTIO operation could not be completed due to a DRTIO link
|
||||
"""Raised when a RTIO operation could not be completed due to a DRTIO link
|
||||
being down.
|
||||
"""
|
||||
artiq_builtin = True
|
||||
|
@ -1,4 +1,4 @@
|
||||
"""RTIO driver for the Fastino 32channel, 16 bit, 2.5 MS/s per channel,
|
||||
"""RTIO driver for the Fastino 32-channel, 16-bit, 2.5 MS/s per channel
|
||||
streaming DAC.
|
||||
"""
|
||||
from numpy import int32, int64
|
||||
@ -17,22 +17,22 @@ class Fastino:
|
||||
to the DAC RTIO addresses, if a channel is not "held" by setting its bit
|
||||
using :meth:`set_hold`, the next frame will contain the update. For the
|
||||
DACs held, the update is triggered explicitly by setting the corresponding
|
||||
bit using :meth:`set_update`. Update is self-clearing. This enables atomic
|
||||
bit using :meth:`update`. Update is self-clearing. This enables atomic
|
||||
DAC updates synchronized to a frame edge.
|
||||
|
||||
The `log2_width=0` RTIO layout uses one DAC channel per RTIO address and a
|
||||
dense RTIO address space. The RTIO words are narrow (32 bit) and
|
||||
The ``log2_width=0`` RTIO layout uses one DAC channel per RTIO address and a
|
||||
dense RTIO address space. The RTIO words are narrow (32-bit) and
|
||||
few-channel updates are efficient. There is the least amount of DAC state
|
||||
tracking in kernels, at the cost of more DMA and RTIO data.
|
||||
The setting here and in the RTIO PHY (gateware) must match.
|
||||
|
||||
Other `log2_width` (up to `log2_width=5`) settings pack multiple
|
||||
Other ``log2_width`` (up to ``log2_width=5``) settings pack multiple
|
||||
(in powers of two) DAC channels into one group and into one RTIO write.
|
||||
The RTIO data width increases accordingly. The `log2_width`
|
||||
The RTIO data width increases accordingly. The ``log2_width``
|
||||
LSBs of the RTIO address for a DAC channel write must be zero and the
|
||||
address space is sparse. For `log2_width=5` the RTIO data is 512 bit wide.
|
||||
address space is sparse. For ``log2_width=5`` the RTIO data is 512-bit wide.
|
||||
|
||||
If `log2_width` is zero, the :meth:`set_dac`/:meth:`set_dac_mu` interface
|
||||
If ``log2_width`` is zero, the :meth:`set_dac`/:meth:`set_dac_mu` interface
|
||||
must be used. If non-zero, the :meth:`set_group`/:meth:`set_group_mu`
|
||||
interface must be used.
|
||||
|
||||
@ -63,15 +63,16 @@ class Fastino:
|
||||
* disables RESET, DAC_CLR, enables AFE_PWR
|
||||
* clears error counters, enables error counting
|
||||
* turns LEDs off
|
||||
* clears `hold` and `continuous` on all channels
|
||||
* clears ``hold`` and ``continuous`` on all channels
|
||||
* clear and resets interpolators to unit rate change on all
|
||||
channels
|
||||
|
||||
It does not change set channel voltages and does not reset the PLLs or clock
|
||||
domains.
|
||||
|
||||
Note: On Fastino gateware before v0.2 this may lead to 0 voltage being emitted
|
||||
transiently.
|
||||
.. warning::
|
||||
On Fastino gateware before v0.2 this may lead to 0 voltage being emitted
|
||||
transiently.
|
||||
"""
|
||||
self.set_cfg(reset=0, afe_power_down=0, dac_clr=0, clr_err=1)
|
||||
delay_mu(self.t_frame)
|
||||
@ -115,7 +116,7 @@ class Fastino:
|
||||
"""Write DAC data in machine units.
|
||||
|
||||
:param dac: DAC channel to write to (0-31).
|
||||
:param data: DAC word to write, 16 bit unsigned integer, in machine
|
||||
:param data: DAC word to write, 16-bit unsigned integer, in machine
|
||||
units.
|
||||
"""
|
||||
self.write(dac, data)
|
||||
@ -124,9 +125,9 @@ class Fastino:
|
||||
def set_group_mu(self, dac: TInt32, data: TList(TInt32)):
|
||||
"""Write a group of DAC channels in machine units.
|
||||
|
||||
:param dac: First channel in DAC channel group (0-31). The `log2_width`
|
||||
:param dac: First channel in DAC channel group (0-31). The ``log2_width``
|
||||
LSBs must be zero.
|
||||
:param data: List of DAC data pairs (2x16 bit unsigned) to write,
|
||||
:param data: List of DAC data pairs (2x16-bit unsigned) to write,
|
||||
in machine units. Data exceeding group size is ignored.
|
||||
If the list length is less than group size, the remaining
|
||||
DAC channels within the group are cleared to 0 (machine units).
|
||||
@ -137,10 +138,10 @@ class Fastino:
|
||||
|
||||
@portable
|
||||
def voltage_to_mu(self, voltage):
|
||||
"""Convert SI Volts to DAC machine units.
|
||||
"""Convert SI volts to DAC machine units.
|
||||
|
||||
:param voltage: Voltage in SI Volts.
|
||||
:return: DAC data word in machine units, 16 bit integer.
|
||||
:param voltage: Voltage in SI volts.
|
||||
:return: DAC data word in machine units, 16-bit integer.
|
||||
"""
|
||||
data = int32(round((0x8000/10.)*voltage)) + int32(0x8000)
|
||||
if data < 0 or data > 0xffff:
|
||||
@ -149,9 +150,9 @@ class Fastino:
|
||||
|
||||
@portable
|
||||
def voltage_group_to_mu(self, voltage, data):
|
||||
"""Convert SI Volts to packed DAC channel group machine units.
|
||||
"""Convert SI volts to packed DAC channel group machine units.
|
||||
|
||||
:param voltage: List of SI Volt voltages.
|
||||
:param voltage: List of SI volt voltages.
|
||||
:param data: List of DAC channel data pairs to write to.
|
||||
Half the length of `voltage`.
|
||||
"""
|
||||
@ -185,7 +186,7 @@ class Fastino:
|
||||
def update(self, update):
|
||||
"""Schedule channels for update.
|
||||
|
||||
:param update: Bit mask of channels to update (32 bit).
|
||||
:param update: Bit mask of channels to update (32-bit).
|
||||
"""
|
||||
self.write(0x20, update)
|
||||
|
||||
@ -193,7 +194,7 @@ class Fastino:
|
||||
def set_hold(self, hold):
|
||||
"""Set channels to manual update.
|
||||
|
||||
:param hold: Bit mask of channels to hold (32 bit).
|
||||
:param hold: Bit mask of channels to hold (32-bit).
|
||||
"""
|
||||
self.write(0x21, hold)
|
||||
|
||||
@ -214,9 +215,9 @@ class Fastino:
|
||||
|
||||
@kernel
|
||||
def set_leds(self, leds):
|
||||
"""Set the green user-defined LEDs
|
||||
"""Set the green user-defined LEDs.
|
||||
|
||||
:param leds: LED status, 8 bit integer each bit corresponding to one
|
||||
:param leds: LED status, 8-bit integer each bit corresponding to one
|
||||
green LED.
|
||||
"""
|
||||
self.write(0x23, leds)
|
||||
@ -245,16 +246,16 @@ class Fastino:
|
||||
def stage_cic(self, rate) -> TInt32:
|
||||
"""Compute and stage interpolator configuration.
|
||||
|
||||
This method approximates the desired interpolation rate using a 10 bit
|
||||
floating point representation (6 bit mantissa, 4 bit exponent) and
|
||||
This method approximates the desired interpolation rate using a 10-bit
|
||||
floating point representation (6-bit mantissa, 4-bit exponent) and
|
||||
then determines an optimal interpolation gain compensation exponent
|
||||
to avoid clipping. Gains for rates that are powers of two are accurately
|
||||
compensated. Other rates lead to overall less than unity gain (but more
|
||||
than 0.5 gain).
|
||||
|
||||
The overall gain including gain compensation is
|
||||
`actual_rate**order/2**ceil(log2(actual_rate**order))`
|
||||
where `order = 3`.
|
||||
The overall gain including gain compensation is ``actual_rate ** order /
|
||||
2 ** ceil(log2(actual_rate ** order))``
|
||||
where ``order = 3``.
|
||||
|
||||
Returns the actual interpolation rate.
|
||||
"""
|
||||
@ -293,7 +294,7 @@ class Fastino:
|
||||
their output is supposed to be constant.
|
||||
|
||||
This method resets and settles the affected interpolators. There will be
|
||||
no output updates for the next `order = 3` input samples.
|
||||
no output updates for the next ``order = 3`` input samples.
|
||||
Affected channels will only accept one input sample per input sample
|
||||
period. This method synchronizes the input sample period to the current
|
||||
frame on the affected channels.
|
||||
|
@ -102,7 +102,7 @@ class Grabber:
|
||||
this call or the next.
|
||||
|
||||
If the timeout is reached before data is available, the exception
|
||||
GrabberTimeoutException is raised.
|
||||
:exc:`GrabberTimeoutException` is raised.
|
||||
|
||||
:param timeout_mu: Timestamp at which a timeout will occur. Set to -1
|
||||
(default) to disable timeout.
|
||||
|
@ -43,7 +43,7 @@ def i2c_poll(busno, busaddr):
|
||||
"""Poll I2C device at address.
|
||||
|
||||
:param busno: I2C bus number
|
||||
:param busaddr: 8 bit I2C device address (LSB=0)
|
||||
:param busaddr: 8-bit I2C device address (LSB=0)
|
||||
:returns: True if the poll was ACKed
|
||||
"""
|
||||
i2c_start(busno)
|
||||
@ -57,7 +57,7 @@ def i2c_write_byte(busno, busaddr, data, ack=True):
|
||||
"""Write one byte to a device.
|
||||
|
||||
:param busno: I2C bus number
|
||||
:param busaddr: 8 bit I2C device address (LSB=0)
|
||||
:param busaddr: 8-bit I2C device address (LSB=0)
|
||||
:param data: Data byte to be written
|
||||
:param nack: Allow NACK
|
||||
"""
|
||||
@ -76,7 +76,7 @@ def i2c_read_byte(busno, busaddr):
|
||||
"""Read one byte from a device.
|
||||
|
||||
:param busno: I2C bus number
|
||||
:param busaddr: 8 bit I2C device address (LSB=0)
|
||||
:param busaddr: 8-bit I2C device address (LSB=0)
|
||||
:returns: Byte read
|
||||
"""
|
||||
i2c_start(busno)
|
||||
@ -95,10 +95,10 @@ def i2c_write_many(busno, busaddr, addr, data, ack_last=True):
|
||||
"""Transfer multiple bytes to a device.
|
||||
|
||||
:param busno: I2c bus number
|
||||
:param busaddr: 8 bit I2C device address (LSB=0)
|
||||
:param addr: 8 bit data address
|
||||
:param busaddr: 8-bit I2C device address (LSB=0)
|
||||
:param addr: 8-bit data address
|
||||
:param data: Data bytes to be written
|
||||
:param ack_last: Expect I2C ACK of the last byte written. If `False`,
|
||||
:param ack_last: Expect I2C ACK of the last byte written. If ``False``,
|
||||
the last byte may be NACKed (e.g. EEPROM full page writes).
|
||||
"""
|
||||
n = len(data)
|
||||
@ -121,8 +121,8 @@ def i2c_read_many(busno, busaddr, addr, data):
|
||||
"""Transfer multiple bytes from a device.
|
||||
|
||||
:param busno: I2c bus number
|
||||
:param busaddr: 8 bit I2C device address (LSB=0)
|
||||
:param addr: 8 bit data address
|
||||
:param busaddr: 8-bit I2C device address (LSB=0)
|
||||
:param addr: 8-bit data address
|
||||
:param data: List of integers to be filled with the data read.
|
||||
One entry ber byte.
|
||||
"""
|
||||
@ -147,7 +147,7 @@ class I2CSwitch:
|
||||
|
||||
PCA954X (or other) type detection is done by the CPU during I2C init.
|
||||
|
||||
I2C transactions not real-time, and are performed by the CPU without
|
||||
I2C transactions are not real-time, and are performed by the CPU without
|
||||
involving RTIO.
|
||||
|
||||
On the KC705, this chip is used for selecting the I2C buses on the two FMC
|
||||
@ -176,7 +176,7 @@ class I2CSwitch:
|
||||
class TCA6424A:
|
||||
"""Driver for the TCA6424A I2C I/O expander.
|
||||
|
||||
I2C transactions not real-time, and are performed by the CPU without
|
||||
I2C transactions are not real-time, and are performed by the CPU without
|
||||
involving RTIO.
|
||||
|
||||
On the NIST QC2 hardware, this chip is used for switching the directions
|
||||
@ -212,7 +212,7 @@ class TCA6424A:
|
||||
class PCF8574A:
|
||||
"""Driver for the PCF8574 I2C remote 8-bit I/O expander.
|
||||
|
||||
I2C transactions not real-time, and are performed by the CPU without
|
||||
I2C transactions are not real-time, and are performed by the CPU without
|
||||
involving RTIO.
|
||||
"""
|
||||
def __init__(self, dmgr, busno=0, address=0x7c, core_device="core"):
|
||||
|
@ -1,4 +1,4 @@
|
||||
"""RTIO driver for Mirny (4 channel GHz PLLs)
|
||||
"""RTIO driver for Mirny (4-channel GHz PLLs)
|
||||
"""
|
||||
|
||||
from artiq.language.core import kernel, delay, portable
|
||||
@ -82,7 +82,7 @@ class Mirny:
|
||||
|
||||
@kernel
|
||||
def read_reg(self, addr):
|
||||
"""Read a register"""
|
||||
"""Read a register."""
|
||||
self.bus.set_config_mu(
|
||||
SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, 24, SPIT_RD, SPI_CS
|
||||
)
|
||||
@ -91,7 +91,7 @@ class Mirny:
|
||||
|
||||
@kernel
|
||||
def write_reg(self, addr, data):
|
||||
"""Write a register"""
|
||||
"""Write a register."""
|
||||
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 24, SPIT_WR, SPI_CS)
|
||||
self.bus.write((addr << 25) | WE | ((data & 0xFFFF) << 8))
|
||||
|
||||
@ -101,9 +101,9 @@ class Mirny:
|
||||
Initialize and detect Mirny.
|
||||
|
||||
Select the clock source based the board's hardware revision.
|
||||
Raise ValueError if the board's hardware revision is not supported.
|
||||
Raise :exc:`ValueError` if the board's hardware revision is not supported.
|
||||
|
||||
:param blind: Verify presence and protocol compatibility. Raise ValueError on failure.
|
||||
:param blind: Verify presence and protocol compatibility. Raise :exc:`ValueError` on failure.
|
||||
"""
|
||||
reg0 = self.read_reg(0)
|
||||
self.hw_rev = reg0 & 0x3
|
||||
@ -138,7 +138,7 @@ class Mirny:
|
||||
def set_att_mu(self, channel, att):
|
||||
"""Set digital step attenuator in machine units.
|
||||
|
||||
:param att: Attenuation setting, 8 bit digital.
|
||||
:param att: Attenuation setting, 8-bit digital.
|
||||
"""
|
||||
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 16, SPIT_WR, SPI_CS)
|
||||
self.bus.write(((channel | 8) << 25) | (att << 16))
|
||||
@ -149,7 +149,7 @@ class Mirny:
|
||||
|
||||
This method will write the attenuator settings of the selected channel.
|
||||
|
||||
.. seealso:: :meth:`set_att_mu`
|
||||
See also :meth:`Mirny.set_att_mu`.
|
||||
|
||||
:param channel: Attenuator channel (0-3).
|
||||
:param att: Attenuation setting in dB. Higher value is more
|
||||
@ -160,7 +160,7 @@ class Mirny:
|
||||
|
||||
@kernel
|
||||
def write_ext(self, addr, length, data, ext_div=SPIT_WR):
|
||||
"""Perform SPI write to a prefixed address"""
|
||||
"""Perform SPI write to a prefixed address."""
|
||||
self.bus.set_config_mu(SPI_CONFIG, 8, SPIT_WR, SPI_CS)
|
||||
self.bus.write(addr << 25)
|
||||
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, length, ext_div, SPI_CS)
|
||||
|
@ -16,31 +16,31 @@ SPI_CS_SR = 2
|
||||
|
||||
@portable
|
||||
def adc_ctrl(channel=1, softspan=0b111, valid=1):
|
||||
"""Build a LTC2335-16 control word"""
|
||||
"""Build a LTC2335-16 control word."""
|
||||
return (valid << 7) | (channel << 3) | softspan
|
||||
|
||||
|
||||
@portable
|
||||
def adc_softspan(data):
|
||||
"""Return the softspan configuration index from a result packet"""
|
||||
"""Return the softspan configuration index from a result packet."""
|
||||
return data & 0x7
|
||||
|
||||
|
||||
@portable
|
||||
def adc_channel(data):
|
||||
"""Return the channel index from a result packet"""
|
||||
"""Return the channel index from a result packet."""
|
||||
return (data >> 3) & 0x7
|
||||
|
||||
|
||||
@portable
|
||||
def adc_data(data):
|
||||
"""Return the ADC value from a result packet"""
|
||||
"""Return the ADC value from a result packet."""
|
||||
return (data >> 8) & 0xffff
|
||||
|
||||
|
||||
@portable
|
||||
def adc_value(data, v_ref=5.):
|
||||
"""Convert a ADC result packet to SI units (Volt)"""
|
||||
"""Convert a ADC result packet to SI units (volts)."""
|
||||
softspan = adc_softspan(data)
|
||||
data = adc_data(data)
|
||||
g = 625
|
||||
@ -107,7 +107,7 @@ class Novogorny:
|
||||
def configure(self, data):
|
||||
"""Set up the ADC sequencer.
|
||||
|
||||
:param data: List of 8 bit control words to write into the sequencer
|
||||
:param data: List of 8-bit control words to write into the sequencer
|
||||
table.
|
||||
"""
|
||||
if len(data) > 1:
|
||||
@ -137,12 +137,10 @@ class Novogorny:
|
||||
|
||||
@kernel
|
||||
def sample(self, next_ctrl=0):
|
||||
"""Acquire a sample
|
||||
|
||||
.. seealso:: :meth:`sample_mu`
|
||||
"""Acquire a sample. See also :meth:`Novogorny.sample_mu`.
|
||||
|
||||
:param next_ctrl: ADC control word for the next sample
|
||||
:return: The ADC result packet (Volt)
|
||||
:return: The ADC result packet (volts)
|
||||
"""
|
||||
return adc_value(self.sample_mu(), self.v_ref)
|
||||
|
||||
@ -151,7 +149,7 @@ class Novogorny:
|
||||
"""Acquire a burst of samples.
|
||||
|
||||
If the burst is too long and the sample rate too high, there will be
|
||||
RTIO input overflows.
|
||||
:exc:RTIOOverflow exceptions.
|
||||
|
||||
High sample rates lead to gain errors since the impedance between the
|
||||
instrumentation amplifier and the ADC is high.
|
||||
|
@ -85,7 +85,7 @@ SERVO_T_CYCLE = (32+12+192+24+4)*ns # Must match gateware ADC parameters
|
||||
class Phaser:
|
||||
"""Phaser 4-channel, 16-bit, 1 GS/s DAC coredevice driver.
|
||||
|
||||
Phaser contains a 4 channel, 1 GS/s DAC chip with integrated upconversion,
|
||||
Phaser contains a 4-channel, 1 GS/s DAC chip with integrated upconversion,
|
||||
quadrature modulation compensation and interpolation features.
|
||||
|
||||
The coredevice RTIO PHY and the Phaser gateware come in different modes
|
||||
@ -109,9 +109,9 @@ class Phaser:
|
||||
**Base mode**
|
||||
|
||||
The coredevice produces 2 IQ (in-phase and quadrature) data streams with 25
|
||||
MS/s and 14 bit per quadrature. Each data stream supports 5 independent
|
||||
numerically controlled IQ oscillators (NCOs, DDSs with 32 bit frequency, 16
|
||||
bit phase, 15 bit amplitude, and phase accumulator clear functionality)
|
||||
MS/s and 14 bits per quadrature. Each data stream supports 5 independent
|
||||
numerically controlled IQ oscillators (NCOs, DDSs with 32-bit frequency,
|
||||
16-bit phase, 15-bit amplitude, and phase accumulator clear functionality)
|
||||
added together. See :class:`PhaserChannel` and :class:`PhaserOscillator`.
|
||||
|
||||
Together with a data clock, framing marker, a checksum and metadata for
|
||||
@ -119,30 +119,28 @@ class Phaser:
|
||||
FastLink via a single EEM connector from coredevice to Phaser.
|
||||
|
||||
On Phaser in the FPGA the data streams are buffered and interpolated
|
||||
from 25 MS/s to 500 MS/s 16 bit followed by a 500 MS/s digital upconverter
|
||||
from 25 MS/s to 500 MS/s 16-bit followed by a 500 MS/s digital upconverter
|
||||
with adjustable frequency and phase. The interpolation passband is 20 MHz
|
||||
wide, passband ripple is less than 1e-3 amplitude, stopband attenuation
|
||||
is better than 75 dB at offsets > 15 MHz and better than 90 dB at offsets
|
||||
> 30 MHz.
|
||||
|
||||
The four 16 bit 500 MS/s DAC data streams are sent via a 32 bit parallel
|
||||
The four 16-bit 500 MS/s DAC data streams are sent via a 32-bit parallel
|
||||
LVDS bus operating at 1 Gb/s per pin pair and processed in the DAC (Texas
|
||||
Instruments DAC34H84). On the DAC 2x interpolation, sinx/x compensation,
|
||||
quadrature modulator compensation, fine and coarse mixing as well as group
|
||||
delay capabilities are available. If desired, these features my be
|
||||
configured via the `dac` dictionary.
|
||||
configured via the ``dac`` dictionary.
|
||||
|
||||
The latency/group delay from the RTIO events setting
|
||||
:class:`PhaserOscillator` or :class:`PhaserChannel` DUC parameters all the
|
||||
way to the DAC outputs is deterministic. This enables deterministic
|
||||
absolute phase with respect to other RTIO input and output events
|
||||
(see `get_next_frame_mu()`).
|
||||
(see :meth:`get_next_frame_mu()`).
|
||||
|
||||
**Miqro mode**
|
||||
|
||||
See :class:`Miqro`
|
||||
|
||||
Here the DAC operates in 4x interpolation.
|
||||
See :class:`Miqro`. Here the DAC operates in 4x interpolation.
|
||||
|
||||
**Analog flow**
|
||||
|
||||
@ -171,7 +169,7 @@ class Phaser:
|
||||
and Q datastreams from the DUC by the IIR output. The IIR state is updated at
|
||||
the 3.788 MHz ADC sampling rate.
|
||||
|
||||
Each channel IIR features 4 profiles, each consisting of the [b0, b1, a1] filter
|
||||
Each channel IIR features 4 profiles, each consisting of the ``[b0, b1, a1]`` filter
|
||||
coefficients as well as an output offset. The coefficients and offset can be
|
||||
set for each profile individually and the profiles each have their own ``y0``,
|
||||
``y1`` output registers (the ``x0``, ``x1`` inputs are shared). To avoid
|
||||
@ -185,25 +183,25 @@ class Phaser:
|
||||
still ingests samples and updates its input ``x0`` and ``x1`` registers, but
|
||||
does not update the ``y0``, ``y1`` output registers.
|
||||
|
||||
After power-up the servo is disabled, in profile 0, with coefficients [0, 0, 0]
|
||||
After power-up the servo is disabled, in profile 0, with coefficients ``[0, 0, 0]``
|
||||
and hold is enabled. If older gateware without ther servo is loaded onto the
|
||||
Phaser FPGA, the device simply behaves as if the servo is disabled and none of
|
||||
the servo functions have any effect.
|
||||
|
||||
.. note:: Various register settings of the DAC and the quadrature
|
||||
upconverters are available to be modified through the `dac`, `trf0`,
|
||||
`trf1` dictionaries. These can be set through the device database
|
||||
(`device_db.py`). The settings are frozen during instantiation of the
|
||||
class and applied during `init()`. See the :class:`DAC34H84` and
|
||||
:class:`TRF372017` source for details.
|
||||
upconverters are available to be modified through the ``dac``, ``trf0``,
|
||||
``trf1`` dictionaries. These can be set through the device database
|
||||
(``device_db.py``). The settings are frozen during instantiation of the
|
||||
class and applied during ``init()``. See the :class:`dac34H84` and
|
||||
:class:`trf372017` source for details.
|
||||
|
||||
.. note:: To establish deterministic latency between RTIO time base and DAC
|
||||
output, the DAC FIFO read pointer value (`fifo_offset`) must be
|
||||
fixed. If `tune_fifo_offset=True` (the default) a value with maximum
|
||||
output, the DAC FIFO read pointer value (``fifo_offset``) must be
|
||||
fixed. If `tune_fifo_offset` = ``True`` (the default) a value with maximum
|
||||
margin is determined automatically by `dac_tune_fifo_offset` each time
|
||||
`init()` is called. This value should be used for the `fifo_offset` key
|
||||
of the `dac` settings of Phaser in `device_db.py` and automatic
|
||||
tuning should be disabled by `tune_fifo_offset=False`.
|
||||
:meth:`init` is called. This value should be used for the ``fifo_offset`` key
|
||||
of the ``dac`` settings of Phaser in ``device_db.py`` and automatic
|
||||
tuning should be disabled by `tune_fifo_offset` = ``False```.
|
||||
|
||||
:param channel: Base RTIO channel number
|
||||
:param core_device: Core device name (default: "core")
|
||||
@ -219,9 +217,9 @@ class Phaser:
|
||||
:param trf1: Channel 1 TRF372017 quadrature upconverter settings as a
|
||||
dictionary.
|
||||
|
||||
Attributes:
|
||||
**Attributes:**
|
||||
|
||||
* :attr:`channel`: List of two :class:`PhaserChannel`
|
||||
* :attr:`channel`: List of two instances of :class:`PhaserChannel`
|
||||
To access oscillators, digital upconverters, PLL/VCO analog
|
||||
quadrature upconverters and attenuators.
|
||||
"""
|
||||
@ -463,8 +461,8 @@ class Phaser:
|
||||
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)
|
||||
: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))
|
||||
@ -473,8 +471,8 @@ class Phaser:
|
||||
def read8(self, addr) -> TInt32:
|
||||
"""Read from FPGA register.
|
||||
|
||||
:param addr: Address to read from (7 bit)
|
||||
:return: Data read (8 bit)
|
||||
: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)
|
||||
@ -482,13 +480,13 @@ class Phaser:
|
||||
|
||||
@kernel
|
||||
def write16(self, addr, data: TInt32):
|
||||
"""Write 16 bit to a sequence of FPGA registers."""
|
||||
"""Write 16 bits to a sequence of FPGA registers."""
|
||||
self.write8(addr, data >> 8)
|
||||
self.write8(addr + 1, data)
|
||||
|
||||
@kernel
|
||||
def write32(self, addr, data: TInt32):
|
||||
"""Write 32 bit to a sequence of FPGA registers."""
|
||||
"""Write 32 bits to a sequence of FPGA registers."""
|
||||
for offset in range(4):
|
||||
byte = data >> 24
|
||||
self.write8(addr + offset, byte)
|
||||
@ -496,7 +494,7 @@ class Phaser:
|
||||
|
||||
@kernel
|
||||
def read32(self, addr) -> TInt32:
|
||||
"""Read 32 bit from a sequence of FPGA registers."""
|
||||
"""Read 32 bits from a sequence of FPGA registers."""
|
||||
data = 0
|
||||
for offset in range(4):
|
||||
data <<= 8
|
||||
@ -508,15 +506,15 @@ class Phaser:
|
||||
def set_leds(self, leds):
|
||||
"""Set the front panel LEDs.
|
||||
|
||||
:param leds: LED settings (6 bit)
|
||||
:param leds: LED settings (6-bit)
|
||||
"""
|
||||
self.write8(PHASER_ADDR_LED, leds)
|
||||
|
||||
@kernel
|
||||
def set_fan_mu(self, pwm):
|
||||
"""Set the fan duty cycle.
|
||||
"""Set the fan duty cycle in machine units.
|
||||
|
||||
:param pwm: Duty cycle in machine units (8 bit)
|
||||
:param pwm: Duty cycle in machine units (8-bit)
|
||||
"""
|
||||
self.write8(PHASER_ADDR_FAN, pwm)
|
||||
|
||||
@ -581,10 +579,10 @@ class Phaser:
|
||||
|
||||
@kernel
|
||||
def measure_frame_timestamp(self):
|
||||
"""Measure the timestamp of an arbitrary frame and store it in `self.frame_tstamp`.
|
||||
"""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()`.
|
||||
See :meth:`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)
|
||||
@ -592,10 +590,10 @@ class Phaser:
|
||||
|
||||
@kernel
|
||||
def get_next_frame_mu(self):
|
||||
"""Return the timestamp of the frame strictly after `now_mu()`.
|
||||
"""Return the timestamp of the frame strictly after :meth:`~artiq.language.core.now_mu()`.
|
||||
|
||||
Register updates (DUC, DAC, TRF, etc.) scheduled at this timestamp and multiples
|
||||
of `self.t_frame` later will have deterministic latency to output.
|
||||
of ``self.t_frame`` later will have deterministic latency to output.
|
||||
"""
|
||||
n = int64((now_mu() - self.frame_tstamp) / self.t_frame)
|
||||
return self.frame_tstamp + (n + 1) * self.t_frame
|
||||
@ -658,7 +656,7 @@ class Phaser:
|
||||
|
||||
@kernel
|
||||
def dac_write(self, addr, data):
|
||||
"""Write 16 bit to a DAC register.
|
||||
"""Write 16 bits to a DAC register.
|
||||
|
||||
:param addr: Register address
|
||||
:param data: Register data to write
|
||||
@ -708,16 +706,16 @@ class Phaser:
|
||||
def dac_sync(self):
|
||||
"""Trigger DAC synchronisation for both output channels.
|
||||
|
||||
The DAC sif_sync is de-asserts, then asserted. The synchronisation is
|
||||
The DAC ``sif_sync`` is de-asserted, then asserted. The synchronisation is
|
||||
triggered on assertion.
|
||||
|
||||
By default, the fine-mixer (NCO) and QMC are synchronised. This
|
||||
includes applying the latest register settings.
|
||||
|
||||
The synchronisation sources may be configured through the `syncsel_x`
|
||||
fields in the `dac` configuration dictionary (see `__init__()`).
|
||||
The synchronisation sources may be configured through the ``syncsel_x``
|
||||
fields in the ``dac`` configuration dictionary (see :class:`Phaser`).
|
||||
|
||||
.. note:: Synchronising the NCO clears the phase-accumulator
|
||||
.. note:: Synchronising the NCO clears the phase-accumulator.
|
||||
"""
|
||||
config1f = self.dac_read(0x1f)
|
||||
delay(.4*ms)
|
||||
@ -726,11 +724,11 @@ class Phaser:
|
||||
|
||||
@kernel
|
||||
def set_dac_cmix(self, fs_8_step):
|
||||
"""Set the DAC coarse mixer frequency for both channels
|
||||
"""Set the DAC coarse mixer frequency for both channels.
|
||||
|
||||
Use of the coarse mixer requires the DAC mixer to be enabled. The mixer
|
||||
can be configured via the `dac` configuration dictionary (see
|
||||
`__init__()`).
|
||||
can be configured via the ``dac`` configuration dictionary (see
|
||||
:class:`Phaser`).
|
||||
|
||||
The selected coarse mixer frequency becomes active without explicit
|
||||
synchronisation.
|
||||
@ -763,8 +761,8 @@ class Phaser:
|
||||
def dac_iotest(self, pattern) -> TInt32:
|
||||
"""Performs a DAC IO test according to the datasheet.
|
||||
|
||||
:param pattern: List of four int32 containing the pattern
|
||||
:return: Bit error mask (16 bits)
|
||||
:param pattern: List of four int32s containing the pattern
|
||||
:return: Bit error mask (16-bit)
|
||||
"""
|
||||
if len(pattern) != 4:
|
||||
raise ValueError("pattern length out of bounds")
|
||||
@ -803,9 +801,9 @@ class Phaser:
|
||||
|
||||
@kernel
|
||||
def dac_tune_fifo_offset(self):
|
||||
"""Scan through `fifo_offset` and configure midpoint setting.
|
||||
"""Scan through ``fifo_offset`` and configure midpoint setting.
|
||||
|
||||
:return: Optimal `fifo_offset` setting with maximum margin to write
|
||||
:return: Optimal ``fifo_offset`` setting with maximum margin to write
|
||||
pointer.
|
||||
"""
|
||||
# expect two or three error free offsets:
|
||||
@ -865,7 +863,7 @@ class PhaserChannel:
|
||||
|
||||
Attributes:
|
||||
|
||||
* :attr:`oscillator`: List of five :class:`PhaserOscillator`.
|
||||
* :attr:`oscillator`: List of five instances of :class:`PhaserOscillator`.
|
||||
* :attr:`miqro`: A :class:`Miqro`.
|
||||
|
||||
.. note:: The amplitude sum of the oscillators must be less than one to
|
||||
@ -879,7 +877,7 @@ class PhaserChannel:
|
||||
changes in oscillator parameters, the overshoot can lead to clipping
|
||||
or overflow after the interpolation. Either band-limit any changes
|
||||
in the oscillator parameters or back off the amplitude sufficiently.
|
||||
Miqro is not affected by this. But both the oscillators and Miqro can
|
||||
Miqro is not affected by this, but both the oscillators and Miqro can
|
||||
be affected by intrinsic overshoot of the interpolator on the DAC.
|
||||
"""
|
||||
kernel_invariants = {"index", "phaser", "trf_mmap"}
|
||||
@ -899,7 +897,7 @@ class PhaserChannel:
|
||||
The data is split accross multiple registers and thus the data
|
||||
is only valid if constant.
|
||||
|
||||
:return: DAC data as 32 bit IQ. I/DACA/DACC in the 16 LSB,
|
||||
:return: DAC data as 32-bit IQ. I/DACA/DACC in the 16 LSB,
|
||||
Q/DACB/DACD in the 16 MSB
|
||||
"""
|
||||
return self.phaser.read32(PHASER_ADDR_DAC0_DATA + (self.index << 4))
|
||||
@ -908,7 +906,7 @@ class PhaserChannel:
|
||||
def set_dac_test(self, data: TInt32):
|
||||
"""Set the DAC test data.
|
||||
|
||||
:param data: 32 bit IQ test data, I/DACA/DACC in the 16 LSB,
|
||||
:param data: 32-bit IQ test data, I/DACA/DACC in the 16 LSB,
|
||||
Q/DACB/DACD in the 16 MSB
|
||||
"""
|
||||
self.phaser.write32(PHASER_ADDR_DAC0_TEST + (self.index << 4), data)
|
||||
@ -930,7 +928,7 @@ class PhaserChannel:
|
||||
def set_duc_frequency_mu(self, ftw):
|
||||
"""Set the DUC frequency.
|
||||
|
||||
:param ftw: DUC frequency tuning word (32 bit)
|
||||
:param ftw: DUC frequency tuning word (32-bit)
|
||||
"""
|
||||
self.phaser.write32(PHASER_ADDR_DUC0_F + (self.index << 4), ftw)
|
||||
|
||||
@ -948,7 +946,7 @@ class PhaserChannel:
|
||||
def set_duc_phase_mu(self, pow):
|
||||
"""Set the DUC phase offset.
|
||||
|
||||
:param pow: DUC phase offset word (16 bit)
|
||||
:param pow: DUC phase offset word (16-bit)
|
||||
"""
|
||||
addr = PHASER_ADDR_DUC0_P + (self.index << 4)
|
||||
self.phaser.write8(addr, pow >> 8)
|
||||
@ -970,10 +968,10 @@ class PhaserChannel:
|
||||
This method stages the new NCO frequency, but does not apply it.
|
||||
|
||||
Use of the DAC-NCO requires the DAC mixer and NCO to be enabled. These
|
||||
can be configured via the `dac` configuration dictionary (see
|
||||
`__init__()`).
|
||||
can be configured via the ``dac`` configuration dictionary (see
|
||||
:class:`Phaser`).
|
||||
|
||||
:param ftw: NCO frequency tuning word (32 bit)
|
||||
:param ftw: NCO frequency tuning word (32-bit)
|
||||
"""
|
||||
self.phaser.dac_write(0x15 + (self.index << 1), ftw >> 16)
|
||||
self.phaser.dac_write(0x14 + (self.index << 1), ftw)
|
||||
@ -985,8 +983,8 @@ class PhaserChannel:
|
||||
This method stages the new NCO frequency, but does not apply it.
|
||||
|
||||
Use of the DAC-NCO requires the DAC mixer and NCO to be enabled. These
|
||||
can be configured via the `dac` configuration dictionary (see
|
||||
`__init__()`).
|
||||
can be configured via the ``dac`` configuration dictionary (see
|
||||
:class:`Phaser`).
|
||||
|
||||
:param frequency: NCO frequency in Hz (passband from -400 MHz
|
||||
to 400 MHz, wrapping around at +- 500 MHz)
|
||||
@ -1001,14 +999,13 @@ class PhaserChannel:
|
||||
By default, the new NCO phase applies on completion of the SPI
|
||||
transfer. This also causes a staged NCO frequency to be applied.
|
||||
Different triggers for applying NCO settings may be configured through
|
||||
the `syncsel_mixerxx` fields in the `dac` configuration dictionary (see
|
||||
`__init__()`).
|
||||
the ``syncsel_mixerxx`` fields in the ``dac`` configuration dictionary (see
|
||||
:class:`Phaser`).
|
||||
|
||||
Use of the DAC-NCO requires the DAC mixer and NCO to be enabled. These
|
||||
can be configured via the `dac` configuration dictionary (see
|
||||
`__init__()`).
|
||||
can be configured via the ``dac`` configuration dictionary.
|
||||
|
||||
:param pow: NCO phase offset word (16 bit)
|
||||
:param pow: NCO phase offset word (16-bit)
|
||||
"""
|
||||
self.phaser.dac_write(0x12 + self.index, pow)
|
||||
|
||||
@ -1019,12 +1016,11 @@ class PhaserChannel:
|
||||
By default, the new NCO phase applies on completion of the SPI
|
||||
transfer. This also causes a staged NCO frequency to be applied.
|
||||
Different triggers for applying NCO settings may be configured through
|
||||
the `syncsel_mixerxx` fields in the `dac` configuration dictionary (see
|
||||
`__init__()`).
|
||||
the ``syncsel_mixerxx`` fields in the ``dac`` configuration dictionary (see
|
||||
:class:`Phaser`).
|
||||
|
||||
Use of the DAC-NCO requires the DAC mixer and NCO to be enabled. These
|
||||
can be configured via the `dac` configuration dictionary (see
|
||||
`__init__()`).
|
||||
can be configured via the ``dac`` configuration dictionary.
|
||||
|
||||
:param phase: NCO phase in turns
|
||||
"""
|
||||
@ -1035,7 +1031,7 @@ class PhaserChannel:
|
||||
def set_att_mu(self, data):
|
||||
"""Set channel attenuation.
|
||||
|
||||
:param data: Attenuator data in machine units (8 bit)
|
||||
: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)
|
||||
@ -1082,7 +1078,7 @@ class PhaserChannel:
|
||||
def trf_write(self, data, readback=False):
|
||||
"""Write 32 bits to quadrature upconverter register.
|
||||
|
||||
:param data: Register data (32 bit) containing encoded address
|
||||
: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
|
||||
@ -1114,7 +1110,7 @@ class PhaserChannel:
|
||||
|
||||
:param addr: Register address to read (0 to 7)
|
||||
:param cnt_mux_sel: Report VCO counter min or max frequency
|
||||
:return: Register data (32 bit)
|
||||
:return: Register data (32-bit)
|
||||
"""
|
||||
self.trf_write(0x80000008 | (addr << 28) | (cnt_mux_sel << 27))
|
||||
# single clk pulse with ~LE to start readback
|
||||
@ -1189,13 +1185,13 @@ class PhaserChannel:
|
||||
* :math:`b_0` and :math:`b_1` are the feedforward gains for the two
|
||||
delays
|
||||
|
||||
.. seealso:: :meth:`set_iir`
|
||||
See also :meth:`PhaserChannel.set_iir`.
|
||||
|
||||
:param profile: Profile to set (0 to 3)
|
||||
:param b0: b0 filter coefficient (16 bit signed)
|
||||
:param b1: b1 filter coefficient (16 bit signed)
|
||||
:param a1: a1 filter coefficient (16 bit signed)
|
||||
:param offset: Output offset (16 bit signed)
|
||||
:param b0: b0 filter coefficient (16-bit signed)
|
||||
:param b1: b1 filter coefficient (16-bit signed)
|
||||
:param a1: a1 filter coefficient (16-bit signed)
|
||||
:param offset: Output offset (16-bit signed)
|
||||
"""
|
||||
if (profile < 0) or (profile > 3):
|
||||
raise ValueError("invalid profile index")
|
||||
@ -1240,7 +1236,7 @@ class PhaserChannel:
|
||||
integrator gain limit is infinite. Same sign as ``ki``.
|
||||
:param x_offset: IIR input offset. Used as the negative
|
||||
setpoint when stabilizing to a desired input setpoint. Will
|
||||
be converted to an equivalent output offset and added to y_offset.
|
||||
be converted to an equivalent output offset and added to ``y_offset``.
|
||||
:param y_offset: IIR output offset.
|
||||
"""
|
||||
NORM = 1 << SERVO_COEFF_SHIFT
|
||||
@ -1296,7 +1292,7 @@ class PhaserOscillator:
|
||||
def set_frequency_mu(self, ftw):
|
||||
"""Set Phaser MultiDDS frequency tuning word.
|
||||
|
||||
:param ftw: Frequency tuning word (32 bit)
|
||||
:param ftw: Frequency tuning word (32-bit)
|
||||
"""
|
||||
rtio_output(self.base_addr, ftw)
|
||||
|
||||
@ -1314,8 +1310,8 @@ class PhaserOscillator:
|
||||
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 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)
|
||||
@ -1346,38 +1342,42 @@ class Miqro:
|
||||
|
||||
**Oscillators**
|
||||
|
||||
* There are n_osc = 16 oscillators with oscillator IDs 0..n_osc-1.
|
||||
* There are ``n_osc = 16`` oscillators with oscillator IDs ``0``... ``n_osc-1``.
|
||||
* Each oscillator outputs one tone at any given time
|
||||
|
||||
* I/Q (quadrature, a.k.a. complex) 2x16 bit signed data
|
||||
* I/Q (quadrature, a.k.a. complex) 2x16-bit signed data
|
||||
at tau = 4 ns sample intervals, 250 MS/s, Nyquist 125 MHz, bandwidth 200 MHz
|
||||
(from f = -100..+100 MHz, taking into account the interpolation anti-aliasing
|
||||
filters in subsequent interpolators),
|
||||
* 32 bit frequency (f) resolution (~ 1/16 Hz),
|
||||
* 16 bit unsigned amplitude (a) resolution
|
||||
* 16 bit phase offset (p) resolution
|
||||
* 32-bit frequency (f) resolution (~ 1/16 Hz),
|
||||
* 16-bit unsigned amplitude (a) resolution
|
||||
* 16-bit phase offset (p) resolution
|
||||
|
||||
* The output phase p' of each oscillator at time t (boot/reset/initialization of the
|
||||
device at t=0) is then p' = f*t + p (mod 1 turn) where f and p are the (currently
|
||||
* The output phase ``p'`` of each oscillator at time ``t`` (boot/reset/initialization of the
|
||||
device at ``t=0``) is then ``p' = f*t + p (mod 1 turn)`` where ``f`` and ``p`` are the (currently
|
||||
active) profile frequency and phase offset.
|
||||
* Note: The terms "phase coherent" and "phase tracking" are defined to refer to this
|
||||
choice of oscillator output phase p'. Note that the phase offset p is not relative to
|
||||
(on top of previous phase/profiles/oscillator history).
|
||||
It is "absolute" in the sense that frequency f and phase offset p fully determine
|
||||
oscillator output phase p' at time t. This is unlike typical DDS behavior.
|
||||
|
||||
.. note ::
|
||||
The terms "phase coherent" and "phase tracking" are defined to refer to this
|
||||
choice of oscillator output phase ``p'``. Note that the phase offset ``p`` is not relative to
|
||||
(on top of previous phase/profiles/oscillator history).
|
||||
It is "absolute" in the sense that frequency ``f`` and phase offset ``p`` fully determine
|
||||
oscillator output phase ``p'`` at time ``t``. This is unlike typical DDS behavior.
|
||||
|
||||
* Frequency, phase, and amplitude of each oscillator are configurable by selecting one of
|
||||
n_profile = 32 profiles 0..n_profile-1. This selection is fast and can be done for
|
||||
each pulse. The phase coherence defined above is guaranteed for each
|
||||
``n_profiles = 32`` profiles ``0``... ``n_profile-1``. This selection is fast and can be
|
||||
done for each pulse. The phase coherence defined above is guaranteed for each
|
||||
profile individually.
|
||||
* Note: one profile per oscillator (usually profile index 0) should be reserved
|
||||
for the NOP (no operation, identity) profile, usually with zero amplitude.
|
||||
* Data for each profile for each oscillator can be configured
|
||||
individually. Storing profile data should be considered "expensive".
|
||||
* Note: The annotation that some operation is "expensive" does not mean it is
|
||||
impossible, just that it may take a significant amount of time and
|
||||
resources to execute such that it may be impractical when used often or
|
||||
during fast pulse sequences. They are intended for use in calibration and
|
||||
initialization.
|
||||
|
||||
.. note::
|
||||
To refer to an operation as "expensive" does not mean it is impossible,
|
||||
merely that it may take a significant amount of time and resources to
|
||||
execute, such that it may be impractical when used often or during fast
|
||||
pulse sequences. They are intended for use in calibration and initialization.
|
||||
|
||||
**Summation**
|
||||
|
||||
@ -1394,18 +1394,18 @@ class Miqro:
|
||||
the RF output.
|
||||
* Selected profiles become active simultaneously (on the same output sample) when
|
||||
triggering the shaper with the first shaper output sample.
|
||||
* The shaper reads (replays) window samples from a memory of size n_window = 1 << 10.
|
||||
* The shaper reads (replays) window samples from a memory of size ``n_window = 1 << 10``.
|
||||
* The window memory can be segmented by choosing different start indices
|
||||
to support different windows.
|
||||
* Each window memory segment starts with a header determining segment
|
||||
length and interpolation parameters.
|
||||
* The window samples are interpolated by a factor (rate change) between 1 and
|
||||
r = 1 << 12.
|
||||
``r = 1 << 12``.
|
||||
* The interpolation order is constant, linear, quadratic, or cubic. This
|
||||
corresponds to interpolation modes from rectangular window (1st order CIC)
|
||||
or zero order hold) to Parzen window (4th order CIC or cubic spline).
|
||||
* This results in support for single shot pulse lengths (envelope support) between
|
||||
tau and a bit more than r * n_window * tau = (1 << 12 + 10) tau ~ 17 ms.
|
||||
tau and a bit more than ``r * n_window * tau = (1 << 12 + 10) tau ~ 17 ms``.
|
||||
* Windows can be configured to be head-less and/or tail-less, meaning, they
|
||||
do not feed zero-amplitude samples into the shaper before and after
|
||||
each window respectively. This is used to implement pulses with arbitrary
|
||||
@ -1413,18 +1413,18 @@ class Miqro:
|
||||
|
||||
**Overall properties**
|
||||
|
||||
* The DAC may upconvert the signal by applying a frequency offset f1 with
|
||||
phase p1.
|
||||
* The DAC may upconvert the signal by applying a frequency offset ``f1`` with
|
||||
phase ``p1``.
|
||||
* In the Upconverter Phaser variant, the analog quadrature upconverter
|
||||
applies another frequency of f2 and phase p2.
|
||||
applies another frequency of ``f2`` and phase ``p2``.
|
||||
* The resulting phase of the signal from one oscillator at the SMA output is
|
||||
(f + f1 + f2)*t + p + s(t - t0) + p1 + p2 (mod 1 turn)
|
||||
where s(t - t0) is the phase of the interpolated
|
||||
shaper output, and t0 is the trigger time (fiducial of the shaper).
|
||||
``(f + f1 + f2)*t + p + s(t - t0) + p1 + p2 (mod 1 turn)``
|
||||
where ``s(t - t0)`` is the phase of the interpolated
|
||||
shaper output, and ``t0`` is the trigger time (fiducial of the shaper).
|
||||
Unsurprisingly the frequency is the derivative of the phase.
|
||||
* Group delays between pulse parameter updates are matched across oscillators,
|
||||
shapers, and channels.
|
||||
* The minimum time to change profiles and phase offsets is ~128 ns (estimate, TBC).
|
||||
* The minimum time to change profiles and phase offsets is ``~128 ns`` (estimate, TBC).
|
||||
This is the minimum pulse interval.
|
||||
The sustained pulse rate of the RTIO PHY/Fastlink is one pulse per Fastlink frame
|
||||
(may be increased, TBC).
|
||||
@ -1455,9 +1455,9 @@ class Miqro:
|
||||
|
||||
:param oscillator: Oscillator index (0 to 15)
|
||||
:param profile: Profile index (0 to 31)
|
||||
:param ftw: Frequency tuning word (32 bit signed integer on a 250 MHz clock)
|
||||
:param asf: Amplitude scale factor (16 bit unsigned integer)
|
||||
:param pow_: Phase offset word (16 bit integer)
|
||||
:param ftw: Frequency tuning word (32-bit signed integer on a 250 MHz clock)
|
||||
:param asf: Amplitude scale factor (16-bit unsigned integer)
|
||||
:param pow_: Phase offset word (16-bit integer)
|
||||
"""
|
||||
if oscillator >= 16:
|
||||
raise ValueError("invalid oscillator index")
|
||||
@ -1481,7 +1481,7 @@ class Miqro:
|
||||
:param amplitude: Amplitude in units of full scale (0. to 1.)
|
||||
:param phase: Phase in turns. See :class:`Miqro` for a definition of
|
||||
phase in this context.
|
||||
:return: The quantized 32 bit frequency tuning word
|
||||
:return: The quantized 32-bit frequency tuning word
|
||||
"""
|
||||
ftw = int32(round(frequency*((1 << 30)/(62.5*MHz))))
|
||||
asf = int32(round(amplitude*0xffff))
|
||||
@ -1493,7 +1493,7 @@ class Miqro:
|
||||
|
||||
@kernel
|
||||
def set_window_mu(self, start, iq, rate=1, shift=0, order=3, head=1, tail=1):
|
||||
"""Store a window segment (machine units)
|
||||
"""Store a window segment (machine units).
|
||||
|
||||
:param start: Window start address (0 to 0x3ff)
|
||||
:param iq: List of IQ window samples. Each window sample is an integer
|
||||
@ -1540,7 +1540,7 @@ class Miqro:
|
||||
|
||||
@kernel
|
||||
def set_window(self, start, iq, period=4*ns, order=3, head=1, tail=1):
|
||||
"""Store a window segment
|
||||
"""Store a window segment.
|
||||
|
||||
:param start: Window start address (0 to 0x3ff)
|
||||
:param iq: List of IQ window samples. Each window sample is a pair of
|
||||
@ -1577,7 +1577,7 @@ class Miqro:
|
||||
|
||||
@kernel
|
||||
def encode(self, window, profiles, data):
|
||||
"""Encode window and profile selection
|
||||
"""Encode window and profile selection.
|
||||
|
||||
:param window: Window start address (0 to 0x3ff)
|
||||
:param profiles: List of profile indices for the oscillators. Maximum
|
||||
|
@ -25,7 +25,7 @@ def rtio_input_data(channel: TInt32) -> TInt32:
|
||||
@syscall(flags={"nowrite"})
|
||||
def rtio_input_timestamped_data(timeout_mu: TInt64,
|
||||
channel: TInt32) -> TTuple([TInt64, TInt32]):
|
||||
"""Wait for an input event up to timeout_mu on the given channel, and
|
||||
"""Wait for an input event up to ``timeout_mu`` on the given channel, and
|
||||
return a tuple of timestamp and attached data, or (-1, 0) if the timeout is
|
||||
reached."""
|
||||
raise NotImplementedError("syscall not simulated")
|
||||
|
@ -16,13 +16,13 @@ SPI_CS_PGIA = 1 # separate SPI bus, CS used as RCLK
|
||||
|
||||
@portable
|
||||
def adc_mu_to_volt(data, gain=0, corrected_fs=True):
|
||||
"""Convert ADC data in machine units to Volts.
|
||||
"""Convert ADC data in machine units to volts.
|
||||
|
||||
:param data: 16 bit signed ADC word
|
||||
:param data: 16-bit signed ADC word
|
||||
:param gain: PGIA gain setting (0: 1, ..., 3: 1000)
|
||||
:param corrected_fs: use corrected ADC FS reference.
|
||||
Should be True for Samplers' revisions after v2.1. False for v2.1 and earlier.
|
||||
:return: Voltage in Volts
|
||||
Should be ``True`` for Sampler revisions after v2.1. ``False`` for v2.1 and earlier.
|
||||
:return: Voltage in volts
|
||||
"""
|
||||
if gain == 0:
|
||||
volt_per_lsb = 20.48 / (1 << 16) if corrected_fs else 20. / (1 << 16)
|
||||
@ -40,7 +40,7 @@ def adc_mu_to_volt(data, gain=0, corrected_fs=True):
|
||||
class Sampler:
|
||||
"""Sampler ADC.
|
||||
|
||||
Controls the LTC2320-16 8 channel 16 bit ADC with SPI interface and
|
||||
Controls the LTC2320-16 8-channel 16-bit ADC with SPI interface and
|
||||
the switchable gain instrumentation amplifiers.
|
||||
|
||||
:param spi_adc_device: ADC SPI bus device name
|
||||
@ -119,12 +119,12 @@ class Sampler:
|
||||
Perform a conversion and transfer the samples.
|
||||
|
||||
This assumes that the input FIFO of the ADC SPI RTIO channel is deep
|
||||
enough to buffer the samples (half the length of `data` deep).
|
||||
enough to buffer the samples (half the length of ``data`` deep).
|
||||
If it is not, there will be RTIO input overflows.
|
||||
|
||||
:param data: List of data samples to fill. Must have even length.
|
||||
Samples are always read from the last channel (channel 7) down.
|
||||
The `data` list will always be filled with the last item
|
||||
The ``data`` list will always be filled with the last item
|
||||
holding to the sample from channel 7.
|
||||
"""
|
||||
self.cnv.pulse(30*ns) # t_CNVH
|
||||
@ -142,7 +142,7 @@ class Sampler:
|
||||
def sample(self, data):
|
||||
"""Acquire a set of samples.
|
||||
|
||||
.. seealso:: :meth:`sample_mu`
|
||||
See also :meth:`Sampler.sample_mu`.
|
||||
|
||||
:param data: List of floating point data samples to fill.
|
||||
"""
|
||||
|
@ -16,8 +16,8 @@ def shuttler_volt_to_mu(volt):
|
||||
class Config:
|
||||
"""Shuttler configuration registers interface.
|
||||
|
||||
The configuration registers control waveform phase auto-clear, and pre-DAC
|
||||
gain & offset values for calibration with ADC on the Shuttler AFE card.
|
||||
The configuration registers control waveform phase auto-clear, pre-DAC
|
||||
gain and offset values for calibration with ADC on the Shuttler AFE card.
|
||||
|
||||
To find the calibrated DAC code, the Shuttler Core first multiplies the
|
||||
output data with pre-DAC gain, then adds the offset.
|
||||
@ -84,8 +84,7 @@ class Config:
|
||||
def set_offset(self, channel, offset):
|
||||
"""Set the 16-bits pre-DAC offset register of a Shuttler Core channel.
|
||||
|
||||
.. seealso::
|
||||
:meth:`shuttler_volt_to_mu`
|
||||
See also :meth:`shuttler_volt_to_mu`.
|
||||
|
||||
:param channel: Shuttler Core channel to be configured.
|
||||
:param offset: Shuttler Core channel offset.
|
||||
@ -114,13 +113,13 @@ class DCBias:
|
||||
.. math::
|
||||
w(t) = a(t) + b(t) * cos(c(t))
|
||||
|
||||
And `t` corresponds to time in seconds.
|
||||
and `t` corresponds to time in seconds.
|
||||
This class controls the cubic spline `a(t)`, in which
|
||||
|
||||
.. math::
|
||||
a(t) = p_0 + p_1t + \\frac{p_2t^2}{2} + \\frac{p_3t^3}{6}
|
||||
|
||||
And `a(t)` is in Volt.
|
||||
and `a(t)` is measured in volts.
|
||||
|
||||
:param channel: RTIO channel number of this DC-bias spline interface.
|
||||
:param core_device: Core device name.
|
||||
@ -137,7 +136,7 @@ class DCBias:
|
||||
"""Set the DC-bias spline waveform.
|
||||
|
||||
Given `a(t)` as defined in :class:`DCBias`, the coefficients should be
|
||||
configured by the following formulae.
|
||||
configured by the following formulae:
|
||||
|
||||
.. math::
|
||||
T &= 8*10^{-9}
|
||||
@ -154,8 +153,10 @@ class DCBias:
|
||||
and 48 bits in width respectively. See :meth:`shuttler_volt_to_mu` for
|
||||
machine unit conversion.
|
||||
|
||||
Note: The waveform is not updated to the Shuttler Core until
|
||||
triggered. See :class:`Trigger` for the update triggering mechanism.
|
||||
.. note::
|
||||
The waveform is not updated to the Shuttler Core until
|
||||
triggered. See :class:`Trigger` for the update triggering
|
||||
mechanism.
|
||||
|
||||
:param a0: The :math:`a_0` coefficient in machine unit.
|
||||
:param a1: The :math:`a_1` coefficient in machine unit.
|
||||
@ -189,7 +190,7 @@ class DDS:
|
||||
.. math::
|
||||
w(t) = a(t) + b(t) * cos(c(t))
|
||||
|
||||
And `t` corresponds to time in seconds.
|
||||
and `t` corresponds to time in seconds.
|
||||
This class controls the cubic spline `b(t)` and quadratic spline `c(t)`,
|
||||
in which
|
||||
|
||||
@ -198,7 +199,7 @@ class DDS:
|
||||
|
||||
c(t) &= r_0 + r_1t + \\frac{r_2t^2}{2}
|
||||
|
||||
And `b(t)` is in Volt, `c(t)` is in number of turns. Note that `b(t)`
|
||||
`b(t)` is in volts, `c(t)` is in number of turns. Note that `b(t)`
|
||||
contributes to a constant gain of :math:`g=1.64676`.
|
||||
|
||||
:param channel: RTIO channel number of this DC-bias spline interface.
|
||||
@ -244,13 +245,13 @@ class DDS:
|
||||
Note: The waveform is not updated to the Shuttler Core until
|
||||
triggered. See :class:`Trigger` for the update triggering mechanism.
|
||||
|
||||
:param b0: The :math:`b_0` coefficient in machine unit.
|
||||
:param b1: The :math:`b_1` coefficient in machine unit.
|
||||
:param b2: The :math:`b_2` coefficient in machine unit.
|
||||
:param b3: The :math:`b_3` coefficient in machine unit.
|
||||
:param c0: The :math:`c_0` coefficient in machine unit.
|
||||
:param c1: The :math:`c_1` coefficient in machine unit.
|
||||
:param c2: The :math:`c_2` coefficient in machine unit.
|
||||
:param b0: The :math:`b_0` coefficient in machine units.
|
||||
:param b1: The :math:`b_1` coefficient in machine units.
|
||||
:param b2: The :math:`b_2` coefficient in machine units.
|
||||
:param b3: The :math:`b_3` coefficient in machine units.
|
||||
:param c0: The :math:`c_0` coefficient in machine units.
|
||||
:param c1: The :math:`c_1` coefficient in machine units.
|
||||
:param c2: The :math:`c_2` coefficient in machine units.
|
||||
"""
|
||||
coef_words = [
|
||||
b0,
|
||||
@ -292,8 +293,8 @@ class Trigger:
|
||||
"""Triggers coefficient update of (a) Shuttler Core channel(s).
|
||||
|
||||
Each bit corresponds to a Shuttler waveform generator core. Setting
|
||||
`trig_out` bits commits the pending coefficient update (from
|
||||
`set_waveform` in :class:`DCBias` and :class:`DDS`) to the Shuttler Core
|
||||
``trig_out`` bits commits the pending coefficient update (from
|
||||
``set_waveform`` in :class:`DCBias` and :class:`DDS`) to the Shuttler Core
|
||||
synchronously.
|
||||
|
||||
:param trig_out: Coefficient update trigger bits. The MSB corresponds
|
||||
@ -336,8 +337,8 @@ _AD4115_REG_SETUPCON0 = 0x20
|
||||
class Relay:
|
||||
"""Shuttler AFE relay switches.
|
||||
|
||||
It controls the AFE relay switches and the LEDs. Switch on the relay to
|
||||
enable AFE output; And off to disable the output. The LEDs indicates the
|
||||
This class controls the AFE relay switches and the LEDs. Switch the relay on to
|
||||
enable AFE output; off to disable the output. The LEDs indicate the
|
||||
relay status.
|
||||
|
||||
.. note::
|
||||
@ -357,7 +358,7 @@ class Relay:
|
||||
def init(self):
|
||||
"""Initialize SPI device.
|
||||
|
||||
Configures the SPI bus to 16-bits, write-only, simultaneous relay
|
||||
Configures the SPI bus to 16 bits, write-only, simultaneous relay
|
||||
switches and LED control.
|
||||
"""
|
||||
self.bus.set_config_mu(
|
||||
@ -365,10 +366,10 @@ class Relay:
|
||||
|
||||
@kernel
|
||||
def enable(self, en: TInt32):
|
||||
"""Enable/Disable relay switches of corresponding channels.
|
||||
"""Enable/disable relay switches of corresponding channels.
|
||||
|
||||
Each bit corresponds to the relay switch of a channel. Asserting a bit
|
||||
turns on the corresponding relay switch; Deasserting the same bit
|
||||
turns on the corresponding relay switch; deasserting the same bit
|
||||
turns off the switch instead.
|
||||
|
||||
:param en: Switch enable bits. The MSB corresponds to Channel 15, LSB
|
||||
@ -403,12 +404,12 @@ class ADC:
|
||||
def reset(self):
|
||||
"""AD4115 reset procedure.
|
||||
|
||||
This performs a write operation of 96 serial clock cycles with DIN
|
||||
held at high. It resets the entire device, including the register
|
||||
Performs a write operation of 96 serial clock cycles with DIN
|
||||
held at high. This resets the entire device, including the register
|
||||
contents.
|
||||
|
||||
.. note::
|
||||
The datasheet only requires 64 cycles, but reasserting `CS_n` right
|
||||
The datasheet only requires 64 cycles, but reasserting ``CS_n`` right
|
||||
after the transfer appears to interrupt the start-up sequence.
|
||||
"""
|
||||
self.bus.set_config_mu(ADC_SPI_CONFIG, 32, SPIT_ADC_WR, CS_ADC)
|
||||
@ -420,7 +421,7 @@ class ADC:
|
||||
|
||||
@kernel
|
||||
def read8(self, addr: TInt32) -> TInt32:
|
||||
"""Read from 8 bit register.
|
||||
"""Read from 8-bit register.
|
||||
|
||||
:param addr: Register address.
|
||||
:return: Read-back register content.
|
||||
@ -433,7 +434,7 @@ class ADC:
|
||||
|
||||
@kernel
|
||||
def read16(self, addr: TInt32) -> TInt32:
|
||||
"""Read from 16 bit register.
|
||||
"""Read from 16-bit register.
|
||||
|
||||
:param addr: Register address.
|
||||
:return: Read-back register content.
|
||||
@ -446,7 +447,7 @@ class ADC:
|
||||
|
||||
@kernel
|
||||
def read24(self, addr: TInt32) -> TInt32:
|
||||
"""Read from 24 bit register.
|
||||
"""Read from 24-bit register.
|
||||
|
||||
:param addr: Register address.
|
||||
:return: Read-back register content.
|
||||
@ -459,7 +460,7 @@ class ADC:
|
||||
|
||||
@kernel
|
||||
def write8(self, addr: TInt32, data: TInt32):
|
||||
"""Write to 8 bit register.
|
||||
"""Write to 8-bit register.
|
||||
|
||||
:param addr: Register address.
|
||||
:param data: Data to be written.
|
||||
@ -470,7 +471,7 @@ class ADC:
|
||||
|
||||
@kernel
|
||||
def write16(self, addr: TInt32, data: TInt32):
|
||||
"""Write to 16 bit register.
|
||||
"""Write to 16-bit register.
|
||||
|
||||
:param addr: Register address.
|
||||
:param data: Data to be written.
|
||||
@ -481,7 +482,7 @@ class ADC:
|
||||
|
||||
@kernel
|
||||
def write24(self, addr: TInt32, data: TInt32):
|
||||
"""Write to 24 bit register.
|
||||
"""Write to 24-bit register.
|
||||
|
||||
:param addr: Register address.
|
||||
:param data: Data to be written.
|
||||
@ -494,11 +495,11 @@ class ADC:
|
||||
def read_ch(self, channel: TInt32) -> TFloat:
|
||||
"""Sample a Shuttler channel on the AFE.
|
||||
|
||||
It performs a single conversion using profile 0 and setup 0, on the
|
||||
selected channel. The sample is then recovered and converted to volt.
|
||||
Performs a single conversion using profile 0 and setup 0 on the
|
||||
selected channel. The sample is then recovered and converted to volts.
|
||||
|
||||
:param channel: Shuttler channel to be sampled.
|
||||
:return: Voltage sample in volt.
|
||||
:return: Voltage sample in volts.
|
||||
"""
|
||||
# Always configure Profile 0 for single conversion
|
||||
self.write16(_AD4115_REG_CH0, 0x8000 | ((channel * 2 + 1) << 4))
|
||||
@ -519,7 +520,7 @@ class ADC:
|
||||
|
||||
@kernel
|
||||
def standby(self):
|
||||
"""Place the ADC in standby mode and disables power down the clock.
|
||||
"""Place the ADC in standby mode and disable power down the clock.
|
||||
|
||||
The ADC can be returned to single conversion mode by calling
|
||||
:meth:`single_conversion`.
|
||||
@ -536,13 +537,7 @@ class ADC:
|
||||
.. note::
|
||||
The AD4115 datasheet suggests placing the ADC in standby mode
|
||||
before power-down. This is to prevent accidental entry into the
|
||||
power-down mode.
|
||||
|
||||
.. seealso::
|
||||
:meth:`standby`
|
||||
|
||||
:meth:`power_up`
|
||||
|
||||
power-down mode. See also :meth:`standby` and :meth:`power_up`.
|
||||
"""
|
||||
self.write16(_AD4115_REG_ADCMODE, 0x8030)
|
||||
|
||||
@ -552,8 +547,7 @@ class ADC:
|
||||
|
||||
The ADC should be in power-down mode before calling this method.
|
||||
|
||||
.. seealso::
|
||||
:meth:`power_down`
|
||||
See also :meth:`power_down`.
|
||||
"""
|
||||
self.reset()
|
||||
# Although the datasheet claims 500 us reset wait time, only waiting
|
||||
@ -564,22 +558,18 @@ class ADC:
|
||||
def calibrate(self, volts, trigger, config, samples=[-5.0, 0.0, 5.0]):
|
||||
"""Calibrate the Shuttler waveform generator using the ADC on the AFE.
|
||||
|
||||
It finds the average slope rate and average offset by samples, and
|
||||
compensate by writing the pre-DAC gain and offset registers in the
|
||||
Finds the average slope rate and average offset by samples, and
|
||||
compensates by writing the pre-DAC gain and offset registers in the
|
||||
configuration registers.
|
||||
|
||||
.. note::
|
||||
If the pre-calibration slope rate < 1, the calibration procedure
|
||||
will introduce a pre-DAC gain compensation. However, this may
|
||||
saturate the pre-DAC voltage code. (See :class:`Config` notes).
|
||||
If the pre-calibration slope rate is less than 1, the calibration
|
||||
procedure will introduce a pre-DAC gain compensation. However, this
|
||||
may saturate the pre-DAC voltage code (see :class:`Config` notes).
|
||||
Shuttler cannot cover the entire +/- 10 V range in this case.
|
||||
See also :meth:`Config.set_gain` and :meth:`Config.set_offset`.
|
||||
|
||||
.. seealso::
|
||||
:meth:`Config.set_gain`
|
||||
|
||||
:meth:`Config.set_offset`
|
||||
|
||||
:param volts: A list of all 16 cubic DC-bias spline.
|
||||
:param volts: A list of all 16 cubic DC-bias splines.
|
||||
(See :class:`DCBias`)
|
||||
:param trigger: The Shuttler spline coefficient update trigger.
|
||||
:param config: The Shuttler Core configuration registers.
|
||||
|
@ -4,7 +4,7 @@ Driver for generic SPI on RTIO.
|
||||
This ARTIQ coredevice driver corresponds to the "new" MiSoC SPI core (v2).
|
||||
|
||||
Output event replacement is not supported and issuing commands at the same
|
||||
time is an error.
|
||||
time results in collision errors.
|
||||
"""
|
||||
|
||||
from artiq.language.core import syscall, kernel, portable, delay_mu
|
||||
@ -51,7 +51,7 @@ class SPIMaster:
|
||||
event (``SPI_INPUT`` set), then :meth:`read` the ``data``.
|
||||
* If ``SPI_END`` was not set, repeat the transfer sequence.
|
||||
|
||||
A **transaction** consists of one or more **transfers**. The chip select
|
||||
A *transaction* consists of one or more *transfers*. The chip select
|
||||
pattern is asserted for the entire length of the transaction. All but the
|
||||
last transfer are submitted with ``SPI_END`` cleared in the configuration
|
||||
register.
|
||||
@ -138,10 +138,10 @@ class SPIMaster:
|
||||
* :const:`SPI_LSB_FIRST`: LSB is the first bit on the wire (reset=0)
|
||||
* :const:`SPI_HALF_DUPLEX`: 3-wire SPI, in/out on ``mosi`` (reset=0)
|
||||
|
||||
:param flags: A bit map of `SPI_*` flags.
|
||||
:param flags: A bit map of :const:`SPI_*` flags.
|
||||
:param length: Number of bits to write during the next transfer.
|
||||
(reset=1)
|
||||
:param freq: Desired SPI clock frequency. (reset=f_rtio/2)
|
||||
:param freq: Desired SPI clock frequency. (reset= ``f_rtio/2``)
|
||||
:param cs: Bit pattern of chip selects to assert.
|
||||
Or number of the chip select to assert if ``cs`` is decoded
|
||||
downstream. (reset=0)
|
||||
@ -152,16 +152,15 @@ class SPIMaster:
|
||||
def set_config_mu(self, flags, length, div, cs):
|
||||
"""Set the ``config`` register (in SPI bus machine units).
|
||||
|
||||
.. seealso:: :meth:`set_config`
|
||||
See also :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.
|
||||
clock by to generate the SPI clock; ``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. (minimum=2, reset=2)
|
||||
:param cs: Bit pattern of chip selects to assert.
|
||||
Or number of the chip select to assert if ``cs`` is decoded
|
||||
downstream. (reset=0)
|
||||
@ -188,7 +187,7 @@ class SPIMaster:
|
||||
experiments and are known.
|
||||
|
||||
This method is portable and can also be called from e.g.
|
||||
:meth:`__init__`.
|
||||
``__init__``.
|
||||
|
||||
.. warning:: If this method is called while recording a DMA
|
||||
sequence, the playback of the sequence will not update the
|
||||
@ -208,7 +207,7 @@ class SPIMaster:
|
||||
* 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
|
||||
: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
|
||||
|
@ -24,7 +24,7 @@ def y_mu_to_full_scale(y):
|
||||
|
||||
@portable
|
||||
def adc_mu_to_volts(x, gain, corrected_fs=True):
|
||||
"""Convert servo ADC data from machine units to Volt."""
|
||||
"""Convert servo ADC data from machine units to volts."""
|
||||
val = (x >> 1) & 0xffff
|
||||
mask = 1 << 15
|
||||
val = -(val & mask) + (val & ~mask)
|
||||
@ -155,7 +155,7 @@ class SUServo:
|
||||
This method advances the timeline by one servo memory access.
|
||||
It does not support RTIO event replacement.
|
||||
|
||||
:param enable (int): Enable servo operation. Enabling starts servo
|
||||
:param int enable: Enable servo operation. Enabling starts servo
|
||||
iterations beginning with the ADC sampling stage. The first DDS
|
||||
update will happen about two servo cycles (~2.3 µs) after enabling
|
||||
the servo. The delay is deterministic.
|
||||
@ -198,7 +198,7 @@ class SUServo:
|
||||
consistent and valid data, stop the servo before using this method.
|
||||
|
||||
:param adc: ADC channel number (0-7)
|
||||
:return: 17 bit signed X0
|
||||
:return: 17-bit signed X0
|
||||
"""
|
||||
# State memory entries are 25 bits. Due to the pre-adder dynamic
|
||||
# range, X0/X1/OFFSET are only 24 bits. Finally, the RTIO interface
|
||||
@ -288,12 +288,12 @@ class Channel:
|
||||
def set_dds_mu(self, profile, ftw, offs, pow_=0):
|
||||
"""Set profile DDS coefficients in machine units.
|
||||
|
||||
.. seealso:: :meth:`set_amplitude`
|
||||
See also :meth:`Channel.set_dds`.
|
||||
|
||||
:param profile: Profile number (0-31)
|
||||
:param ftw: Frequency tuning word (32 bit unsigned)
|
||||
:param offs: IIR offset (17 bit signed)
|
||||
:param pow_: Phase offset word (16 bit)
|
||||
:param ftw: Frequency tuning word (32-bit unsigned)
|
||||
:param offs: IIR offset (17-bit signed)
|
||||
:param pow_: Phase offset word (16-bit)
|
||||
"""
|
||||
base = (self.servo_channel << 8) | (profile << 3)
|
||||
self.servo.write(base + 0, ftw >> 16)
|
||||
@ -327,7 +327,7 @@ class Channel:
|
||||
See :meth:`set_dds_mu` for setting the complete DDS profile.
|
||||
|
||||
:param profile: Profile number (0-31)
|
||||
:param offs: IIR offset (17 bit signed)
|
||||
:param offs: IIR offset (17-bit signed)
|
||||
"""
|
||||
base = (self.servo_channel << 8) | (profile << 3)
|
||||
self.servo.write(base + 4, offs)
|
||||
@ -375,15 +375,15 @@ class Channel:
|
||||
* :math:`b_0` and :math:`b_1` are the feedforward gains for the two
|
||||
delays
|
||||
|
||||
.. seealso:: :meth:`set_iir`
|
||||
See also :meth:`Channel.set_iir`.
|
||||
|
||||
:param profile: Profile number (0-31)
|
||||
:param adc: ADC channel to take IIR input from (0-7)
|
||||
:param a1: 18 bit signed A1 coefficient (Y1 coefficient,
|
||||
:param a1: 18-bit signed A1 coefficient (Y1 coefficient,
|
||||
feedback, integrator gain)
|
||||
:param b0: 18 bit signed B0 coefficient (recent,
|
||||
:param b0: 18-bit signed B0 coefficient (recent,
|
||||
X0 coefficient, feed forward, proportional gain)
|
||||
:param b1: 18 bit signed B1 coefficient (old,
|
||||
:param b1: 18-bit signed B1 coefficient (old,
|
||||
X1 coefficient, feed forward, proportional gain)
|
||||
:param dly: IIR update suppression time. In units of IIR cycles
|
||||
(~1.2 µs, 0-255).
|
||||
@ -499,7 +499,7 @@ class Channel:
|
||||
consistent and valid data, stop the servo before using this method.
|
||||
|
||||
:param profile: Profile number (0-31)
|
||||
:return: 17 bit unsigned Y0
|
||||
:return: 17-bit unsigned Y0
|
||||
"""
|
||||
return self.servo.read(STATE_SEL | (self.servo_channel << 5) | profile)
|
||||
|
||||
@ -535,7 +535,7 @@ class Channel:
|
||||
This method advances the timeline by one servo memory access.
|
||||
|
||||
:param profile: Profile number (0-31)
|
||||
:param y: 17 bit unsigned Y0
|
||||
:param y: 17-bit unsigned Y0
|
||||
"""
|
||||
# State memory is 25 bits wide and signed.
|
||||
# Reads interact with the 18 MSBs (coefficient memory width)
|
||||
|
@ -27,7 +27,7 @@ class TTLOut:
|
||||
|
||||
This should be used with output-only channels.
|
||||
|
||||
:param channel: channel number
|
||||
:param channel: Channel number
|
||||
"""
|
||||
kernel_invariants = {"core", "channel", "target_o"}
|
||||
|
||||
@ -109,7 +109,7 @@ class TTLInOut:
|
||||
API is active (e.g. the gate is open, or the input events have not been
|
||||
fully read out), another API must not be used simultaneously.
|
||||
|
||||
:param channel: channel number
|
||||
:param channel: Channel number
|
||||
"""
|
||||
kernel_invariants = {"core", "channel", "gate_latency_mu",
|
||||
"target_o", "target_oe", "target_sens", "target_sample"}
|
||||
@ -145,7 +145,7 @@ class TTLInOut:
|
||||
"""Set the direction to output at the current position of the time
|
||||
cursor.
|
||||
|
||||
There must be a delay of at least one RTIO clock cycle before any
|
||||
A delay of at least one RTIO clock cycle is necessary before any
|
||||
other command can be issued.
|
||||
|
||||
This method only configures the direction at the FPGA. When using
|
||||
@ -158,7 +158,7 @@ class TTLInOut:
|
||||
"""Set the direction to input at the current position of the time
|
||||
cursor.
|
||||
|
||||
There must be a delay of at least one RTIO clock cycle before any
|
||||
A delay of at least one RTIO clock cycle is necessary before any
|
||||
other command can be issued.
|
||||
|
||||
This method only configures the direction at the FPGA. When using
|
||||
@ -326,17 +326,18 @@ class TTLInOut:
|
||||
:return: The number of events before the timeout elapsed (0 if none
|
||||
observed).
|
||||
|
||||
Examples:
|
||||
**Examples:**
|
||||
|
||||
To count events on channel ``ttl_input``, up to the current timeline
|
||||
position::
|
||||
position: ::
|
||||
|
||||
ttl_input.count(now_mu())
|
||||
|
||||
If other events are scheduled between the end of the input gate
|
||||
period and when the number of events is counted, using ``now_mu()``
|
||||
as timeout consumes an unnecessary amount of timeline slack. In
|
||||
such cases, it can be beneficial to pass a more precise timestamp,
|
||||
for example::
|
||||
period and when the number of events is counted, using
|
||||
:meth:`~artiq.language.core.now_mu()` as timeout consumes an
|
||||
unnecessary amount of timeline slack. In such cases, it can be
|
||||
beneficial to pass a more precise timestamp, for example: ::
|
||||
|
||||
gate_end_mu = ttl_input.gate_rising(100 * us)
|
||||
|
||||
@ -350,7 +351,7 @@ class TTLInOut:
|
||||
num_rising_edges = ttl_input.count(gate_end_mu)
|
||||
|
||||
The ``gate_*()`` family of methods return the cursor at the end
|
||||
of the window, allowing this to be expressed in a compact fashion::
|
||||
of the window, allowing this to be expressed in a compact fashion: ::
|
||||
|
||||
ttl_input.count(ttl_input.gate_rising(100 * us))
|
||||
"""
|
||||
@ -441,7 +442,7 @@ class TTLInOut:
|
||||
was being watched.
|
||||
|
||||
The time cursor is not modified by this function. This function
|
||||
always makes the slack negative.
|
||||
always results in negative slack.
|
||||
"""
|
||||
rtio_output(self.target_sens, 0)
|
||||
success = True
|
||||
|
@ -130,7 +130,7 @@ class CPLD:
|
||||
:param spi_device: SPI bus device name
|
||||
:param io_update_device: IO update RTIO TTLOut channel name
|
||||
:param dds_reset_device: DDS reset RTIO TTLOut channel name
|
||||
:param sync_device: AD9910 SYNC_IN RTIO TTLClockGen channel name
|
||||
:param sync_device: AD9910 ``SYNC_IN`` RTIO TTLClockGen channel name
|
||||
:param refclk: Reference clock (SMA, MMCX or on-board 100 MHz oscillator)
|
||||
frequency in Hz
|
||||
:param clk_sel: Reference clock selection. For hardware revision >= 1.3
|
||||
@ -143,9 +143,9 @@ class CPLD:
|
||||
1: divide-by-1; 2: divide-by-2; 3: divide-by-4.
|
||||
On Urukul boards with CPLD gateware before v1.3.1 only the default
|
||||
(0, i.e. variant dependent divider) is valid.
|
||||
:param sync_sel: SYNC (multi-chip synchronisation) signal source selection.
|
||||
0 corresponds to SYNC_IN being supplied by the FPGA via the EEM
|
||||
connector. 1 corresponds to SYNC_OUT from DDS0 being distributed to the
|
||||
:param sync_sel: ``SYNC`` (multi-chip synchronisation) signal source selection.
|
||||
0 corresponds to ``SYNC_IN`` being supplied by the FPGA via the EEM
|
||||
connector. 1 corresponds to ``SYNC_OUT`` from DDS0 being distributed to the
|
||||
other chips.
|
||||
:param rf_sw: Initial CPLD RF switch register setting (default: 0x0).
|
||||
Knowledge of this state is not transferred between experiments.
|
||||
@ -153,8 +153,8 @@ class CPLD:
|
||||
0x00000000). See also :meth:`get_att_mu` which retrieves the hardware
|
||||
state without side effects. Knowledge of this state is not transferred
|
||||
between experiments.
|
||||
:param sync_div: SYNC_IN generator divider. The ratio between the coarse
|
||||
RTIO frequency and the SYNC_IN generator frequency (default: 2 if
|
||||
:param sync_div: ``SYNC_IN`` generator divider. The ratio between the coarse
|
||||
RTIO frequency and the ``SYNC_IN`` generator frequency (default: 2 if
|
||||
`sync_device` was specified).
|
||||
:param core_device: Core device name
|
||||
|
||||
@ -204,7 +204,7 @@ class CPLD:
|
||||
|
||||
See :func:`urukul_cfg` for possible flags.
|
||||
|
||||
:param cfg: 24 bit data to be written. Will be stored at
|
||||
:param cfg: 24-bit data to be written. Will be stored at
|
||||
:attr:`cfg_reg`.
|
||||
"""
|
||||
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 24,
|
||||
@ -237,7 +237,7 @@ class CPLD:
|
||||
|
||||
Resets the DDS I/O interface and verifies correct CPLD gateware
|
||||
version.
|
||||
Does not pulse the DDS MASTER_RESET as that confuses the AD9910.
|
||||
Does not pulse the DDS ``MASTER_RESET`` as that confuses the AD9910.
|
||||
|
||||
:param blind: Do not attempt to verify presence and compatibility.
|
||||
"""
|
||||
@ -283,7 +283,7 @@ class CPLD:
|
||||
def cfg_switches(self, state: TInt32):
|
||||
"""Configure all four RF switches through the configuration register.
|
||||
|
||||
:param state: RF switch state as a 4 bit integer.
|
||||
:param state: RF switch state as a 4-bit integer.
|
||||
"""
|
||||
self.cfg_write((self.cfg_reg & ~0xf) | state)
|
||||
|
||||
@ -326,11 +326,10 @@ class CPLD:
|
||||
|
||||
@kernel
|
||||
def set_all_att_mu(self, att_reg: TInt32):
|
||||
"""Set all four digital step attenuators (in machine units).
|
||||
"""Set all four digital step attenuators (in machine units).
|
||||
See also :meth:`set_att_mu`.
|
||||
|
||||
.. seealso:: :meth:`set_att_mu`
|
||||
|
||||
:param att_reg: Attenuator setting string (32 bit)
|
||||
:param att_reg: Attenuator setting string (32-bit)
|
||||
"""
|
||||
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 32,
|
||||
SPIT_ATT_WR, CS_ATT)
|
||||
@ -342,8 +341,7 @@ class CPLD:
|
||||
"""Set digital step attenuator in SI units.
|
||||
|
||||
This method will write the attenuator settings of all four channels.
|
||||
|
||||
.. seealso:: :meth:`set_att_mu`
|
||||
See also :meth:`set_att_mu`.
|
||||
|
||||
:param channel: Attenuator channel (0-3).
|
||||
:param att: Attenuation setting in dB. Higher value is more
|
||||
@ -359,9 +357,9 @@ class CPLD:
|
||||
The result is stored and will be used in future calls of
|
||||
:meth:`set_att_mu` and :meth:`set_att`.
|
||||
|
||||
.. seealso:: :meth:`get_channel_att_mu`
|
||||
See also :meth:`get_channel_att_mu`.
|
||||
|
||||
:return: 32 bit attenuator settings
|
||||
:return: 32-bit attenuator settings
|
||||
"""
|
||||
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_INPUT, 32,
|
||||
SPIT_ATT_RD, CS_ATT)
|
||||
@ -380,7 +378,7 @@ class CPLD:
|
||||
The result is stored and will be used in future calls of
|
||||
:meth:`set_att_mu` and :meth:`set_att`.
|
||||
|
||||
.. seealso:: :meth:`get_att_mu`
|
||||
See also :meth:`get_att_mu`.
|
||||
|
||||
:param channel: Attenuator channel (0-3).
|
||||
:return: 8-bit digital attenuation setting:
|
||||
@ -392,7 +390,7 @@ class CPLD:
|
||||
def get_channel_att(self, channel: TInt32) -> TFloat:
|
||||
"""Get digital step attenuator value for a channel in SI units.
|
||||
|
||||
.. seealso:: :meth:`get_channel_att_mu`
|
||||
See also :meth:`get_channel_att_mu`.
|
||||
|
||||
:param channel: Attenuator channel (0-3).
|
||||
:return: Attenuation setting in dB. Higher value is more
|
||||
@ -403,14 +401,14 @@ class CPLD:
|
||||
|
||||
@kernel
|
||||
def set_sync_div(self, div: TInt32):
|
||||
"""Set the SYNC_IN AD9910 pulse generator frequency
|
||||
"""Set the ``SYNC_IN`` AD9910 pulse generator frequency
|
||||
and align it to the current RTIO timestamp.
|
||||
|
||||
The SYNC_IN signal is derived from the coarse RTIO clock
|
||||
The ``SYNC_IN`` signal is derived from the coarse RTIO clock
|
||||
and the divider must be a power of two.
|
||||
Configure ``sync_sel == 0``.
|
||||
|
||||
:param div: SYNC_IN frequency divider. Must be a power of two.
|
||||
:param div: ``SYNC_IN`` frequency divider. Must be a power of two.
|
||||
Minimum division ratio is 2. Maximum division ratio is 16.
|
||||
"""
|
||||
ftw_max = 1 << 4
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""RTIO driver for the Zotino 32-channel, 16-bit 1MSPS DAC.
|
||||
|
||||
Output event replacement is not supported and issuing commands at the same
|
||||
time is an error.
|
||||
time results in a collision error.
|
||||
"""
|
||||
|
||||
from artiq.language.core import kernel
|
||||
|
@ -28,7 +28,7 @@ def kernel(arg=None, flags={}):
|
||||
This decorator marks an object's method for execution on the core
|
||||
device.
|
||||
|
||||
When a decorated method is called from the Python interpreter, the :attr:`core`
|
||||
When a decorated method is called from the Python interpreter, the ``core``
|
||||
attribute of the object is retrieved and used as core device driver. The
|
||||
core device driver will typically compile, transfer and run the method
|
||||
(kernel) on the device.
|
||||
@ -41,7 +41,7 @@ def kernel(arg=None, flags={}):
|
||||
- if the method is a regular Python method (not a kernel), it generates
|
||||
a remote procedure call (RPC) for execution on the host.
|
||||
|
||||
The decorator takes an optional parameter that defaults to :attr`core` and
|
||||
The decorator takes an optional parameter that defaults to ``core`` and
|
||||
specifies the name of the attribute to use as core device driver.
|
||||
|
||||
This decorator must be present in the global namespace of all modules using
|
||||
@ -134,7 +134,7 @@ def portable(arg=None, flags={}):
|
||||
def rpc(arg=None, flags={}):
|
||||
"""
|
||||
This decorator marks a function for execution on the host interpreter.
|
||||
This is also the default behavior of ARTIQ; however, this decorator allows
|
||||
This is also the default behavior of ARTIQ; however, this decorator allows for
|
||||
specifying additional flags.
|
||||
"""
|
||||
if arg is None:
|
||||
@ -256,7 +256,7 @@ _time_manager = _DummyTimeManager()
|
||||
def set_time_manager(time_manager):
|
||||
"""Set the time manager used for simulating kernels by running them
|
||||
directly inside the Python interpreter. The time manager responds to the
|
||||
entering and leaving of interleave/parallel/sequential blocks, delays, etc. and
|
||||
entering and leaving of parallel/sequential blocks, delays, etc. and
|
||||
provides a time-stamped logging facility for events.
|
||||
"""
|
||||
global _time_manager
|
||||
@ -280,7 +280,7 @@ class _Parallel:
|
||||
|
||||
The execution time of a parallel block is the execution time of its longest
|
||||
statement. A parallel block may contain sequential blocks, which themselves
|
||||
may contain interleave blocks, etc.
|
||||
may contain parallel blocks, etc.
|
||||
"""
|
||||
def __enter__(self):
|
||||
_time_manager.enter_parallel()
|
||||
@ -340,5 +340,5 @@ def watchdog(timeout):
|
||||
|
||||
|
||||
class TerminationRequested(Exception):
|
||||
"""Raised by ``pause`` when the user has requested termination."""
|
||||
"""Raised by :meth:`pause` when the user has requested termination."""
|
||||
pass
|
||||
|
@ -28,7 +28,7 @@ class DefaultMissing(Exception):
|
||||
|
||||
|
||||
class CancelledArgsError(Exception):
|
||||
"""Raised by the ``interactive`` context manager when an interactive
|
||||
"""Raised by the :meth:`~artiq.language.environment.HasEnvironment.interactive` context manager when an interactive
|
||||
arguments request is cancelled."""
|
||||
pass
|
||||
|
||||
@ -117,7 +117,7 @@ class NumberValue(_SimpleArgProcessor):
|
||||
``int`` will also result in an error unless these conditions are met.
|
||||
|
||||
When ``scale`` is not specified, and the unit is a common one (i.e.
|
||||
defined in ``artiq.language.units``), then the scale is obtained from
|
||||
defined in :class:`~artiq.language.units`), then the scale is obtained from
|
||||
the unit using a simple string match. For example, milliseconds (``"ms"``)
|
||||
units set the scale to 0.001. No unit (default) corresponds to a scale of
|
||||
1.0.
|
||||
@ -321,7 +321,8 @@ class HasEnvironment:
|
||||
|
||||
:param key: Name of the argument.
|
||||
:param processor: A description of how to process the argument, such
|
||||
as instances of ``BooleanValue`` and ``NumberValue``.
|
||||
as instances of :mod:`~artiq.language.environment.BooleanValue` and
|
||||
:mod:`~artiq.language.environment.NumberValue`.
|
||||
:param group: An optional string that defines what group the argument
|
||||
belongs to, for user interface purposes.
|
||||
:param tooltip: An optional string to describe the argument in more
|
||||
@ -347,7 +348,8 @@ class HasEnvironment:
|
||||
"""Request arguments from the user interactively.
|
||||
|
||||
This context manager returns a namespace object on which the method
|
||||
`setattr_argument` should be called, with the usual semantics.
|
||||
:meth:`~artiq.language.environment.HasEnvironment.setattr_argument` should be called,
|
||||
with the usual semantics.
|
||||
|
||||
When the context manager terminates, the experiment is blocked
|
||||
and the user is presented with the requested argument widgets.
|
||||
@ -355,7 +357,7 @@ class HasEnvironment:
|
||||
the namespace contains the values of the arguments.
|
||||
|
||||
If the interactive arguments request is cancelled, raises
|
||||
``CancelledArgsError``."""
|
||||
:exc:`~artiq.language.environment.CancelledArgsError`."""
|
||||
interactive_arglist = []
|
||||
namespace = SimpleNamespace()
|
||||
def setattr_argument(key, processor=None, group=None, tooltip=None):
|
||||
@ -478,7 +480,7 @@ class HasEnvironment:
|
||||
|
||||
This function is used to get additional information for displaying the dataset.
|
||||
|
||||
See ``set_dataset`` for documentation of metadata items.
|
||||
See :meth:`set_dataset` for documentation of metadata items.
|
||||
"""
|
||||
try:
|
||||
return self.__dataset_mgr.get_metadata(key)
|
||||
|
@ -1,20 +1,6 @@
|
||||
"""
|
||||
Implementation and management of scan objects.
|
||||
|
||||
A scan object (e.g. :class:`artiq.language.scan.RangeScan`) represents a
|
||||
one-dimensional sweep of a numerical range. Multi-dimensional scans are
|
||||
constructed by combining several scan objects, for example using
|
||||
:class:`artiq.language.scan.MultiScanManager`.
|
||||
|
||||
Iterate on a scan object to scan it, e.g. ::
|
||||
|
||||
for variable in self.scan:
|
||||
do_something(variable)
|
||||
|
||||
Iterating multiple times on the same scan object is possible, with the scan
|
||||
yielding the same values each time. Iterating concurrently on the
|
||||
same scan object (e.g. via nested loops) is also supported, and the
|
||||
iterators are independent from each other.
|
||||
"""
|
||||
|
||||
import random
|
||||
@ -32,6 +18,21 @@ __all__ = ["ScanObject",
|
||||
|
||||
|
||||
class ScanObject:
|
||||
"""
|
||||
Represents a one-dimensional sweep of a numerical range. Multi-dimensional scans are
|
||||
constructed by combining several scan objects, for example using
|
||||
:class:`MultiScanManager`.
|
||||
|
||||
Iterate on a scan object to scan it, e.g. ::
|
||||
|
||||
for variable in self.scan:
|
||||
do_something(variable)
|
||||
|
||||
Iterating multiple times on the same scan object is possible, with the scan
|
||||
yielding the same values each time. Iterating concurrently on the
|
||||
same scan object (e.g. via nested loops) is also supported, and the
|
||||
iterators are independent from each other.
|
||||
"""
|
||||
def __iter__(self):
|
||||
raise NotImplementedError
|
||||
|
||||
@ -163,7 +164,7 @@ class Scannable:
|
||||
takes a scan object.
|
||||
|
||||
When ``scale`` is not specified, and the unit is a common one (i.e.
|
||||
defined in ``artiq.language.units``), then the scale is obtained from
|
||||
defined in :class:`artiq.language.units`), then the scale is obtained from
|
||||
the unit using a simple string match. For example, milliseconds (``"ms"``)
|
||||
units set the scale to 0.001. No unit (default) corresponds to a scale of
|
||||
1.0.
|
||||
|
@ -477,16 +477,16 @@ class Scheduler:
|
||||
return self.notifier.raw_view
|
||||
|
||||
def check_pause(self, rid):
|
||||
"""Returns ``True`` if there is a condition that could make ``pause``
|
||||
"""Returns ``True`` if there is a condition that could make :meth:`pause`
|
||||
not return immediately (termination requested or higher priority run).
|
||||
|
||||
The typical purpose of this function is to check from a kernel
|
||||
whether returning control to the host and pausing would have an effect,
|
||||
in order to avoid the cost of switching kernels in the common case
|
||||
where ``pause`` does nothing.
|
||||
where :meth:`pause` does nothing.
|
||||
|
||||
This function does not have side effects, and does not have to be
|
||||
followed by a call to ``pause``.
|
||||
followed by a call to :meth:`pause`.
|
||||
"""
|
||||
for pipeline in self._pipelines.values():
|
||||
if rid in pipeline.pool.runs:
|
||||
|
@ -96,19 +96,19 @@ When using multiple pipelines it is the responsibility of the user to ensure tha
|
||||
Pauses
|
||||
^^^^^^
|
||||
|
||||
In the run stage, an experiment may yield to the scheduler by calling the ``pause()`` method of the scheduler.
|
||||
If there are other experiments with higher priority (e.g. a high-priority experiment has been newly submitted, or reached its due date and become eligible for execution), the higher-priority experiments are executed first, and then ``pause()`` returns. If there are no such experiments, ``pause()`` returns immediately. To check whether ``pause()`` would in fact *not* return immediately, use :meth:`artiq.master.scheduler.Scheduler.check_pause`.
|
||||
In the run stage, an experiment may yield to the scheduler by calling the :meth:`pause` method of the scheduler.
|
||||
If there are other experiments with higher priority (e.g. a high-priority experiment has been newly submitted, or reached its due date and become eligible for execution), the higher-priority experiments are executed first, and then :meth:`pause` returns. If there are no such experiments, :meth:`pause` returns immediately. To check whether :meth:`pause` would in fact *not* return immediately, use :meth:`artiq.master.scheduler.Scheduler.check_pause`.
|
||||
|
||||
The experiment must place the hardware in a safe state and disconnect from the core device (typically, by calling ``self.core.comm.close()`` from the kernel, which is equivalent to :meth:`artiq.coredevice.core.Core.close`) before calling ``pause()``.
|
||||
The experiment must place the hardware in a safe state and disconnect from the core device (typically, by calling ``self.core.comm.close()`` from the kernel, which is equivalent to :meth:`artiq.coredevice.core.Core.close`) before calling :meth:`pause`.
|
||||
|
||||
Accessing the ``pause()`` and :meth:`~artiq.master.scheduler.Scheduler.check_pause` methods is done through a virtual device called ``scheduler`` that is accessible to all experiments. The scheduler virtual device is requested like regular devices using :meth:`~artiq.language.environment.HasEnvironment.get_device` (``self.get_device()``) or :meth:`~artiq.language.environment.HasEnvironment.setattr_device` (``self.setattr_device()``).
|
||||
Accessing the :meth:`pause` and :meth:`~artiq.master.scheduler.Scheduler.check_pause` methods is done through a virtual device called ``scheduler`` that is accessible to all experiments. The scheduler virtual device is requested like regular devices using :meth:`~artiq.language.environment.HasEnvironment.get_device` (``self.get_device()``) or :meth:`~artiq.language.environment.HasEnvironment.setattr_device` (``self.setattr_device()``).
|
||||
|
||||
:meth:`~artiq.master.scheduler.Scheduler.check_pause` can be called (via RPC) from a kernel, but ``pause()`` must not be.
|
||||
:meth:`~artiq.master.scheduler.Scheduler.check_pause` can be called (via RPC) from a kernel, but :meth:`pause` must not be.
|
||||
|
||||
Scheduler API reference
|
||||
-----------------------
|
||||
|
||||
The scheduler is exposed to the experiments via a virtual device called ``scheduler``. It can be requested like any regular device, and then the methods below can be called on the returned object.
|
||||
The scheduler is exposed to the experiments via a virtual device called ``scheduler``. It can be requested like any regular device, and the methods below, as well as :meth:`pause`, can be called on the returned object.
|
||||
|
||||
The scheduler virtual device also contains the attributes ``rid``, ``pipeline_name``, ``priority`` and ``expid``, which contain the corresponding information about the current run.
|
||||
|
||||
@ -130,20 +130,17 @@ CCBs are used by experiments to configure applets in the dashboard, for example
|
||||
Applet request interfaces
|
||||
-------------------------
|
||||
|
||||
Applet request interfaces allow applets to perform actions on the master database and set arguments in the dashboard. Applets may inherit from the ``artiq.applets.simple.SimpleApplet`` and call the methods defined below through the `req` attribute.
|
||||
Applet request interfaces allow applets to perform actions on the master database and set arguments in the dashboard. Applets may inherit from ``artiq.applets.simple.SimpleApplet`` and call the methods defined below through the ``req`` attribute.
|
||||
|
||||
Embedded applets should use `AppletRequestIPC` while standalone applets use `AppletRequestRPC`. `SimpleApplet` automatically chooses the correct interface on initialization.
|
||||
Embedded applets should use ``AppletRequestIPC`` while standalone applets use ``AppletRequestRPC``. ``SimpleApplet`` automatically chooses the correct interface on initialization.
|
||||
|
||||
.. autoclass:: artiq.applets.simple._AppletRequestInterface
|
||||
:members:
|
||||
|
||||
|
||||
Applet entry area
|
||||
-----------------
|
||||
|
||||
Argument widgets can be used in applets through the `EntryArea` class.
|
||||
|
||||
Below is a simple example code snippet using the `EntryArea` class: ::
|
||||
Argument widgets can be used in applets through the :class:`~artiq.gui.applets.EntryArea` class. Below is a simple example code snippet: ::
|
||||
|
||||
entry_area = EntryArea()
|
||||
|
||||
@ -159,7 +156,7 @@ Below is a simple example code snippet using the `EntryArea` class: ::
|
||||
# False
|
||||
print(entry_area.bl)
|
||||
|
||||
The `EntryArea` object can then be added to a layout and integrated with the applet GUI. Multiple `EntryArea` objects can be used in a single applet.
|
||||
The :class:`~artiq.gui.applets.EntryArea` object can then be added to a layout and integrated with the applet GUI. Multiple :class:`~artiq.gui.applets.EntryArea` objects can be used in a single applet.
|
||||
|
||||
.. class:: artiq.gui.applets.EntryArea
|
||||
|
||||
@ -169,7 +166,7 @@ The `EntryArea` object can then be added to a layout and integrated with the app
|
||||
attribute are the same.
|
||||
|
||||
:param name: Argument name
|
||||
:param proc: Argument processor, for example ``NumberValue``
|
||||
:param proc: Argument processor, for example :class:`~artiq.language.environment.NumberValue`
|
||||
:param group: Used to group together arguments in the GUI under a common category
|
||||
:param tooltip: Tooltip displayed when hovering over the entry widget
|
||||
|
||||
@ -181,18 +178,18 @@ The `EntryArea` object can then be added to a layout and integrated with the app
|
||||
|
||||
.. method:: get_values()
|
||||
|
||||
Get all values in the ``EntryArea`` as a dictionary. Names are stored as keys, and argument values as values.
|
||||
Get all values in the :class:`~artiq.gui.applets.EntryArea` as a dictionary. Names are stored as keys, and argument values as values.
|
||||
|
||||
.. method:: set_value(name, value)
|
||||
|
||||
Set the value of an entry widget. The change is temporary and will reset to default when the reset button is clicked.
|
||||
|
||||
:param name: Argument name
|
||||
:param value: Object representing the new value of the argument. For ``Scannable`` arguments, this parameter
|
||||
should be a ``ScanObject``. The type of the ``ScanObject`` will be set as the selected type when this function is called.
|
||||
:param value: Object representing the new value of the argument. For :class:`~artiq.language.scan.Scannable` arguments, this parameter
|
||||
should be a :class:`~artiq.language.scan.ScanObject`. The type of the :class:`~artiq.language.scan.ScanObject` will be set as the selected type when this function is called.
|
||||
|
||||
.. method:: set_values(values)
|
||||
|
||||
Set multiple values from a dictionary input. Calls ``set_value()`` for each key-value pair.
|
||||
Set multiple values from a dictionary input. Calls :meth:`set_value` for each key-value pair.
|
||||
|
||||
:param values: Dictionary with names as keys and new argument values as values.
|
||||
|
Loading…
Reference in New Issue
Block a user