forked from M-Labs/artiq
doc: Formatting and link fixes in docstrings
This commit is contained in:
parent
0e1b29c5d9
commit
a4bfb0d5dd
|
@ -24,21 +24,21 @@ class _AppletRequestInterface:
|
||||||
def set_dataset(self, key, value, unit=None, scale=None, precision=None, persist=None):
|
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
|
||||||
|
|
||||||
|
|
|
@ -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) - (
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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"):
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
@ -327,10 +327,9 @@ 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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue