doc: Formatting and link fixes in docstrings

This commit is contained in:
architeuthidae 2024-07-16 13:20:45 +08:00 committed by Sébastien Bourdeauducq
parent 0e1b29c5d9
commit a4bfb0d5dd
31 changed files with 498 additions and 512 deletions

View File

@ -24,21 +24,21 @@ class _AppletRequestInterface:
def set_dataset(self, key, value, unit=None, scale=None, precision=None, persist=None): def set_dataset(self, key, value, unit=None, scale=None, precision=None, persist=None):
""" """
Set a dataset. Set a dataset.
See documentation of ``artiq.language.environment.set_dataset``. See documentation of :meth:`~artiq.language.environment.HasEnvironment.set_dataset`.
""" """
raise NotImplementedError raise NotImplementedError
def mutate_dataset(self, key, index, value): def mutate_dataset(self, key, index, value):
""" """
Mutate a dataset. Mutate a dataset.
See documentation of ``artiq.language.environment.mutate_dataset``. See documentation of :meth:`~artiq.language.environment.HasEnvironment.mutate_dataset`.
""" """
raise NotImplementedError raise NotImplementedError
def append_to_dataset(self, key, value): def append_to_dataset(self, key, value):
""" """
Append to a dataset. 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 raise NotImplementedError
@ -49,8 +49,9 @@ class _AppletRequestInterface:
:param expurl: Experiment URL identifying the experiment in the dashboard. Example: 'repo:ArgumentsDemo'. :param expurl: Experiment URL identifying the experiment in the dashboard. Example: 'repo:ArgumentsDemo'.
:param key: Name of the argument in the experiment. :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 :param value: Object representing the new temporary value of the argument. For :class:`~artiq.language.scan.Scannable` arguments,
should be a ``ScanObject``. The type of the ``ScanObject`` will be set as the selected type when this function is called. 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 raise NotImplementedError

View File

@ -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. Digital to Analog Converters.
Output event replacement is not supported and issuing commands at the same 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 # 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 optimized for speed; datasheet says t22: 25ns min SCLK edge to SDO
valid, and suggests the SPI speed for reads should be <=20 MHz) valid, and suggests the SPI speed for reads should be <=20 MHz)
:param vref: DAC reference voltage (default: 5.) :param vref: DAC reference voltage (default: 5.)
:param offset_dacs: Initial register value for the two offset DACs, device :param offset_dacs: Initial register value for the two offset DACs
dependent and must be set correctly for correct voltage to mu (default: 8192). Device dependent and must be set correctly for
conversions. Knowledge of his state is not transferred between correct voltage-to-mu conversions. Knowledge of this state is
experiments. (default: 8192) not transferred between experiments.
:param core_device: Core device name (default: "core") :param core_device: Core device name (default: "core")
""" """
kernel_invariants = {"bus", "ldac", "clr", "chip_select", "div_write", 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`, :param op: Operation to perform, one of :const:`AD53XX_READ_X1A`,
:const:`AD53XX_READ_X1B`, :const:`AD53XX_READ_OFFSET`, :const:`AD53XX_READ_X1B`, :const:`AD53XX_READ_OFFSET`,
:const:`AD53XX_READ_GAIN` etc. (default: :const:`AD53XX_READ_X1A`). :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.write(ad53xx_cmd_read_ch(channel, op) << 8)
self.bus.set_config_mu(SPI_AD53XX_CONFIG | spi.SPI_INPUT, 24, 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 This method does not advance the timeline; write events are scheduled
in the past. The DACs will synchronously start changing their output 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. If no LDAC device was defined, the LDAC pulse is skipped.
@ -364,8 +364,8 @@ class AD53xx:
high) can be calibrated in this fashion. high) can be calibrated in this fashion.
:param channel: The number of the calibrated channel :param channel: The number of the calibrated channel
:params vzs: Measured voltage with the DAC set to zero-scale (0x0000) :param vzs: Measured voltage with the DAC set to zero-scale (0x0000)
:params vfs: Measured voltage with the DAC set to full-scale (0xffff) :param vfs: Measured voltage with the DAC set to full-scale (0xffff)
""" """
offset_err = voltage_to_mu(vzs, self.offset_dacs, self.vref) offset_err = voltage_to_mu(vzs, self.offset_dacs, self.vref)
gain_err = voltage_to_mu(vfs, self.offset_dacs, self.vref) - ( gain_err = voltage_to_mu(vfs, self.offset_dacs, self.vref) - (

View File

@ -114,27 +114,27 @@ class AD9910:
(as configured through CFG_MASK_NU), 4-7 for individual channels. (as configured through CFG_MASK_NU), 4-7 for individual channels.
:param cpld_device: Name of the Urukul CPLD this device is on. :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 :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 :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 ``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 ``clk_div`` is the reference clock divider (both set in the parent
Urukul CPLD instance). Urukul CPLD instance).
:param pll_en: PLL enable bit, set to 0 to bypass PLL (default: 1). :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. Note that when bypassing the PLL the red front panel LED may remain on.
:param pll_cp: DDS PLL charge pump setting. :param pll_cp: DDS PLL charge pump setting.
:param pll_vco: DDS PLL VCO range selection. :param pll_vco: DDS PLL VCO range selection.
:param sync_delay_seed: SYNC_IN delay tuning starting value. :param sync_delay_seed: ``SYNC_IN`` delay tuning starting value.
To stabilize the SYNC_IN delay tuning, run :meth:`tune_sync_delay` once 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 and set this to the delay tap number returned (default: -1 to signal no
synchronization and no tuning during :meth:`init`). synchronization and no tuning during :meth:`init`).
Can be a string of the form "eeprom_device:byte_offset" to read the 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 value from a I2C EEPROM, in which case ``io_update_delay`` must be set
to the same string value. to the same string value.
:param io_update_delay: IO_UPDATE pulse alignment delay. :param io_update_delay: ``IO_UPDATE`` pulse alignment delay.
To align IO_UPDATE to SYNC_CLK, run :meth:`tune_io_update_delay` and To align ``IO_UPDATE`` to ``SYNC_CLK``, run :meth:`tune_io_update_delay` and
set this to the delay tap number returned. set this to the delay tap number returned.
Can be a string of the form "eeprom_device:byte_offset" to read the 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 value from a I2C EEPROM, in which case ``sync_delay_seed`` must be set
to the same string value. to the same string value.
""" """
@ -188,9 +188,7 @@ class AD9910:
@kernel @kernel
def set_phase_mode(self, phase_mode: TInt32): def set_phase_mode(self, phase_mode: TInt32):
r"""Set the default phase mode. r"""Set the default phase mode for future calls to :meth:`set` and
for future calls to :meth:`set` and
:meth:`set_mu`. Supported phase modes are: :meth:`set_mu`. Supported phase modes are:
* :const:`PHASE_MODE_CONTINUOUS`: the phase accumulator is unchanged * :const:`PHASE_MODE_CONTINUOUS`: the phase accumulator is unchanged
@ -233,7 +231,7 @@ class AD9910:
@kernel @kernel
def write16(self, addr: TInt32, data: TInt32): def write16(self, addr: TInt32, data: TInt32):
"""Write to 16 bit register. """Write to 16-bit register.
:param addr: Register address :param addr: Register address
:param data: Data to be written :param data: Data to be written
@ -244,7 +242,7 @@ class AD9910:
@kernel @kernel
def write32(self, addr: TInt32, data: TInt32): def write32(self, addr: TInt32, data: TInt32):
"""Write to 32 bit register. """Write to 32-bit register.
:param addr: Register address :param addr: Register address
:param data: Data to be written :param data: Data to be written
@ -258,7 +256,7 @@ class AD9910:
@kernel @kernel
def read16(self, addr: TInt32) -> TInt32: def read16(self, addr: TInt32) -> TInt32:
"""Read from 16 bit register. """Read from 16-bit register.
:param addr: Register address :param addr: Register address
""" """
@ -273,7 +271,7 @@ class AD9910:
@kernel @kernel
def read32(self, addr: TInt32) -> TInt32: def read32(self, addr: TInt32) -> TInt32:
"""Read from 32 bit register. """Read from 32-bit register.
:param addr: Register address :param addr: Register address
""" """
@ -288,10 +286,10 @@ class AD9910:
@kernel @kernel
def read64(self, addr: TInt32) -> TInt64: def read64(self, addr: TInt32) -> TInt64:
"""Read from 64 bit register. """Read from 64-bit register.
:param addr: Register address :param addr: Register address
:return: 64 bit integer register value :return: 64-bit integer register value
""" """
self.bus.set_config_mu( self.bus.set_config_mu(
urukul.SPI_CONFIG, 8, urukul.SPI_CONFIG, 8,
@ -311,10 +309,10 @@ class AD9910:
@kernel @kernel
def write64(self, addr: TInt32, data_high: TInt32, data_low: TInt32): 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 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 :param data_low: Low (LSB) 32 data bits
""" """
self.bus.set_config_mu(urukul.SPI_CONFIG, 8, self.bus.set_config_mu(urukul.SPI_CONFIG, 8,
@ -332,8 +330,9 @@ class AD9910:
"""Write data to RAM. """Write data to RAM.
The profile to write to and the step, start, and end address The profile to write to and the step, start, and end address
need to be configured before and separately using need to be configured in advance 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: Data to be written to RAM. :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 The profile to read from and the step, start, and end address
need to be configured before and separately using 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. :param data: List to be filled with data read from RAM.
""" """
@ -392,7 +392,7 @@ class AD9910:
select_auto_osk: TInt32 = 0): select_auto_osk: TInt32 = 0):
"""Set CFR1. See the AD9910 datasheet for parameter meanings. """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 power_down: Power down bits.
:param phase_autoclear: Autoclear phase accumulator. :param phase_autoclear: Autoclear phase accumulator.
@ -431,7 +431,7 @@ class AD9910:
matched_latency_enable: TInt32 = 0): matched_latency_enable: TInt32 = 0):
"""Set CFR2. See the AD9910 datasheet for parameter meanings. """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 asf_profile_enable: Enable amplitude scale from single tone profiles.
:param drg_enable: Digital ramp enable. :param drg_enable: Digital ramp enable.
@ -456,14 +456,14 @@ class AD9910:
"""Initialize and configure the DDS. """Initialize and configure the DDS.
Sets up SPI mode, confirms chip presence, powers down unused blocks, Sets up SPI mode, confirms chip presence, powers down unused blocks,
configures the PLL, waits for PLL lock. Uses the configures the PLL, waits for PLL lock. Uses the ``IO_UPDATE``
IO_UPDATE signal multiple times. signal multiple times.
:param blind: Do not read back DDS identity and do not wait for lock. :param blind: Do not read back DDS identity and do not wait for lock.
""" """
self.sync_data.init() self.sync_data.init()
if self.sync_data.sync_delay_seed >= 0 and not self.cpld.sync_div: 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.sync_data.sync_delay_seed >= 0:
if self.sysclk_per_mu != self.sysclk * self.core.ref_period: if self.sysclk_per_mu != self.sysclk * self.core.ref_period:
raise ValueError("incorrect clock ratio for synchronization") raise ValueError("incorrect clock ratio for synchronization")
@ -514,7 +514,7 @@ class AD9910:
def power_down(self, bits: TInt32 = 0b1111): def power_down(self, bits: TInt32 = 0b1111):
"""Power down DDS. """Power down DDS.
:param bits: Power down bits, see datasheet :param bits: Power-down bits, see datasheet
""" """
self.set_cfr1(power_down=bits) self.set_cfr1(power_down=bits)
self.cpld.io_update.pulse(1 * us) 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 After the SPI transfer, the shared IO update pin is pulsed to
activate the data. 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. phase modes.
:param ftw: Frequency tuning word: 32 bit. :param ftw: Frequency tuning word: 32-bit.
:param pow_: Phase tuning word: 16 bit unsigned. :param pow_: Phase tuning word: 16-bit unsigned.
:param asf: Amplitude scale factor: 14 bit unsigned. :param asf: Amplitude scale factor: 14-bit unsigned.
:param phase_mode: If specified, overrides the default phase mode set :param phase_mode: If specified, overrides the default phase mode set
by :meth:`set_phase_mode` for this call. by :meth:`set_phase_mode` for this call.
:param ref_time_mu: Fiducial time used to compute absolute or tracking :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). :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`, :param ram_destination: RAM destination (:const:`RAM_DEST_FTW`,
:const:`RAM_DEST_POW`, :const:`RAM_DEST_ASF`, :const:`RAM_DEST_POW`, :const:`RAM_DEST_ASF`,
:const:`RAM_DEST_POWASF`). If specified, write free DDS parameters :const:`RAM_DEST_POWASF`). If specified, write free DDS parameters
to the ASF/FTW/POW registers instead of to the single tone profile 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 :return: Resulting phase offset word after application of phase
tracking offset. When using :const:`PHASE_MODE_CONTINUOUS` in tracking offset. When using :const:`PHASE_MODE_CONTINUOUS` in
subsequent calls, use this value as the "current" phase. subsequent calls, use this value as the "current" phase.
@ -598,10 +598,10 @@ class AD9910:
"""Get the frequency tuning word, phase offset word, """Get the frequency tuning word, phase offset word,
and amplitude scale factor. and amplitude scale factor.
.. seealso:: :meth:`get` See also :meth:`AD9910.get`.
:param profile: Profile number to get (0-7, default: 7) :param profile: Profile number to get (0-7, default: 7)
:return: A tuple ``(ftw, pow, asf)`` :return: A tuple (FTW, POW, ASF)
""" """
# Read data # Read data
@ -850,7 +850,7 @@ class AD9910:
ram_destination: TInt32 = -1) -> TFloat: ram_destination: TInt32 = -1) -> TFloat:
"""Set DDS data in SI units. """Set DDS data in SI units.
.. seealso:: :meth:`set_mu` See also :meth:`AD9910.set_mu`.
:param frequency: Frequency in Hz :param frequency: Frequency in Hz
:param phase: Phase tuning word in turns :param phase: Phase tuning word in turns
@ -871,10 +871,10 @@ class AD9910:
) -> TTuple([TFloat, TFloat, TFloat]): ) -> TTuple([TFloat, TFloat, TFloat]):
"""Get the frequency, phase, and amplitude. """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) :param profile: Profile number to get (0-7, default: 7)
:return: A tuple ``(frequency, phase, amplitude)`` :return: A tuple (frequency, phase, amplitude)
""" """
# Get values # Get values
@ -887,11 +887,10 @@ class AD9910:
def set_att_mu(self, att: TInt32): def set_att_mu(self, att: TInt32):
"""Set digital step attenuator in machine units. """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) self.cpld.set_att_mu(self.chip_select - 4, att)
@ -899,9 +898,8 @@ class AD9910:
def set_att(self, att: TFloat): def set_att(self, att: TFloat):
"""Set digital step attenuator in SI units. """Set digital step attenuator in SI 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>`.
.. seealso:: :meth:`artiq.coredevice.urukul.CPLD.set_att`
:param att: Attenuation in dB. :param att: Attenuation in dB.
""" """
@ -909,19 +907,17 @@ class AD9910:
@kernel @kernel
def get_att_mu(self) -> TInt32: 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) return self.cpld.get_channel_att_mu(self.chip_select - 4)
@kernel @kernel
def get_att(self) -> TFloat: def get_att(self) -> TFloat:
"""Get digital step attenuator value in SI units. """Get digital step attenuator value in SI units. See also
:meth:`CPLD.get_channel_att <artiq.coredevice.urukul.CPLD.get_channel_att>`.
.. seealso:: :meth:`artiq.coredevice.urukul.CPLD.get_channel_att`
:return: Attenuation in dB. :return: Attenuation in dB.
""" """
@ -943,16 +939,16 @@ class AD9910:
window: TInt32, window: TInt32,
en_sync_gen: TInt32 = 0): en_sync_gen: TInt32 = 0):
"""Set the relevant parameters in the multi device synchronization """Set the relevant parameters in the multi device synchronization
register. See the AD9910 datasheet for details. The SYNC clock register. See the AD9910 datasheet for details. The ``SYNC`` clock
generator preset value is set to zero, and the SYNC_OUT generator is generator preset value is set to zero, and the ``SYNC_OUT`` generator is
disabled by default. disabled by default.
:param in_delay: SYNC_IN delay tap (0-31) in steps of ~75ps :param in_delay: ``SYNC_IN`` delay tap (0-31) in steps of ~75ps
:param window: Symmetric SYNC_IN validation window (0-15) in :param window: Symmetric ``SYNC_IN`` validation window (0-15) in
steps of ~75ps for both hold and setup margin. steps of ~75ps for both hold and setup margin.
:param en_sync_gen: Whether to enable the DDS-internal sync generator :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 (``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. use case, where the ``SYNC`` clock is supplied by the core device.
""" """
self.write32(_AD9910_REG_SYNC, self.write32(_AD9910_REG_SYNC,
(window << 28) | # SYNC S/H validation delay (window << 28) | # SYNC S/H validation delay
@ -965,9 +961,9 @@ class AD9910:
@kernel @kernel
def clear_smp_err(self): 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 SMP_ERR being asserted. This then also activates the red LED on
the respective Urukul channel. the respective Urukul channel.
@ -982,9 +978,9 @@ class AD9910:
@kernel @kernel
def tune_sync_delay(self, def tune_sync_delay(self,
search_seed: TInt32 = 15) -> TTuple([TInt32, TInt32]): 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 window size (setup/hold margin) by scanning around `search_seed`. It
then looks for similar valid delays at successively larger validation then looks for similar valid delays at successively larger validation
window sizes until none can be found. It then decreases the 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. 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). Defaults to 15 (half range).
:return: Tuple of optimal delay and window size. :return: Tuple of optimal delay and window size.
""" """
@ -1040,16 +1036,16 @@ class AD9910:
def measure_io_update_alignment(self, delay_start: TInt64, def measure_io_update_alignment(self, delay_start: TInt64,
delay_stop: TInt64) -> TInt32: delay_stop: TInt64) -> TInt32:
"""Use the digital ramp generator to locate the alignment between """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 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 ``(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_start`` and stopped at a coarse RTIO time stamp plus
`delay_stop`. ``delay_stop``.
:param delay_start: Start IO_UPDATE delay in machine units. :param delay_start: Start ``IO_UPDATE`` delay in machine units.
:param delay_stop: Stop IO_UPDATE delay in machine units. :param delay_stop: Stop ``IO_UPDATE`` delay in machine units.
:return: Odd/even SYNC_CLK cycle indicator. :return: Odd/even ``SYNC_CLK`` cycle indicator.
""" """
# set up DRG # set up DRG
self.set_cfr1(drg_load_lrr=1, drg_autoclear=1) self.set_cfr1(drg_load_lrr=1, drg_autoclear=1)
@ -1081,19 +1077,19 @@ class AD9910:
@kernel @kernel
def tune_io_update_delay(self) -> TInt32: 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 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 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 ``IO_UPDATE`` delay that is as far away from that ``SYNC_CLK`` edge
as possible. 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). unit resolution (SERDES).
This method and :meth:`tune_sync_delay` can be run in any order. 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. :class:`AD9910` via the device database.
""" """
period = self.sysclk_per_mu * 4 # SYNC_CLK period period = self.sysclk_per_mu * 4 # SYNC_CLK period

View File

@ -11,7 +11,7 @@ from artiq.coredevice import urukul
class AD9912: class AD9912:
""" """
AD9912 DDS channel on Urukul AD9912 DDS channel on Urukul.
This class supports a single DDS channel and exposes the DDS, This class supports a single DDS channel and exposes the DDS,
the digital step attenuator, and the RF switch. 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 :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 :attr:`sw` attribute of this instance.
:param pll_n: DDS PLL multiplier. The DDS sample clock is :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 ``f_ref / clk_div * pll_n`` where ``f_ref`` is the reference frequency and
is the reference clock divider (both set in the parent Urukul CPLD ``clk_div`` is the reference clock divider (both set in the parent
instance). Urukul CPLD instance).
:param pll_en: PLL enable bit, set to 0 to bypass PLL (default: 1). :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. 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, Sets up SPI mode, confirms chip presence, powers down unused blocks,
and configures the PLL. Does not wait for PLL lock. Uses the and configures the PLL. Does not wait for PLL lock. Uses the
IO_UPDATE signal multiple times. ``IO_UPDATE`` signal multiple times.
""" """
# SPI mode # SPI mode
self.write(AD9912_SER_CONF, 0x99, length=1) 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. 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) 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. 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. :param att: Attenuation in dB. Higher values mean more attenuation.
""" """
@ -155,9 +155,9 @@ class AD9912:
def get_att_mu(self) -> TInt32: def get_att_mu(self) -> TInt32:
"""Get digital step attenuator value in machine units. """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) return self.cpld.get_channel_att_mu(self.chip_select - 4)
@ -165,7 +165,7 @@ class AD9912:
def get_att(self) -> TFloat: def get_att(self) -> TFloat:
"""Get digital step attenuator value in SI units. """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. :return: Attenuation in dB.
""" """
@ -178,8 +178,8 @@ class AD9912:
After the SPI transfer, the shared IO update pin is pulsed to After the SPI transfer, the shared IO update pin is pulsed to
activate the data. activate the data.
:param ftw: Frequency tuning word: 48 bit unsigned. :param ftw: Frequency tuning word: 48-bit unsigned.
:param pow_: Phase tuning word: 16 bit unsigned. :param pow_: Phase tuning word: 16-bit unsigned.
""" """
# streaming transfer of FTW and POW # streaming transfer of FTW and POW
self.bus.set_config_mu(urukul.SPI_CONFIG, 16, self.bus.set_config_mu(urukul.SPI_CONFIG, 16,
@ -197,9 +197,9 @@ class AD9912:
def get_mu(self) -> TTuple([TInt64, TInt32]): def get_mu(self) -> TTuple([TInt64, TInt32]):
"""Get the frequency tuning word and phase offset word. """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 # Read data
@ -247,7 +247,7 @@ class AD9912:
def set(self, frequency: TFloat, phase: TFloat = 0.0): def set(self, frequency: TFloat, phase: TFloat = 0.0):
"""Set profile 0 data in SI units. """Set profile 0 data in SI units.
.. seealso:: :meth:`set_mu` See also :meth:`AD9912.set_mu`.
:param frequency: Frequency in Hz :param frequency: Frequency in Hz
:param phase: Phase tuning word in turns :param phase: Phase tuning word in turns
@ -259,9 +259,9 @@ class AD9912:
def get(self) -> TTuple([TFloat, TFloat]): def get(self) -> TTuple([TFloat, TFloat]):
"""Get the frequency and phase. """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 # Get values

View File

@ -49,7 +49,7 @@ class AD9914:
The time cursor is not modified by any function in this class. The time cursor is not modified by any function in this class.
Output event replacement is not supported and issuing commands at the same 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 :param sysclk: DDS system frequency. The DDS system clock must be a
phase-locked multiple of the RTIO clock. phase-locked multiple of the RTIO clock.
@ -134,7 +134,7 @@ class AD9914:
timing margin. timing margin.
:param sync_delay: integer from 0 to 0x3f that sets the value of :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) delay_mu(-self.init_sync_duration_mu)
self.write(AD9914_GPIO, (1 << self.channel) << 1) self.write(AD9914_GPIO, (1 << self.channel) << 1)

View File

@ -112,7 +112,7 @@ class ADF5356:
This method will write the attenuator settings of the channel. 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. :param att: Attenuation in dB.
""" """
@ -122,7 +122,7 @@ class ADF5356:
def set_att_mu(self, att): def set_att_mu(self, att):
"""Set digital step attenuator in machine units. """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) self.cpld.set_att_mu(self.channel, att)
@ -531,14 +531,14 @@ class ADF5356:
@portable @portable
def _compute_pfd_frequency(self, r, d, t) -> TInt64: 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)))) return int64(self.sysclk * ((1 + d) / (r * (1 + t))))
@portable @portable
def _compute_reference_counter(self) -> TInt32: 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]) d = ADF5356_REG4_R_DOUBLER_GET(self.regs[4])
t = ADF5356_REG4_R_DIVIDER_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 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 where
``mod1 = 2**24`` and ``mod2 <= 2**28``
``mod1 = 2**24`` and ``mod2 <= 2**28``
:param f_vco: target VCO frequency :param f_vco: target VCO frequency
:param f_pfd: PFD 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_pfd = int64(f_pfd)
f_vco = int64(f_vco) f_vco = int64(f_vco)

View File

@ -17,12 +17,12 @@ ALMAZNY_LEGACY_SPIT_WR = 32
class AlmaznyLegacy: 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. 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): def __init__(self, dmgr, host_mirny):
@ -121,12 +121,13 @@ class AlmaznyLegacy:
class AlmaznyChannel: class AlmaznyChannel:
""" """
One Almazny channel Driver for one Almazny channel.
Almazny is a mezzanine for the Quad PLL RF source Mirny that exposes and Almazny is a mezzanine for the Quad PLL RF source Mirny that exposes and
controls the frequency-doubled outputs. controls the frequency-doubled outputs.
This driver requires Almazny hardware revision v1.2 or later This driver requires Almazny hardware revision v1.2 or later
and Mirny CPLD gateware v0.3 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 host_mirny: Mirny CPLD device name
:param channel: channel index (0-3) :param channel: channel index (0-3)

View File

@ -21,9 +21,9 @@ class CoreCache:
"""Extract a value from the core device cache. """Extract a value from the core device cache.
After a value is extracted, it cannot be replaced with another value using After a value is extracted, it cannot be replaced with another value using
:meth:`put` until all kernel functions finish executing; attempting :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. is returned.
The value is not copied, so mutating it will change what's stored in the cache. The value is not copied, so mutating it will change what's stored in the cache.

View File

@ -73,8 +73,8 @@ class Core:
On platforms that use clock multiplication and SERDES-based PHYs, On platforms that use clock multiplication and SERDES-based PHYs,
this is the period after multiplication. For example, with a RTIO core this is the period after multiplication. For example, with a RTIO core
clocked at 125MHz and a SERDES multiplication factor of 8, the clocked at 125MHz and a SERDES multiplication factor of 8, the
reference period is 1ns. reference period is ``1 ns``.
The time machine unit is equal to this period. The machine time unit (``mu``) is equal to this period.
:param ref_multiplier: ratio between the RTIO fine timestamp frequency :param ref_multiplier: ratio between the RTIO fine timestamp frequency
and the RTIO coarse timestamp frequency (e.g. SERDES multiplication and the RTIO coarse timestamp frequency (e.g. SERDES multiplication
factor). factor).
@ -116,6 +116,8 @@ class Core:
self.trigger_analyzer_proxy() self.trigger_analyzer_proxy()
def close(self): def close(self):
"""Disconnect core device and close sockets.
"""
self.comm.close() self.comm.close()
def compile(self, function, args, kwargs, set_result=None, 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 Similarly, modified values are not written back, and explicit RPC should be used
to modify host objects. to modify host objects.
Carefully review the source code of drivers calls used in precompiled kernels, as 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. 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 Examples include code used to control DDS phase and Urukul RF switch control
via the CPLD register. via the CPLD register.
The return value of the callable is the return value of the kernel, if any. The return value of the callable is the return value of the kernel, if any.
@ -273,7 +275,7 @@ class Core:
@portable @portable
def seconds_to_mu(self, seconds): def seconds_to_mu(self, seconds):
"""Convert seconds to the corresponding number of machine units """Convert seconds to the corresponding number of machine units
(RTIO cycles). (fine RTIO cycles).
:param seconds: time (in seconds) to convert. :param seconds: time (in seconds) to convert.
""" """
@ -281,7 +283,7 @@ class Core:
@portable @portable
def mu_to_seconds(self, mu): 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. :param mu: cycle count to convert.
""" """
@ -296,7 +298,7 @@ class Core:
for the actual value of the hardware register at the instant when for the actual value of the hardware register at the instant when
execution resumes in the caller. 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() return rtio_get_counter()
@ -315,7 +317,7 @@ class Core:
def get_rtio_destination_status(self, destination): def get_rtio_destination_status(self, destination):
"""Returns whether the specified RTIO destination is up. """Returns whether the specified RTIO destination is up.
This is particularly useful in startup kernels to delay 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) return rtio_get_destination_status(destination)
@kernel @kernel
@ -343,7 +345,7 @@ class Core:
Returns only after the dump has been retrieved from the device. 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 analyzer proxy fails. In the latter case, more details would be
available in the proxy log. available in the proxy log.
""" """

View File

@ -76,11 +76,11 @@ class CoreDMA:
@kernel @kernel
def record(self, name, enable_ddma=False): 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. Any previously recorded trace with the same name is overwritten.
The trace will persist across kernel switches. 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 Enabling it allows running DMA on satellites, rather than sending all
events from the master. events from the master.
@ -116,7 +116,7 @@ class CoreDMA:
def playback_handle(self, handle): def playback_handle(self, handle):
"""Replays a handle obtained with :meth:`get_handle`. Using this function """Replays a handle obtained with :meth:`get_handle`. Using this function
is much faster than :meth:`playback` for replaying a set of traces repeatedly, 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 (epoch, advance_mu, ptr, uses_ddma) = handle
if self.epoch != epoch: if self.epoch != epoch:
raise DMAError("Invalid handle") raise DMAError("Invalid handle")

View File

@ -1,9 +1,9 @@
"""Driver for RTIO-enabled TTL edge counter. """Driver for RTIO-enabled TTL edge counter.
Like for the TTL input PHYs, sensitivity can be configured over RTIO As for the TTL input PHYs, sensitivity can be configured over RTIO
(``gate_rising()``, etc.). In contrast to the former, however, the count is (: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 accumulated in gateware, and only a single input event is generated at the end
of each gate period:: of each gate period: ::
with parallel: with parallel:
doppler_cool() doppler_cool()
@ -17,12 +17,12 @@ of each gate period::
print("Readout counts:", self.pmt_counter.fetch_count()) print("Readout counts:", self.pmt_counter.fetch_count())
For applications where the timestamps of the individual input events are not For applications where the timestamps of the individual input events are not
required, this has two advantages over ``TTLInOut.count()`` beyond raw required, this has two advantages over :meth:`TTLInOut.count<artiq.coredevice.ttl.TTLInOut.count>`
throughput. First, it is easy to count events during multiple separate periods beyond raw throughput. First, it is easy to count events during multiple separate
without blocking to read back counts in between, as illustrated in the above periods without blocking to read back counts in between, as illustrated in the
example. Secondly, as each count total only takes up a single input event, it above example. Secondly, as each count total only takes up a single input event,
is much easier to acquire counts on several channels in parallel without it is much easier to acquire counts on several channels in parallel without
risking input FIFO overflows:: risking input RTIO overflows: ::
# Using the TTLInOut driver, pmt_1 input events are only processed # Using the TTLInOut driver, pmt_1 input events are only processed
# after pmt_0 is done counting. To avoid RTIOOverflows, a round-robin # 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_0 = self.pmt_0.count(now_mu()) # blocks
counts_1 = self.pmt_1.count(now_mu()) counts_1 = self.pmt_1.count(now_mu())
#
# Using gateware counters, only a single input event each is # Using gateware counters, only a single input event each is
# generated, greatly reducing the load on the input FIFOs: # 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_0 = self.pmt_0_counter.fetch_count() # blocks
counts_1 = self.pmt_1_counter.fetch_count() 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. :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 """Emit an RTIO event at the current timeline position to set the
gateware configuration. 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_rising: Whether to count rising signal edges.
:param count_falling: Whether to count falling 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). 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). the next clock cycle (once).
""" """
config = int32(0) config = int32(0)

View File

@ -137,7 +137,7 @@ class RTIOOverflow(Exception):
class RTIODestinationUnreachable(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. being down.
""" """
artiq_builtin = True artiq_builtin = True

View File

@ -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. streaming DAC.
""" """
from numpy import int32, int64 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 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 using :meth:`set_hold`, the next frame will contain the update. For the
DACs held, the update is triggered explicitly by setting the corresponding 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. DAC updates synchronized to a frame edge.
The `log2_width=0` RTIO layout uses one DAC channel per RTIO address and a 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 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 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. tracking in kernels, at the cost of more DMA and RTIO data.
The setting here and in the RTIO PHY (gateware) must match. 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. (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 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` must be used. If non-zero, the :meth:`set_group`/:meth:`set_group_mu`
interface must be used. interface must be used.
@ -63,15 +63,16 @@ class Fastino:
* disables RESET, DAC_CLR, enables AFE_PWR * disables RESET, DAC_CLR, enables AFE_PWR
* clears error counters, enables error counting * clears error counters, enables error counting
* turns LEDs off * 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 * clear and resets interpolators to unit rate change on all
channels channels
It does not change set channel voltages and does not reset the PLLs or clock It does not change set channel voltages and does not reset the PLLs or clock
domains. domains.
Note: On Fastino gateware before v0.2 this may lead to 0 voltage being emitted .. warning::
transiently. 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) self.set_cfg(reset=0, afe_power_down=0, dac_clr=0, clr_err=1)
delay_mu(self.t_frame) delay_mu(self.t_frame)
@ -115,7 +116,7 @@ class Fastino:
"""Write DAC data in machine units. """Write DAC data in machine units.
:param dac: DAC channel to write to (0-31). :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. units.
""" """
self.write(dac, data) self.write(dac, data)
@ -124,9 +125,9 @@ class Fastino:
def set_group_mu(self, dac: TInt32, data: TList(TInt32)): def set_group_mu(self, dac: TInt32, data: TList(TInt32)):
"""Write a group of DAC channels in machine units. """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. 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. in machine units. Data exceeding group size is ignored.
If the list length is less than group size, the remaining If the list length is less than group size, the remaining
DAC channels within the group are cleared to 0 (machine units). DAC channels within the group are cleared to 0 (machine units).
@ -137,10 +138,10 @@ class Fastino:
@portable @portable
def voltage_to_mu(self, voltage): 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. :param voltage: Voltage in SI volts.
:return: DAC data word in machine units, 16 bit integer. :return: DAC data word in machine units, 16-bit integer.
""" """
data = int32(round((0x8000/10.)*voltage)) + int32(0x8000) data = int32(round((0x8000/10.)*voltage)) + int32(0x8000)
if data < 0 or data > 0xffff: if data < 0 or data > 0xffff:
@ -149,9 +150,9 @@ class Fastino:
@portable @portable
def voltage_group_to_mu(self, voltage, data): 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. :param data: List of DAC channel data pairs to write to.
Half the length of `voltage`. Half the length of `voltage`.
""" """
@ -185,7 +186,7 @@ class Fastino:
def update(self, update): def update(self, update):
"""Schedule channels for 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) self.write(0x20, update)
@ -193,7 +194,7 @@ class Fastino:
def set_hold(self, hold): def set_hold(self, hold):
"""Set channels to manual update. """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) self.write(0x21, hold)
@ -214,9 +215,9 @@ class Fastino:
@kernel @kernel
def set_leds(self, leds): 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. green LED.
""" """
self.write(0x23, leds) self.write(0x23, leds)
@ -245,16 +246,16 @@ class Fastino:
def stage_cic(self, rate) -> TInt32: def stage_cic(self, rate) -> TInt32:
"""Compute and stage interpolator configuration. """Compute and stage interpolator configuration.
This method approximates the desired interpolation rate using a 10 bit This method approximates the desired interpolation rate using a 10-bit
floating point representation (6 bit mantissa, 4 bit exponent) and floating point representation (6-bit mantissa, 4-bit exponent) and
then determines an optimal interpolation gain compensation exponent then determines an optimal interpolation gain compensation exponent
to avoid clipping. Gains for rates that are powers of two are accurately 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 compensated. Other rates lead to overall less than unity gain (but more
than 0.5 gain). than 0.5 gain).
The overall gain including gain compensation is The overall gain including gain compensation is ``actual_rate ** order /
`actual_rate**order/2**ceil(log2(actual_rate**order))` 2 ** ceil(log2(actual_rate ** order))``
where `order = 3`. where ``order = 3``.
Returns the actual interpolation rate. Returns the actual interpolation rate.
""" """
@ -293,7 +294,7 @@ class Fastino:
their output is supposed to be constant. their output is supposed to be constant.
This method resets and settles the affected interpolators. There will be 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 Affected channels will only accept one input sample per input sample
period. This method synchronizes the input sample period to the current period. This method synchronizes the input sample period to the current
frame on the affected channels. frame on the affected channels.

View File

@ -102,7 +102,7 @@ class Grabber:
this call or the next. this call or the next.
If the timeout is reached before data is available, the exception 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 :param timeout_mu: Timestamp at which a timeout will occur. Set to -1
(default) to disable timeout. (default) to disable timeout.

View File

@ -43,7 +43,7 @@ def i2c_poll(busno, busaddr):
"""Poll I2C device at address. """Poll I2C device at address.
:param busno: I2C bus number :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 :returns: True if the poll was ACKed
""" """
i2c_start(busno) i2c_start(busno)
@ -57,7 +57,7 @@ def i2c_write_byte(busno, busaddr, data, ack=True):
"""Write one byte to a device. """Write one byte to a device.
:param busno: I2C bus number :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 data: Data byte to be written
:param nack: Allow NACK :param nack: Allow NACK
""" """
@ -76,7 +76,7 @@ def i2c_read_byte(busno, busaddr):
"""Read one byte from a device. """Read one byte from a device.
:param busno: I2C bus number :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 :returns: Byte read
""" """
i2c_start(busno) i2c_start(busno)
@ -95,10 +95,10 @@ def i2c_write_many(busno, busaddr, addr, data, ack_last=True):
"""Transfer multiple bytes to a device. """Transfer multiple bytes to a device.
:param busno: I2c bus number :param busno: I2c bus number
:param busaddr: 8 bit I2C device address (LSB=0) :param busaddr: 8-bit I2C device address (LSB=0)
:param addr: 8 bit data address :param addr: 8-bit data address
:param data: Data bytes to be written :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). the last byte may be NACKed (e.g. EEPROM full page writes).
""" """
n = len(data) n = len(data)
@ -121,8 +121,8 @@ def i2c_read_many(busno, busaddr, addr, data):
"""Transfer multiple bytes from a device. """Transfer multiple bytes from a device.
:param busno: I2c bus number :param busno: I2c bus number
:param busaddr: 8 bit I2C device address (LSB=0) :param busaddr: 8-bit I2C device address (LSB=0)
:param addr: 8 bit data address :param addr: 8-bit data address
:param data: List of integers to be filled with the data read. :param data: List of integers to be filled with the data read.
One entry ber byte. One entry ber byte.
""" """
@ -147,7 +147,7 @@ class I2CSwitch:
PCA954X (or other) type detection is done by the CPU during I2C init. 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. involving RTIO.
On the KC705, this chip is used for selecting the I2C buses on the two FMC On the KC705, this chip is used for selecting the I2C buses on the two FMC
@ -176,7 +176,7 @@ class I2CSwitch:
class TCA6424A: class TCA6424A:
"""Driver for the TCA6424A I2C I/O expander. """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. involving RTIO.
On the NIST QC2 hardware, this chip is used for switching the directions On the NIST QC2 hardware, this chip is used for switching the directions
@ -212,7 +212,7 @@ class TCA6424A:
class PCF8574A: class PCF8574A:
"""Driver for the PCF8574 I2C remote 8-bit I/O expander. """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. involving RTIO.
""" """
def __init__(self, dmgr, busno=0, address=0x7c, core_device="core"): def __init__(self, dmgr, busno=0, address=0x7c, core_device="core"):

View File

@ -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 from artiq.language.core import kernel, delay, portable
@ -82,7 +82,7 @@ class Mirny:
@kernel @kernel
def read_reg(self, addr): def read_reg(self, addr):
"""Read a register""" """Read a register."""
self.bus.set_config_mu( self.bus.set_config_mu(
SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, 24, SPIT_RD, SPI_CS SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, 24, SPIT_RD, SPI_CS
) )
@ -91,7 +91,7 @@ class Mirny:
@kernel @kernel
def write_reg(self, addr, data): 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.set_config_mu(SPI_CONFIG | spi.SPI_END, 24, SPIT_WR, SPI_CS)
self.bus.write((addr << 25) | WE | ((data & 0xFFFF) << 8)) self.bus.write((addr << 25) | WE | ((data & 0xFFFF) << 8))
@ -101,9 +101,9 @@ class Mirny:
Initialize and detect Mirny. Initialize and detect Mirny.
Select the clock source based the board's hardware revision. 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) reg0 = self.read_reg(0)
self.hw_rev = reg0 & 0x3 self.hw_rev = reg0 & 0x3
@ -138,7 +138,7 @@ class Mirny:
def set_att_mu(self, channel, att): def set_att_mu(self, channel, att):
"""Set digital step attenuator in machine units. """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.set_config_mu(SPI_CONFIG | spi.SPI_END, 16, SPIT_WR, SPI_CS)
self.bus.write(((channel | 8) << 25) | (att << 16)) 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. 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 channel: Attenuator channel (0-3).
:param att: Attenuation setting in dB. Higher value is more :param att: Attenuation setting in dB. Higher value is more
@ -160,7 +160,7 @@ class Mirny:
@kernel @kernel
def write_ext(self, addr, length, data, ext_div=SPIT_WR): 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.set_config_mu(SPI_CONFIG, 8, SPIT_WR, SPI_CS)
self.bus.write(addr << 25) self.bus.write(addr << 25)
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, length, ext_div, SPI_CS) self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, length, ext_div, SPI_CS)

View File

@ -16,31 +16,31 @@ SPI_CS_SR = 2
@portable @portable
def adc_ctrl(channel=1, softspan=0b111, valid=1): 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 return (valid << 7) | (channel << 3) | softspan
@portable @portable
def adc_softspan(data): 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 return data & 0x7
@portable @portable
def adc_channel(data): def adc_channel(data):
"""Return the channel index from a result packet""" """Return the channel index from a result packet."""
return (data >> 3) & 0x7 return (data >> 3) & 0x7
@portable @portable
def adc_data(data): def adc_data(data):
"""Return the ADC value from a result packet""" """Return the ADC value from a result packet."""
return (data >> 8) & 0xffff return (data >> 8) & 0xffff
@portable @portable
def adc_value(data, v_ref=5.): 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) softspan = adc_softspan(data)
data = adc_data(data) data = adc_data(data)
g = 625 g = 625
@ -107,7 +107,7 @@ class Novogorny:
def configure(self, data): def configure(self, data):
"""Set up the ADC sequencer. """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. table.
""" """
if len(data) > 1: if len(data) > 1:
@ -137,12 +137,10 @@ class Novogorny:
@kernel @kernel
def sample(self, next_ctrl=0): def sample(self, next_ctrl=0):
"""Acquire a sample """Acquire a sample. See also :meth:`Novogorny.sample_mu`.
.. seealso:: :meth:`sample_mu`
:param next_ctrl: ADC control word for the next sample :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) return adc_value(self.sample_mu(), self.v_ref)
@ -151,7 +149,7 @@ class Novogorny:
"""Acquire a burst of samples. """Acquire a burst of samples.
If the burst is too long and the sample rate too high, there will be 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 High sample rates lead to gain errors since the impedance between the
instrumentation amplifier and the ADC is high. instrumentation amplifier and the ADC is high.

View File

@ -85,7 +85,7 @@ SERVO_T_CYCLE = (32+12+192+24+4)*ns # Must match gateware ADC parameters
class Phaser: class Phaser:
"""Phaser 4-channel, 16-bit, 1 GS/s DAC coredevice driver. """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. quadrature modulation compensation and interpolation features.
The coredevice RTIO PHY and the Phaser gateware come in different modes The coredevice RTIO PHY and the Phaser gateware come in different modes
@ -109,9 +109,9 @@ class Phaser:
**Base mode** **Base mode**
The coredevice produces 2 IQ (in-phase and quadrature) data streams with 25 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 MS/s and 14 bits per quadrature. Each data stream supports 5 independent
numerically controlled IQ oscillators (NCOs, DDSs with 32 bit frequency, 16 numerically controlled IQ oscillators (NCOs, DDSs with 32-bit frequency,
bit phase, 15 bit amplitude, and phase accumulator clear functionality) 16-bit phase, 15-bit amplitude, and phase accumulator clear functionality)
added together. See :class:`PhaserChannel` and :class:`PhaserOscillator`. added together. See :class:`PhaserChannel` and :class:`PhaserOscillator`.
Together with a data clock, framing marker, a checksum and metadata for 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. FastLink via a single EEM connector from coredevice to Phaser.
On Phaser in the FPGA the data streams are buffered and interpolated 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 with adjustable frequency and phase. The interpolation passband is 20 MHz
wide, passband ripple is less than 1e-3 amplitude, stopband attenuation 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 is better than 75 dB at offsets > 15 MHz and better than 90 dB at offsets
> 30 MHz. > 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 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, Instruments DAC34H84). On the DAC 2x interpolation, sinx/x compensation,
quadrature modulator compensation, fine and coarse mixing as well as group quadrature modulator compensation, fine and coarse mixing as well as group
delay capabilities are available. If desired, these features my be 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 The latency/group delay from the RTIO events setting
:class:`PhaserOscillator` or :class:`PhaserChannel` DUC parameters all the :class:`PhaserOscillator` or :class:`PhaserChannel` DUC parameters all the
way to the DAC outputs is deterministic. This enables deterministic way to the DAC outputs is deterministic. This enables deterministic
absolute phase with respect to other RTIO input and output events absolute phase with respect to other RTIO input and output events
(see `get_next_frame_mu()`). (see :meth:`get_next_frame_mu()`).
**Miqro mode** **Miqro mode**
See :class:`Miqro` See :class:`Miqro`. Here the DAC operates in 4x interpolation.
Here the DAC operates in 4x interpolation.
**Analog flow** **Analog flow**
@ -171,7 +169,7 @@ class Phaser:
and Q datastreams from the DUC by the IIR output. The IIR state is updated at and Q datastreams from the DUC by the IIR output. The IIR state is updated at
the 3.788 MHz ADC sampling rate. 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 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``, set for each profile individually and the profiles each have their own ``y0``,
``y1`` output registers (the ``x0``, ``x1`` inputs are shared). To avoid ``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 still ingests samples and updates its input ``x0`` and ``x1`` registers, but
does not update the ``y0``, ``y1`` output registers. 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 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 Phaser FPGA, the device simply behaves as if the servo is disabled and none of
the servo functions have any effect. the servo functions have any effect.
.. note:: Various register settings of the DAC and the quadrature .. note:: Various register settings of the DAC and the quadrature
upconverters are available to be modified through the `dac`, `trf0`, upconverters are available to be modified through the ``dac``, ``trf0``,
`trf1` dictionaries. These can be set through the device database ``trf1`` dictionaries. These can be set through the device database
(`device_db.py`). The settings are frozen during instantiation of the (``device_db.py``). The settings are frozen during instantiation of the
class and applied during `init()`. See the :class:`DAC34H84` and class and applied during ``init()``. See the :class:`dac34H84` and
:class:`TRF372017` source for details. :class:`trf372017` source for details.
.. note:: To establish deterministic latency between RTIO time base and DAC .. note:: To establish deterministic latency between RTIO time base and DAC
output, the DAC FIFO read pointer value (`fifo_offset`) must be output, the DAC FIFO read pointer value (``fifo_offset``) must be
fixed. If `tune_fifo_offset=True` (the default) a value with maximum fixed. If `tune_fifo_offset` = ``True`` (the default) a value with maximum
margin is determined automatically by `dac_tune_fifo_offset` each time margin is determined automatically by `dac_tune_fifo_offset` each time
`init()` is called. This value should be used for the `fifo_offset` key :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 of the ``dac`` settings of Phaser in ``device_db.py`` and automatic
tuning should be disabled by `tune_fifo_offset=False`. tuning should be disabled by `tune_fifo_offset` = ``False```.
:param channel: Base RTIO channel number :param channel: Base RTIO channel number
:param core_device: Core device name (default: "core") :param core_device: Core device name (default: "core")
@ -219,9 +217,9 @@ class Phaser:
:param trf1: Channel 1 TRF372017 quadrature upconverter settings as a :param trf1: Channel 1 TRF372017 quadrature upconverter settings as a
dictionary. 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 To access oscillators, digital upconverters, PLL/VCO analog
quadrature upconverters and attenuators. quadrature upconverters and attenuators.
""" """
@ -463,8 +461,8 @@ class Phaser:
def write8(self, addr, data): def write8(self, addr, data):
"""Write data to FPGA register. """Write data to FPGA register.
:param addr: Address to write to (7 bit) :param addr: Address to write to (7-bit)
:param data: Data to write (8 bit) :param data: Data to write (8-bit)
""" """
rtio_output((self.channel_base << 8) | (addr & 0x7f) | 0x80, data) rtio_output((self.channel_base << 8) | (addr & 0x7f) | 0x80, data)
delay_mu(int64(self.t_frame)) delay_mu(int64(self.t_frame))
@ -473,8 +471,8 @@ class Phaser:
def read8(self, addr) -> TInt32: def read8(self, addr) -> TInt32:
"""Read from FPGA register. """Read from FPGA register.
:param addr: Address to read from (7 bit) :param addr: Address to read from (7-bit)
:return: Data read (8 bit) :return: Data read (8-bit)
""" """
rtio_output((self.channel_base << 8) | (addr & 0x7f), 0) rtio_output((self.channel_base << 8) | (addr & 0x7f), 0)
response = rtio_input_data(self.channel_base) response = rtio_input_data(self.channel_base)
@ -482,13 +480,13 @@ class Phaser:
@kernel @kernel
def write16(self, addr, data: TInt32): 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, data >> 8)
self.write8(addr + 1, data) self.write8(addr + 1, data)
@kernel @kernel
def write32(self, addr, data: TInt32): 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): for offset in range(4):
byte = data >> 24 byte = data >> 24
self.write8(addr + offset, byte) self.write8(addr + offset, byte)
@ -496,7 +494,7 @@ class Phaser:
@kernel @kernel
def read32(self, addr) -> TInt32: 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 data = 0
for offset in range(4): for offset in range(4):
data <<= 8 data <<= 8
@ -508,15 +506,15 @@ class Phaser:
def set_leds(self, leds): def set_leds(self, leds):
"""Set the front panel LEDs. """Set the front panel LEDs.
:param leds: LED settings (6 bit) :param leds: LED settings (6-bit)
""" """
self.write8(PHASER_ADDR_LED, leds) self.write8(PHASER_ADDR_LED, leds)
@kernel @kernel
def set_fan_mu(self, pwm): 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) self.write8(PHASER_ADDR_FAN, pwm)
@ -581,10 +579,10 @@ class Phaser:
@kernel @kernel
def measure_frame_timestamp(self): 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. 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 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) self.frame_tstamp = rtio_input_timestamp(now_mu() + 4 * self.t_frame, self.channel_base)
@ -592,10 +590,10 @@ class Phaser:
@kernel @kernel
def get_next_frame_mu(self): 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 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) n = int64((now_mu() - self.frame_tstamp) / self.t_frame)
return self.frame_tstamp + (n + 1) * self.t_frame return self.frame_tstamp + (n + 1) * self.t_frame
@ -658,7 +656,7 @@ class Phaser:
@kernel @kernel
def dac_write(self, addr, data): 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 addr: Register address
:param data: Register data to write :param data: Register data to write
@ -708,16 +706,16 @@ class Phaser:
def dac_sync(self): def dac_sync(self):
"""Trigger DAC synchronisation for both output channels. """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. triggered on assertion.
By default, the fine-mixer (NCO) and QMC are synchronised. This By default, the fine-mixer (NCO) and QMC are synchronised. This
includes applying the latest register settings. includes applying the latest register settings.
The synchronisation sources may be configured through the `syncsel_x` The synchronisation sources may be configured through the ``syncsel_x``
fields in the `dac` configuration dictionary (see `__init__()`). 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) config1f = self.dac_read(0x1f)
delay(.4*ms) delay(.4*ms)
@ -726,11 +724,11 @@ class Phaser:
@kernel @kernel
def set_dac_cmix(self, fs_8_step): 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 Use of the coarse mixer requires the DAC mixer to be enabled. The mixer
can be configured via the `dac` configuration dictionary (see can be configured via the ``dac`` configuration dictionary (see
`__init__()`). :class:`Phaser`).
The selected coarse mixer frequency becomes active without explicit The selected coarse mixer frequency becomes active without explicit
synchronisation. synchronisation.
@ -763,8 +761,8 @@ class Phaser:
def dac_iotest(self, pattern) -> TInt32: def dac_iotest(self, pattern) -> TInt32:
"""Performs a DAC IO test according to the datasheet. """Performs a DAC IO test according to the datasheet.
:param pattern: List of four int32 containing the pattern :param pattern: List of four int32s containing the pattern
:return: Bit error mask (16 bits) :return: Bit error mask (16-bit)
""" """
if len(pattern) != 4: if len(pattern) != 4:
raise ValueError("pattern length out of bounds") raise ValueError("pattern length out of bounds")
@ -803,9 +801,9 @@ class Phaser:
@kernel @kernel
def dac_tune_fifo_offset(self): 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. pointer.
""" """
# expect two or three error free offsets: # expect two or three error free offsets:
@ -865,7 +863,7 @@ class PhaserChannel:
Attributes: Attributes:
* :attr:`oscillator`: List of five :class:`PhaserOscillator`. * :attr:`oscillator`: List of five instances of :class:`PhaserOscillator`.
* :attr:`miqro`: A :class:`Miqro`. * :attr:`miqro`: A :class:`Miqro`.
.. note:: The amplitude sum of the oscillators must be less than one to .. 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 changes in oscillator parameters, the overshoot can lead to clipping
or overflow after the interpolation. Either band-limit any changes or overflow after the interpolation. Either band-limit any changes
in the oscillator parameters or back off the amplitude sufficiently. 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. be affected by intrinsic overshoot of the interpolator on the DAC.
""" """
kernel_invariants = {"index", "phaser", "trf_mmap"} kernel_invariants = {"index", "phaser", "trf_mmap"}
@ -899,7 +897,7 @@ class PhaserChannel:
The data is split accross multiple registers and thus the data The data is split accross multiple registers and thus the data
is only valid if constant. 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 Q/DACB/DACD in the 16 MSB
""" """
return self.phaser.read32(PHASER_ADDR_DAC0_DATA + (self.index << 4)) return self.phaser.read32(PHASER_ADDR_DAC0_DATA + (self.index << 4))
@ -908,7 +906,7 @@ class PhaserChannel:
def set_dac_test(self, data: TInt32): def set_dac_test(self, data: TInt32):
"""Set the DAC test data. """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 Q/DACB/DACD in the 16 MSB
""" """
self.phaser.write32(PHASER_ADDR_DAC0_TEST + (self.index << 4), data) self.phaser.write32(PHASER_ADDR_DAC0_TEST + (self.index << 4), data)
@ -930,7 +928,7 @@ class PhaserChannel:
def set_duc_frequency_mu(self, ftw): def set_duc_frequency_mu(self, ftw):
"""Set the DUC frequency. """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) self.phaser.write32(PHASER_ADDR_DUC0_F + (self.index << 4), ftw)
@ -948,7 +946,7 @@ class PhaserChannel:
def set_duc_phase_mu(self, pow): def set_duc_phase_mu(self, pow):
"""Set the DUC phase offset. """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) addr = PHASER_ADDR_DUC0_P + (self.index << 4)
self.phaser.write8(addr, pow >> 8) self.phaser.write8(addr, pow >> 8)
@ -970,10 +968,10 @@ class PhaserChannel:
This method stages the new NCO frequency, but does not apply it. 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 Use of the DAC-NCO requires the DAC mixer and NCO to be enabled. These
can be configured via the `dac` configuration dictionary (see can be configured via the ``dac`` configuration dictionary (see
`__init__()`). :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(0x15 + (self.index << 1), ftw >> 16)
self.phaser.dac_write(0x14 + (self.index << 1), ftw) 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. 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 Use of the DAC-NCO requires the DAC mixer and NCO to be enabled. These
can be configured via the `dac` configuration dictionary (see can be configured via the ``dac`` configuration dictionary (see
`__init__()`). :class:`Phaser`).
:param frequency: NCO frequency in Hz (passband from -400 MHz :param frequency: NCO frequency in Hz (passband from -400 MHz
to 400 MHz, wrapping around at +- 500 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 By default, the new NCO phase applies on completion of the SPI
transfer. This also causes a staged NCO frequency to be applied. transfer. This also causes a staged NCO frequency to be applied.
Different triggers for applying NCO settings may be configured through Different triggers for applying NCO settings may be configured through
the `syncsel_mixerxx` fields in the `dac` configuration dictionary (see the ``syncsel_mixerxx`` fields in the ``dac`` configuration dictionary (see
`__init__()`). :class:`Phaser`).
Use of the DAC-NCO requires the DAC mixer and NCO to be enabled. These Use of the DAC-NCO requires the DAC mixer and NCO to be enabled. These
can be configured via the `dac` configuration dictionary (see can be configured via the ``dac`` configuration dictionary.
`__init__()`).
:param pow: NCO phase offset word (16 bit) :param pow: NCO phase offset word (16-bit)
""" """
self.phaser.dac_write(0x12 + self.index, pow) 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 By default, the new NCO phase applies on completion of the SPI
transfer. This also causes a staged NCO frequency to be applied. transfer. This also causes a staged NCO frequency to be applied.
Different triggers for applying NCO settings may be configured through Different triggers for applying NCO settings may be configured through
the `syncsel_mixerxx` fields in the `dac` configuration dictionary (see the ``syncsel_mixerxx`` fields in the ``dac`` configuration dictionary (see
`__init__()`). :class:`Phaser`).
Use of the DAC-NCO requires the DAC mixer and NCO to be enabled. These Use of the DAC-NCO requires the DAC mixer and NCO to be enabled. These
can be configured via the `dac` configuration dictionary (see can be configured via the ``dac`` configuration dictionary.
`__init__()`).
:param phase: NCO phase in turns :param phase: NCO phase in turns
""" """
@ -1035,7 +1031,7 @@ class PhaserChannel:
def set_att_mu(self, data): def set_att_mu(self, data):
"""Set channel attenuation. """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 div = 34 # 30 ns min period
t_xfer = self.phaser.core.seconds_to_mu((8 + 1)*div*4*ns) 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): def trf_write(self, data, readback=False):
"""Write 32 bits to quadrature upconverter register. """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 :param readback: Whether to return the read back MISO data
""" """
div = 34 # 50 ns min period div = 34 # 50 ns min period
@ -1114,7 +1110,7 @@ class PhaserChannel:
:param addr: Register address to read (0 to 7) :param addr: Register address to read (0 to 7)
:param cnt_mux_sel: Report VCO counter min or max frequency :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)) self.trf_write(0x80000008 | (addr << 28) | (cnt_mux_sel << 27))
# single clk pulse with ~LE to start readback # 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 * :math:`b_0` and :math:`b_1` are the feedforward gains for the two
delays delays
.. seealso:: :meth:`set_iir` See also :meth:`PhaserChannel.set_iir`.
:param profile: Profile to set (0 to 3) :param profile: Profile to set (0 to 3)
:param b0: b0 filter coefficient (16 bit signed) :param b0: b0 filter coefficient (16-bit signed)
:param b1: b1 filter coefficient (16 bit signed) :param b1: b1 filter coefficient (16-bit signed)
:param a1: a1 filter coefficient (16 bit signed) :param a1: a1 filter coefficient (16-bit signed)
:param offset: Output offset (16 bit signed) :param offset: Output offset (16-bit signed)
""" """
if (profile < 0) or (profile > 3): if (profile < 0) or (profile > 3):
raise ValueError("invalid profile index") raise ValueError("invalid profile index")
@ -1240,7 +1236,7 @@ class PhaserChannel:
integrator gain limit is infinite. Same sign as ``ki``. integrator gain limit is infinite. Same sign as ``ki``.
:param x_offset: IIR input offset. Used as the negative :param x_offset: IIR input offset. Used as the negative
setpoint when stabilizing to a desired input setpoint. Will 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. :param y_offset: IIR output offset.
""" """
NORM = 1 << SERVO_COEFF_SHIFT NORM = 1 << SERVO_COEFF_SHIFT
@ -1296,7 +1292,7 @@ class PhaserOscillator:
def set_frequency_mu(self, ftw): def set_frequency_mu(self, ftw):
"""Set Phaser MultiDDS frequency tuning word. """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) rtio_output(self.base_addr, ftw)
@ -1314,8 +1310,8 @@ class PhaserOscillator:
def set_amplitude_phase_mu(self, asf=0x7fff, pow=0, clr=0): def set_amplitude_phase_mu(self, asf=0x7fff, pow=0, clr=0):
"""Set Phaser MultiDDS amplitude, phase offset and accumulator clear. """Set Phaser MultiDDS amplitude, phase offset and accumulator clear.
:param asf: Amplitude (15 bit) :param asf: Amplitude (15-bit)
:param pow: Phase offset word (16 bit) :param pow: Phase offset word (16-bit)
:param clr: Clear the phase accumulator (persistent) :param clr: Clear the phase accumulator (persistent)
""" """
data = (asf & 0x7fff) | ((clr & 1) << 15) | (pow << 16) data = (asf & 0x7fff) | ((clr & 1) << 15) | (pow << 16)
@ -1346,38 +1342,42 @@ class Miqro:
**Oscillators** **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 * 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 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 (from f = -100..+100 MHz, taking into account the interpolation anti-aliasing
filters in subsequent interpolators), filters in subsequent interpolators),
* 32 bit frequency (f) resolution (~ 1/16 Hz), * 32-bit frequency (f) resolution (~ 1/16 Hz),
* 16 bit unsigned amplitude (a) resolution * 16-bit unsigned amplitude (a) resolution
* 16 bit phase offset (p) resolution * 16-bit phase offset (p) resolution
* The output phase p' of each oscillator at time t (boot/reset/initialization of the * 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 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. 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 .. note ::
(on top of previous phase/profiles/oscillator history). The terms "phase coherent" and "phase tracking" are defined to refer to this
It is "absolute" in the sense that frequency f and phase offset p fully determine choice of oscillator output phase ``p'``. Note that the phase offset ``p`` is not relative to
oscillator output phase p' at time t. This is unlike typical DDS behavior. (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 * 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 ``n_profiles = 32`` profiles ``0``... ``n_profile-1``. This selection is fast and can be
each pulse. The phase coherence defined above is guaranteed for each done for each pulse. The phase coherence defined above is guaranteed for each
profile individually. profile individually.
* Note: one profile per oscillator (usually profile index 0) should be reserved * Note: one profile per oscillator (usually profile index 0) should be reserved
for the NOP (no operation, identity) profile, usually with zero amplitude. for the NOP (no operation, identity) profile, usually with zero amplitude.
* Data for each profile for each oscillator can be configured * Data for each profile for each oscillator can be configured
individually. Storing profile data should be considered "expensive". 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 .. note::
resources to execute such that it may be impractical when used often or To refer to an operation as "expensive" does not mean it is impossible,
during fast pulse sequences. They are intended for use in calibration and merely that it may take a significant amount of time and resources to
initialization. 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** **Summation**
@ -1394,18 +1394,18 @@ class Miqro:
the RF output. the RF output.
* Selected profiles become active simultaneously (on the same output sample) when * Selected profiles become active simultaneously (on the same output sample) when
triggering the shaper with the first shaper output sample. 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 * The window memory can be segmented by choosing different start indices
to support different windows. to support different windows.
* Each window memory segment starts with a header determining segment * Each window memory segment starts with a header determining segment
length and interpolation parameters. length and interpolation parameters.
* The window samples are interpolated by a factor (rate change) between 1 and * 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 * The interpolation order is constant, linear, quadratic, or cubic. This
corresponds to interpolation modes from rectangular window (1st order CIC) corresponds to interpolation modes from rectangular window (1st order CIC)
or zero order hold) to Parzen window (4th order CIC or cubic spline). 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 * 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 * 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 do not feed zero-amplitude samples into the shaper before and after
each window respectively. This is used to implement pulses with arbitrary each window respectively. This is used to implement pulses with arbitrary
@ -1413,18 +1413,18 @@ class Miqro:
**Overall properties** **Overall properties**
* The DAC may upconvert the signal by applying a frequency offset f1 with * The DAC may upconvert the signal by applying a frequency offset ``f1`` with
phase p1. phase ``p1``.
* In the Upconverter Phaser variant, the analog quadrature upconverter * 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 * 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) ``(f + f1 + f2)*t + p + s(t - t0) + p1 + p2 (mod 1 turn)``
where s(t - t0) is the phase of the interpolated where ``s(t - t0)`` is the phase of the interpolated
shaper output, and t0 is the trigger time (fiducial of the shaper). shaper output, and ``t0`` is the trigger time (fiducial of the shaper).
Unsurprisingly the frequency is the derivative of the phase. Unsurprisingly the frequency is the derivative of the phase.
* Group delays between pulse parameter updates are matched across oscillators, * Group delays between pulse parameter updates are matched across oscillators,
shapers, and channels. 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. This is the minimum pulse interval.
The sustained pulse rate of the RTIO PHY/Fastlink is one pulse per Fastlink frame The sustained pulse rate of the RTIO PHY/Fastlink is one pulse per Fastlink frame
(may be increased, TBC). (may be increased, TBC).
@ -1455,9 +1455,9 @@ class Miqro:
:param oscillator: Oscillator index (0 to 15) :param oscillator: Oscillator index (0 to 15)
:param profile: Profile index (0 to 31) :param profile: Profile index (0 to 31)
:param ftw: Frequency tuning word (32 bit signed integer on a 250 MHz clock) :param ftw: Frequency tuning word (32-bit signed integer on a 250 MHz clock)
:param asf: Amplitude scale factor (16 bit unsigned integer) :param asf: Amplitude scale factor (16-bit unsigned integer)
:param pow_: Phase offset word (16 bit integer) :param pow_: Phase offset word (16-bit integer)
""" """
if oscillator >= 16: if oscillator >= 16:
raise ValueError("invalid oscillator index") raise ValueError("invalid oscillator index")
@ -1481,7 +1481,7 @@ class Miqro:
:param amplitude: Amplitude in units of full scale (0. to 1.) :param amplitude: Amplitude in units of full scale (0. to 1.)
:param phase: Phase in turns. See :class:`Miqro` for a definition of :param phase: Phase in turns. See :class:`Miqro` for a definition of
phase in this context. 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)))) ftw = int32(round(frequency*((1 << 30)/(62.5*MHz))))
asf = int32(round(amplitude*0xffff)) asf = int32(round(amplitude*0xffff))
@ -1493,7 +1493,7 @@ class Miqro:
@kernel @kernel
def set_window_mu(self, start, iq, rate=1, shift=0, order=3, head=1, tail=1): 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 start: Window start address (0 to 0x3ff)
:param iq: List of IQ window samples. Each window sample is an integer :param iq: List of IQ window samples. Each window sample is an integer
@ -1540,7 +1540,7 @@ class Miqro:
@kernel @kernel
def set_window(self, start, iq, period=4*ns, order=3, head=1, tail=1): 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 start: Window start address (0 to 0x3ff)
:param iq: List of IQ window samples. Each window sample is a pair of :param iq: List of IQ window samples. Each window sample is a pair of
@ -1577,7 +1577,7 @@ class Miqro:
@kernel @kernel
def encode(self, window, profiles, data): 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 window: Window start address (0 to 0x3ff)
:param profiles: List of profile indices for the oscillators. Maximum :param profiles: List of profile indices for the oscillators. Maximum

View File

@ -25,7 +25,7 @@ def rtio_input_data(channel: TInt32) -> TInt32:
@syscall(flags={"nowrite"}) @syscall(flags={"nowrite"})
def rtio_input_timestamped_data(timeout_mu: TInt64, def rtio_input_timestamped_data(timeout_mu: TInt64,
channel: TInt32) -> TTuple([TInt64, TInt32]): 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 return a tuple of timestamp and attached data, or (-1, 0) if the timeout is
reached.""" reached."""
raise NotImplementedError("syscall not simulated") raise NotImplementedError("syscall not simulated")

View File

@ -16,13 +16,13 @@ SPI_CS_PGIA = 1 # separate SPI bus, CS used as RCLK
@portable @portable
def adc_mu_to_volt(data, gain=0, corrected_fs=True): 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 gain: PGIA gain setting (0: 1, ..., 3: 1000)
:param corrected_fs: use corrected ADC FS reference. :param corrected_fs: use corrected ADC FS reference.
Should be True for Samplers' revisions after v2.1. False for v2.1 and earlier. Should be ``True`` for Sampler revisions after v2.1. ``False`` for v2.1 and earlier.
:return: Voltage in Volts :return: Voltage in volts
""" """
if gain == 0: if gain == 0:
volt_per_lsb = 20.48 / (1 << 16) if corrected_fs else 20. / (1 << 16) 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: class Sampler:
"""Sampler ADC. """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. the switchable gain instrumentation amplifiers.
:param spi_adc_device: ADC SPI bus device name :param spi_adc_device: ADC SPI bus device name
@ -119,12 +119,12 @@ class Sampler:
Perform a conversion and transfer the samples. Perform a conversion and transfer the samples.
This assumes that the input FIFO of the ADC SPI RTIO channel is deep 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. If it is not, there will be RTIO input overflows.
:param data: List of data samples to fill. Must have even length. :param data: List of data samples to fill. Must have even length.
Samples are always read from the last channel (channel 7) down. 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. holding to the sample from channel 7.
""" """
self.cnv.pulse(30*ns) # t_CNVH self.cnv.pulse(30*ns) # t_CNVH
@ -142,7 +142,7 @@ class Sampler:
def sample(self, data): def sample(self, data):
"""Acquire a set of samples. """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. :param data: List of floating point data samples to fill.
""" """

View File

@ -16,8 +16,8 @@ def shuttler_volt_to_mu(volt):
class Config: class Config:
"""Shuttler configuration registers interface. """Shuttler configuration registers interface.
The configuration registers control waveform phase auto-clear, and pre-DAC The configuration registers control waveform phase auto-clear, pre-DAC
gain & offset values for calibration with ADC on the Shuttler AFE card. 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 To find the calibrated DAC code, the Shuttler Core first multiplies the
output data with pre-DAC gain, then adds the offset. output data with pre-DAC gain, then adds the offset.
@ -84,8 +84,7 @@ class Config:
def set_offset(self, channel, offset): def set_offset(self, channel, offset):
"""Set the 16-bits pre-DAC offset register of a Shuttler Core channel. """Set the 16-bits pre-DAC offset register of a Shuttler Core channel.
.. seealso:: See also :meth:`shuttler_volt_to_mu`.
:meth:`shuttler_volt_to_mu`
:param channel: Shuttler Core channel to be configured. :param channel: Shuttler Core channel to be configured.
:param offset: Shuttler Core channel offset. :param offset: Shuttler Core channel offset.
@ -114,13 +113,13 @@ class DCBias:
.. math:: .. math::
w(t) = a(t) + b(t) * cos(c(t)) 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 This class controls the cubic spline `a(t)`, in which
.. math:: .. math::
a(t) = p_0 + p_1t + \\frac{p_2t^2}{2} + \\frac{p_3t^3}{6} 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 channel: RTIO channel number of this DC-bias spline interface.
:param core_device: Core device name. :param core_device: Core device name.
@ -137,7 +136,7 @@ class DCBias:
"""Set the DC-bias spline waveform. """Set the DC-bias spline waveform.
Given `a(t)` as defined in :class:`DCBias`, the coefficients should be Given `a(t)` as defined in :class:`DCBias`, the coefficients should be
configured by the following formulae. configured by the following formulae:
.. math:: .. math::
T &= 8*10^{-9} T &= 8*10^{-9}
@ -154,8 +153,10 @@ class DCBias:
and 48 bits in width respectively. See :meth:`shuttler_volt_to_mu` for and 48 bits in width respectively. See :meth:`shuttler_volt_to_mu` for
machine unit conversion. machine unit conversion.
Note: The waveform is not updated to the Shuttler Core until .. note::
triggered. See :class:`Trigger` for the update triggering mechanism. 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 a0: The :math:`a_0` coefficient in machine unit.
:param a1: The :math:`a_1` coefficient in machine unit. :param a1: The :math:`a_1` coefficient in machine unit.
@ -189,7 +190,7 @@ class DDS:
.. math:: .. math::
w(t) = a(t) + b(t) * cos(c(t)) 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)`, This class controls the cubic spline `b(t)` and quadratic spline `c(t)`,
in which in which
@ -198,7 +199,7 @@ class DDS:
c(t) &= r_0 + r_1t + \\frac{r_2t^2}{2} 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`. contributes to a constant gain of :math:`g=1.64676`.
:param channel: RTIO channel number of this DC-bias spline interface. :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 Note: The waveform is not updated to the Shuttler Core until
triggered. See :class:`Trigger` for the update triggering mechanism. triggered. See :class:`Trigger` for the update triggering mechanism.
:param b0: The :math:`b_0` coefficient in machine unit. :param b0: The :math:`b_0` coefficient in machine units.
:param b1: The :math:`b_1` coefficient in machine unit. :param b1: The :math:`b_1` coefficient in machine units.
:param b2: The :math:`b_2` coefficient in machine unit. :param b2: The :math:`b_2` coefficient in machine units.
:param b3: The :math:`b_3` coefficient in machine unit. :param b3: The :math:`b_3` coefficient in machine units.
:param c0: The :math:`c_0` coefficient in machine unit. :param c0: The :math:`c_0` coefficient in machine units.
:param c1: The :math:`c_1` coefficient in machine unit. :param c1: The :math:`c_1` coefficient in machine units.
:param c2: The :math:`c_2` coefficient in machine unit. :param c2: The :math:`c_2` coefficient in machine units.
""" """
coef_words = [ coef_words = [
b0, b0,
@ -292,8 +293,8 @@ class Trigger:
"""Triggers coefficient update of (a) Shuttler Core channel(s). """Triggers coefficient update of (a) Shuttler Core channel(s).
Each bit corresponds to a Shuttler waveform generator core. Setting Each bit corresponds to a Shuttler waveform generator core. Setting
`trig_out` bits commits the pending coefficient update (from ``trig_out`` bits commits the pending coefficient update (from
`set_waveform` in :class:`DCBias` and :class:`DDS`) to the Shuttler Core ``set_waveform`` in :class:`DCBias` and :class:`DDS`) to the Shuttler Core
synchronously. synchronously.
:param trig_out: Coefficient update trigger bits. The MSB corresponds :param trig_out: Coefficient update trigger bits. The MSB corresponds
@ -336,8 +337,8 @@ _AD4115_REG_SETUPCON0 = 0x20
class Relay: class Relay:
"""Shuttler AFE relay switches. """Shuttler AFE relay switches.
It controls the AFE relay switches and the LEDs. Switch on the relay to This class controls the AFE relay switches and the LEDs. Switch the relay on to
enable AFE output; And off to disable the output. The LEDs indicates the enable AFE output; off to disable the output. The LEDs indicate the
relay status. relay status.
.. note:: .. note::
@ -357,7 +358,7 @@ class Relay:
def init(self): def init(self):
"""Initialize SPI device. """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. switches and LED control.
""" """
self.bus.set_config_mu( self.bus.set_config_mu(
@ -365,10 +366,10 @@ class Relay:
@kernel @kernel
def enable(self, en: TInt32): 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 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. turns off the switch instead.
:param en: Switch enable bits. The MSB corresponds to Channel 15, LSB :param en: Switch enable bits. The MSB corresponds to Channel 15, LSB
@ -403,12 +404,12 @@ class ADC:
def reset(self): def reset(self):
"""AD4115 reset procedure. """AD4115 reset procedure.
This performs a write operation of 96 serial clock cycles with DIN Performs a write operation of 96 serial clock cycles with DIN
held at high. It resets the entire device, including the register held at high. This resets the entire device, including the register
contents. contents.
.. note:: .. 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. after the transfer appears to interrupt the start-up sequence.
""" """
self.bus.set_config_mu(ADC_SPI_CONFIG, 32, SPIT_ADC_WR, CS_ADC) self.bus.set_config_mu(ADC_SPI_CONFIG, 32, SPIT_ADC_WR, CS_ADC)
@ -420,7 +421,7 @@ class ADC:
@kernel @kernel
def read8(self, addr: TInt32) -> TInt32: def read8(self, addr: TInt32) -> TInt32:
"""Read from 8 bit register. """Read from 8-bit register.
:param addr: Register address. :param addr: Register address.
:return: Read-back register content. :return: Read-back register content.
@ -433,7 +434,7 @@ class ADC:
@kernel @kernel
def read16(self, addr: TInt32) -> TInt32: def read16(self, addr: TInt32) -> TInt32:
"""Read from 16 bit register. """Read from 16-bit register.
:param addr: Register address. :param addr: Register address.
:return: Read-back register content. :return: Read-back register content.
@ -446,7 +447,7 @@ class ADC:
@kernel @kernel
def read24(self, addr: TInt32) -> TInt32: def read24(self, addr: TInt32) -> TInt32:
"""Read from 24 bit register. """Read from 24-bit register.
:param addr: Register address. :param addr: Register address.
:return: Read-back register content. :return: Read-back register content.
@ -459,7 +460,7 @@ class ADC:
@kernel @kernel
def write8(self, addr: TInt32, data: TInt32): def write8(self, addr: TInt32, data: TInt32):
"""Write to 8 bit register. """Write to 8-bit register.
:param addr: Register address. :param addr: Register address.
:param data: Data to be written. :param data: Data to be written.
@ -470,7 +471,7 @@ class ADC:
@kernel @kernel
def write16(self, addr: TInt32, data: TInt32): def write16(self, addr: TInt32, data: TInt32):
"""Write to 16 bit register. """Write to 16-bit register.
:param addr: Register address. :param addr: Register address.
:param data: Data to be written. :param data: Data to be written.
@ -481,7 +482,7 @@ class ADC:
@kernel @kernel
def write24(self, addr: TInt32, data: TInt32): def write24(self, addr: TInt32, data: TInt32):
"""Write to 24 bit register. """Write to 24-bit register.
:param addr: Register address. :param addr: Register address.
:param data: Data to be written. :param data: Data to be written.
@ -494,11 +495,11 @@ class ADC:
def read_ch(self, channel: TInt32) -> TFloat: def read_ch(self, channel: TInt32) -> TFloat:
"""Sample a Shuttler channel on the AFE. """Sample a Shuttler channel on the AFE.
It performs a single conversion using profile 0 and setup 0, on the Performs a single conversion using profile 0 and setup 0 on the
selected channel. The sample is then recovered and converted to volt. selected channel. The sample is then recovered and converted to volts.
:param channel: Shuttler channel to be sampled. :param channel: Shuttler channel to be sampled.
:return: Voltage sample in volt. :return: Voltage sample in volts.
""" """
# Always configure Profile 0 for single conversion # Always configure Profile 0 for single conversion
self.write16(_AD4115_REG_CH0, 0x8000 | ((channel * 2 + 1) << 4)) self.write16(_AD4115_REG_CH0, 0x8000 | ((channel * 2 + 1) << 4))
@ -519,7 +520,7 @@ class ADC:
@kernel @kernel
def standby(self): 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 The ADC can be returned to single conversion mode by calling
:meth:`single_conversion`. :meth:`single_conversion`.
@ -536,13 +537,7 @@ class ADC:
.. note:: .. note::
The AD4115 datasheet suggests placing the ADC in standby mode The AD4115 datasheet suggests placing the ADC in standby mode
before power-down. This is to prevent accidental entry into the before power-down. This is to prevent accidental entry into the
power-down mode. power-down mode. See also :meth:`standby` and :meth:`power_up`.
.. seealso::
:meth:`standby`
:meth:`power_up`
""" """
self.write16(_AD4115_REG_ADCMODE, 0x8030) self.write16(_AD4115_REG_ADCMODE, 0x8030)
@ -552,8 +547,7 @@ class ADC:
The ADC should be in power-down mode before calling this method. The ADC should be in power-down mode before calling this method.
.. seealso:: See also :meth:`power_down`.
:meth:`power_down`
""" """
self.reset() self.reset()
# Although the datasheet claims 500 us reset wait time, only waiting # 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]): def calibrate(self, volts, trigger, config, samples=[-5.0, 0.0, 5.0]):
"""Calibrate the Shuttler waveform generator using the ADC on the AFE. """Calibrate the Shuttler waveform generator using the ADC on the AFE.
It finds the average slope rate and average offset by samples, and Finds the average slope rate and average offset by samples, and
compensate by writing the pre-DAC gain and offset registers in the compensates by writing the pre-DAC gain and offset registers in the
configuration registers. configuration registers.
.. note:: .. note::
If the pre-calibration slope rate < 1, the calibration procedure If the pre-calibration slope rate is less than 1, the calibration
will introduce a pre-DAC gain compensation. However, this may procedure will introduce a pre-DAC gain compensation. However, this
saturate the pre-DAC voltage code. (See :class:`Config` notes). may saturate the pre-DAC voltage code (see :class:`Config` notes).
Shuttler cannot cover the entire +/- 10 V range in this case. Shuttler cannot cover the entire +/- 10 V range in this case.
See also :meth:`Config.set_gain` and :meth:`Config.set_offset`.
.. seealso:: :param volts: A list of all 16 cubic DC-bias splines.
:meth:`Config.set_gain`
:meth:`Config.set_offset`
:param volts: A list of all 16 cubic DC-bias spline.
(See :class:`DCBias`) (See :class:`DCBias`)
:param trigger: The Shuttler spline coefficient update trigger. :param trigger: The Shuttler spline coefficient update trigger.
:param config: The Shuttler Core configuration registers. :param config: The Shuttler Core configuration registers.

View File

@ -4,7 +4,7 @@ Driver for generic SPI on RTIO.
This ARTIQ coredevice driver corresponds to the "new" MiSoC SPI core (v2). This ARTIQ coredevice driver corresponds to the "new" MiSoC SPI core (v2).
Output event replacement is not supported and issuing commands at the same 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 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``. event (``SPI_INPUT`` set), then :meth:`read` the ``data``.
* If ``SPI_END`` was not set, repeat the transfer sequence. * 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 pattern is asserted for the entire length of the transaction. All but the
last transfer are submitted with ``SPI_END`` cleared in the configuration last transfer are submitted with ``SPI_END`` cleared in the configuration
register. register.
@ -138,10 +138,10 @@ class SPIMaster:
* :const:`SPI_LSB_FIRST`: LSB is the first bit on the wire (reset=0) * :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) * :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. :param length: Number of bits to write during the next transfer.
(reset=1) (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. :param cs: Bit pattern of chip selects to assert.
Or number of the chip select to assert if ``cs`` is decoded Or number of the chip select to assert if ``cs`` is decoded
downstream. (reset=0) downstream. (reset=0)
@ -152,16 +152,15 @@ class SPIMaster:
def set_config_mu(self, flags, length, div, cs): def set_config_mu(self, flags, length, div, cs):
"""Set the ``config`` register (in SPI bus machine units). """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 flags: A bit map of `SPI_*` flags.
:param length: Number of bits to write during the next transfer. :param length: Number of bits to write during the next transfer.
(reset=1) (reset=1)
:param div: Counter load value to divide the RTIO :param div: Counter load value to divide the RTIO
clock by to generate the SPI clock. (minimum=2, reset=2) clock by to generate the SPI clock; ``f_rtio_clk/f_spi == div``.
``f_rtio_clk/f_spi == div``. If ``div`` is odd, If ``div`` is odd, the setup phase of the SPI clock is one
the setup phase of the SPI clock is one coarse RTIO clock cycle coarse RTIO clock cycle longer than the hold phase. (minimum=2, reset=2)
longer than the hold phase.
:param cs: Bit pattern of chip selects to assert. :param cs: Bit pattern of chip selects to assert.
Or number of the chip select to assert if ``cs`` is decoded Or number of the chip select to assert if ``cs`` is decoded
downstream. (reset=0) downstream. (reset=0)
@ -188,7 +187,7 @@ class SPIMaster:
experiments and are known. experiments and are known.
This method is portable and can also be called from e.g. 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 .. warning:: If this method is called while recording a DMA
sequence, the playback of the sequence will not update the 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. * The ``data`` register and the shift register are 32 bits wide.
* Data writes take one ``ref_period`` cycle. * Data writes take one ``ref_period`` cycle.
* A transaction consisting of a single transfer (``SPI_END``) takes * 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. ``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 * Transfers in a multi-transfer transaction take up to one SPI clock
cycle less time depending on multiple parameters. Advanced users may cycle less time depending on multiple parameters. Advanced users may

View File

@ -24,7 +24,7 @@ def y_mu_to_full_scale(y):
@portable @portable
def adc_mu_to_volts(x, gain, corrected_fs=True): 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 val = (x >> 1) & 0xffff
mask = 1 << 15 mask = 1 << 15
val = -(val & mask) + (val & ~mask) val = -(val & mask) + (val & ~mask)
@ -155,7 +155,7 @@ class SUServo:
This method advances the timeline by one servo memory access. This method advances the timeline by one servo memory access.
It does not support RTIO event replacement. 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 iterations beginning with the ADC sampling stage. The first DDS
update will happen about two servo cycles (~2.3 µs) after enabling update will happen about two servo cycles (~2.3 µs) after enabling
the servo. The delay is deterministic. the servo. The delay is deterministic.
@ -198,7 +198,7 @@ class SUServo:
consistent and valid data, stop the servo before using this method. consistent and valid data, stop the servo before using this method.
:param adc: ADC channel number (0-7) :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 # State memory entries are 25 bits. Due to the pre-adder dynamic
# range, X0/X1/OFFSET are only 24 bits. Finally, the RTIO interface # 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): def set_dds_mu(self, profile, ftw, offs, pow_=0):
"""Set profile DDS coefficients in machine units. """Set profile DDS coefficients in machine units.
.. seealso:: :meth:`set_amplitude` See also :meth:`Channel.set_dds`.
:param profile: Profile number (0-31) :param profile: Profile number (0-31)
:param ftw: Frequency tuning word (32 bit unsigned) :param ftw: Frequency tuning word (32-bit unsigned)
:param offs: IIR offset (17 bit signed) :param offs: IIR offset (17-bit signed)
:param pow_: Phase offset word (16 bit) :param pow_: Phase offset word (16-bit)
""" """
base = (self.servo_channel << 8) | (profile << 3) base = (self.servo_channel << 8) | (profile << 3)
self.servo.write(base + 0, ftw >> 16) self.servo.write(base + 0, ftw >> 16)
@ -327,7 +327,7 @@ class Channel:
See :meth:`set_dds_mu` for setting the complete DDS profile. See :meth:`set_dds_mu` for setting the complete DDS profile.
:param profile: Profile number (0-31) :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) base = (self.servo_channel << 8) | (profile << 3)
self.servo.write(base + 4, offs) 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 * :math:`b_0` and :math:`b_1` are the feedforward gains for the two
delays delays
.. seealso:: :meth:`set_iir` See also :meth:`Channel.set_iir`.
:param profile: Profile number (0-31) :param profile: Profile number (0-31)
:param adc: ADC channel to take IIR input from (0-7) :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) 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) 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) X1 coefficient, feed forward, proportional gain)
:param dly: IIR update suppression time. In units of IIR cycles :param dly: IIR update suppression time. In units of IIR cycles
(~1.2 µs, 0-255). (~1.2 µs, 0-255).
@ -499,7 +499,7 @@ class Channel:
consistent and valid data, stop the servo before using this method. consistent and valid data, stop the servo before using this method.
:param profile: Profile number (0-31) :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) 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. This method advances the timeline by one servo memory access.
:param profile: Profile number (0-31) :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. # State memory is 25 bits wide and signed.
# Reads interact with the 18 MSBs (coefficient memory width) # Reads interact with the 18 MSBs (coefficient memory width)

View File

@ -27,7 +27,7 @@ class TTLOut:
This should be used with output-only channels. This should be used with output-only channels.
:param channel: channel number :param channel: Channel number
""" """
kernel_invariants = {"core", "channel", "target_o"} 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 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. 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", kernel_invariants = {"core", "channel", "gate_latency_mu",
"target_o", "target_oe", "target_sens", "target_sample"} "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 """Set the direction to output at the current position of the time
cursor. 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. other command can be issued.
This method only configures the direction at the FPGA. When using 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 """Set the direction to input at the current position of the time
cursor. 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. other command can be issued.
This method only configures the direction at the FPGA. When using 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 :return: The number of events before the timeout elapsed (0 if none
observed). observed).
Examples: **Examples:**
To count events on channel ``ttl_input``, up to the current timeline To count events on channel ``ttl_input``, up to the current timeline
position:: position: ::
ttl_input.count(now_mu()) ttl_input.count(now_mu())
If other events are scheduled between the end of the input gate If other events are scheduled between the end of the input gate
period and when the number of events is counted, using ``now_mu()`` period and when the number of events is counted, using
as timeout consumes an unnecessary amount of timeline slack. In :meth:`~artiq.language.core.now_mu()` as timeout consumes an
such cases, it can be beneficial to pass a more precise timestamp, unnecessary amount of timeline slack. In such cases, it can be
for example:: beneficial to pass a more precise timestamp, for example: ::
gate_end_mu = ttl_input.gate_rising(100 * us) gate_end_mu = ttl_input.gate_rising(100 * us)
@ -350,7 +351,7 @@ class TTLInOut:
num_rising_edges = ttl_input.count(gate_end_mu) num_rising_edges = ttl_input.count(gate_end_mu)
The ``gate_*()`` family of methods return the cursor at the end 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)) ttl_input.count(ttl_input.gate_rising(100 * us))
""" """
@ -441,7 +442,7 @@ class TTLInOut:
was being watched. was being watched.
The time cursor is not modified by this function. This function 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) rtio_output(self.target_sens, 0)
success = True success = True

View File

@ -130,7 +130,7 @@ class CPLD:
:param spi_device: SPI bus device name :param spi_device: SPI bus device name
:param io_update_device: IO update RTIO TTLOut channel name :param io_update_device: IO update RTIO TTLOut channel name
:param dds_reset_device: DDS reset 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) :param refclk: Reference clock (SMA, MMCX or on-board 100 MHz oscillator)
frequency in Hz frequency in Hz
:param clk_sel: Reference clock selection. For hardware revision >= 1.3 :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. 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 On Urukul boards with CPLD gateware before v1.3.1 only the default
(0, i.e. variant dependent divider) is valid. (0, i.e. variant dependent divider) is valid.
:param sync_sel: SYNC (multi-chip synchronisation) signal source selection. :param sync_sel: ``SYNC`` (multi-chip synchronisation) signal source selection.
0 corresponds to SYNC_IN being supplied by the FPGA via the EEM 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 connector. 1 corresponds to ``SYNC_OUT`` from DDS0 being distributed to the
other chips. other chips.
:param rf_sw: Initial CPLD RF switch register setting (default: 0x0). :param rf_sw: Initial CPLD RF switch register setting (default: 0x0).
Knowledge of this state is not transferred between experiments. 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 0x00000000). See also :meth:`get_att_mu` which retrieves the hardware
state without side effects. Knowledge of this state is not transferred state without side effects. Knowledge of this state is not transferred
between experiments. between experiments.
:param sync_div: SYNC_IN generator divider. The ratio between the coarse :param sync_div: ``SYNC_IN`` generator divider. The ratio between the coarse
RTIO frequency and the SYNC_IN generator frequency (default: 2 if RTIO frequency and the ``SYNC_IN`` generator frequency (default: 2 if
`sync_device` was specified). `sync_device` was specified).
:param core_device: Core device name :param core_device: Core device name
@ -204,7 +204,7 @@ class CPLD:
See :func:`urukul_cfg` for possible flags. 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`. :attr:`cfg_reg`.
""" """
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 24, 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 Resets the DDS I/O interface and verifies correct CPLD gateware
version. 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. :param blind: Do not attempt to verify presence and compatibility.
""" """
@ -283,7 +283,7 @@ class CPLD:
def cfg_switches(self, state: TInt32): def cfg_switches(self, state: TInt32):
"""Configure all four RF switches through the configuration register. """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) self.cfg_write((self.cfg_reg & ~0xf) | state)
@ -326,11 +326,10 @@ class CPLD:
@kernel @kernel
def set_all_att_mu(self, att_reg: TInt32): 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, self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 32,
SPIT_ATT_WR, CS_ATT) SPIT_ATT_WR, CS_ATT)
@ -342,8 +341,7 @@ class CPLD:
"""Set digital step attenuator in SI units. """Set digital step attenuator in SI 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:`set_att_mu`.
.. seealso:: :meth:`set_att_mu`
:param channel: Attenuator channel (0-3). :param channel: Attenuator channel (0-3).
:param att: Attenuation setting in dB. Higher value is more :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 The result is stored and will be used in future calls of
:meth:`set_att_mu` and :meth:`set_att`. :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, self.bus.set_config_mu(SPI_CONFIG | spi.SPI_INPUT, 32,
SPIT_ATT_RD, CS_ATT) SPIT_ATT_RD, CS_ATT)
@ -380,7 +378,7 @@ class CPLD:
The result is stored and will be used in future calls of The result is stored and will be used in future calls of
:meth:`set_att_mu` and :meth:`set_att`. :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). :param channel: Attenuator channel (0-3).
:return: 8-bit digital attenuation setting: :return: 8-bit digital attenuation setting:
@ -392,7 +390,7 @@ class CPLD:
def get_channel_att(self, channel: TInt32) -> TFloat: def get_channel_att(self, channel: TInt32) -> TFloat:
"""Get digital step attenuator value for a channel in SI units. """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). :param channel: Attenuator channel (0-3).
:return: Attenuation setting in dB. Higher value is more :return: Attenuation setting in dB. Higher value is more
@ -403,14 +401,14 @@ class CPLD:
@kernel @kernel
def set_sync_div(self, div: TInt32): 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. 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. and the divider must be a power of two.
Configure ``sync_sel == 0``. 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. Minimum division ratio is 2. Maximum division ratio is 16.
""" """
ftw_max = 1 << 4 ftw_max = 1 << 4

View File

@ -1,7 +1,7 @@
"""RTIO driver for the Zotino 32-channel, 16-bit 1MSPS DAC. """RTIO driver for the Zotino 32-channel, 16-bit 1MSPS DAC.
Output event replacement is not supported and issuing commands at the same 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 from artiq.language.core import kernel

View File

@ -28,7 +28,7 @@ def kernel(arg=None, flags={}):
This decorator marks an object's method for execution on the core This decorator marks an object's method for execution on the core
device. 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 attribute of the object is retrieved and used as core device driver. The
core device driver will typically compile, transfer and run the method core device driver will typically compile, transfer and run the method
(kernel) on the device. (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 - if the method is a regular Python method (not a kernel), it generates
a remote procedure call (RPC) for execution on the host. 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. 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 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={}): def rpc(arg=None, flags={}):
""" """
This decorator marks a function for execution on the host interpreter. 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. specifying additional flags.
""" """
if arg is None: if arg is None:
@ -256,7 +256,7 @@ _time_manager = _DummyTimeManager()
def set_time_manager(time_manager): def set_time_manager(time_manager):
"""Set the time manager used for simulating kernels by running them """Set the time manager used for simulating kernels by running them
directly inside the Python interpreter. The time manager responds to the 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. provides a time-stamped logging facility for events.
""" """
global _time_manager global _time_manager
@ -280,7 +280,7 @@ class _Parallel:
The execution time of a parallel block is the execution time of its longest The execution time of a parallel block is the execution time of its longest
statement. A parallel block may contain sequential blocks, which themselves statement. A parallel block may contain sequential blocks, which themselves
may contain interleave blocks, etc. may contain parallel blocks, etc.
""" """
def __enter__(self): def __enter__(self):
_time_manager.enter_parallel() _time_manager.enter_parallel()
@ -340,5 +340,5 @@ def watchdog(timeout):
class TerminationRequested(Exception): class TerminationRequested(Exception):
"""Raised by ``pause`` when the user has requested termination.""" """Raised by :meth:`pause` when the user has requested termination."""
pass pass

View File

@ -28,7 +28,7 @@ class DefaultMissing(Exception):
class CancelledArgsError(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.""" arguments request is cancelled."""
pass pass
@ -117,7 +117,7 @@ class NumberValue(_SimpleArgProcessor):
``int`` will also result in an error unless these conditions are met. ``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. 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"``) 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 units set the scale to 0.001. No unit (default) corresponds to a scale of
1.0. 1.0.
@ -321,7 +321,8 @@ class HasEnvironment:
:param key: Name of the argument. :param key: Name of the argument.
:param processor: A description of how to process the argument, such :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 :param group: An optional string that defines what group the argument
belongs to, for user interface purposes. belongs to, for user interface purposes.
:param tooltip: An optional string to describe the argument in more :param tooltip: An optional string to describe the argument in more
@ -347,7 +348,8 @@ class HasEnvironment:
"""Request arguments from the user interactively. """Request arguments from the user interactively.
This context manager returns a namespace object on which the method 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 When the context manager terminates, the experiment is blocked
and the user is presented with the requested argument widgets. and the user is presented with the requested argument widgets.
@ -355,7 +357,7 @@ class HasEnvironment:
the namespace contains the values of the arguments. the namespace contains the values of the arguments.
If the interactive arguments request is cancelled, raises If the interactive arguments request is cancelled, raises
``CancelledArgsError``.""" :exc:`~artiq.language.environment.CancelledArgsError`."""
interactive_arglist = [] interactive_arglist = []
namespace = SimpleNamespace() namespace = SimpleNamespace()
def setattr_argument(key, processor=None, group=None, tooltip=None): 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. 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: try:
return self.__dataset_mgr.get_metadata(key) return self.__dataset_mgr.get_metadata(key)

View File

@ -1,20 +1,6 @@
""" """
Implementation and management of scan objects. 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 import random
@ -32,6 +18,21 @@ __all__ = ["ScanObject",
class 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): def __iter__(self):
raise NotImplementedError raise NotImplementedError
@ -163,7 +164,7 @@ class Scannable:
takes a scan object. takes a scan object.
When ``scale`` is not specified, and the unit is a common one (i.e. 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"``) 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 units set the scale to 0.001. No unit (default) corresponds to a scale of
1.0. 1.0.

View File

@ -477,16 +477,16 @@ class Scheduler:
return self.notifier.raw_view return self.notifier.raw_view
def check_pause(self, rid): 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). not return immediately (termination requested or higher priority run).
The typical purpose of this function is to check from a kernel The typical purpose of this function is to check from a kernel
whether returning control to the host and pausing would have an effect, 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 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 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(): for pipeline in self._pipelines.values():
if rid in pipeline.pool.runs: if rid in pipeline.pool.runs:

View File

@ -96,19 +96,19 @@ When using multiple pipelines it is the responsibility of the user to ensure tha
Pauses Pauses
^^^^^^ ^^^^^^
In the run stage, an experiment may yield to the scheduler by calling the ``pause()`` method of the scheduler. 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 ``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`. 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 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. 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
------------------------- -------------------------
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 .. autoclass:: artiq.applets.simple._AppletRequestInterface
:members: :members:
Applet entry area Applet entry area
----------------- -----------------
Argument widgets can be used in applets through 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: ::
Below is a simple example code snippet using the `EntryArea` class: ::
entry_area = EntryArea() entry_area = EntryArea()
@ -159,7 +156,7 @@ Below is a simple example code snippet using the `EntryArea` class: ::
# False # False
print(entry_area.bl) 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 .. 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. attribute are the same.
:param name: Argument name :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 group: Used to group together arguments in the GUI under a common category
:param tooltip: Tooltip displayed when hovering over the entry widget :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() .. 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) .. 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. 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 name: Argument name
:param value: Object representing the new value of the argument. For ``Scannable`` arguments, this parameter :param value: Object representing the new value of the argument. For :class:`~artiq.language.scan.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. 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) .. 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. :param values: Dictionary with names as keys and new argument values as values.