forked from M-Labs/artiq
parent
a42f774440
commit
22506e849f
|
@ -17,13 +17,13 @@ COEFF_SHIFT = 11
|
||||||
|
|
||||||
@portable
|
@portable
|
||||||
def y_mu_to_full_scale(y):
|
def y_mu_to_full_scale(y):
|
||||||
"""Convert Servo Y data from machine units to units of full scale."""
|
"""Convert servo Y data from machine units to units of full scale."""
|
||||||
return y*(1./(1 << COEFF_WIDTH - 1))
|
return y*(1./(1 << COEFF_WIDTH - 1))
|
||||||
|
|
||||||
|
|
||||||
@portable
|
@portable
|
||||||
def adc_mu_to_volts(x, gain):
|
def adc_mu_to_volts(x, gain):
|
||||||
"""Convert Servo ADC data from machine units to Volt."""
|
"""Convert servo ADC data from machine units to Volt."""
|
||||||
val = (x >> 1) & 0xffff
|
val = (x >> 1) & 0xffff
|
||||||
mask = 1 << 15
|
mask = 1 << 15
|
||||||
val = -(val & mask) + (val & ~mask)
|
val = -(val & mask) + (val & ~mask)
|
||||||
|
@ -36,20 +36,21 @@ class SUServo:
|
||||||
Sampler-Urukul Servo is a integrated device controlling one
|
Sampler-Urukul Servo is a integrated device controlling one
|
||||||
8-channel ADC (Sampler) and two 4-channel DDS (Urukuls) with a DSP engine
|
8-channel ADC (Sampler) and two 4-channel DDS (Urukuls) with a DSP engine
|
||||||
connecting the ADC data and the DDS output amplitudes to enable
|
connecting the ADC data and the DDS output amplitudes to enable
|
||||||
feedback. SUServo can for example be used to implement intensity
|
feedback. SU Servo can for example be used to implement intensity
|
||||||
stabilization of laser beams with an AOM and a photodetector.
|
stabilization of laser beams with an amplifier and AOM driven by Urukul
|
||||||
|
and a photodetector connected to Sampler.
|
||||||
|
|
||||||
Additionally SUServo supports multiple preconfigured profiles per channel
|
Additionally SU Servo supports multiple preconfigured profiles per channel
|
||||||
and features like automatic integrator hold.
|
and features like automatic integrator hold.
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
|
|
||||||
* See the SUServo variant of the Kasli target for an example of how to
|
* See the SU Servo variant of the Kasli target for an example of how to
|
||||||
connect the gateware and the devices. Sampler and each Urukul need
|
connect the gateware and the devices. Sampler and each Urukul need
|
||||||
two EEM connections.
|
two EEM connections.
|
||||||
* Ensure that both Urukuls are AD9910 variants and have the on-board
|
* Ensure that both Urukuls are AD9910 variants and have the on-board
|
||||||
dip switches set to 1100 (first two on, last two off).
|
dip switches set to 1100 (first two on, last two off).
|
||||||
* Refer to the Sampler and Urukul documentation and the SUServo
|
* Refer to the Sampler and Urukul documentation and the SU Servo
|
||||||
example device database for runtime configuration of the devices
|
example device database for runtime configuration of the devices
|
||||||
(PLLs, gains, clock routing etc.)
|
(PLLs, gains, clock routing etc.)
|
||||||
|
|
||||||
|
@ -89,9 +90,10 @@ class SUServo:
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def init(self):
|
def init(self):
|
||||||
"""Initialize the Servo, Sampler and both Urukuls.
|
"""Initialize the servo, Sampler and both Urukuls.
|
||||||
|
|
||||||
Leaves the Servo disabled (see :meth:`set_config`), resets all DDS.
|
Leaves the servo disabled (see :meth:`set_config`), resets and
|
||||||
|
configures all DDS.
|
||||||
|
|
||||||
Urukul initialization is performed blindly as there is no readback from
|
Urukul initialization is performed blindly as there is no readback from
|
||||||
the DDS or the CPLDs.
|
the DDS or the CPLDs.
|
||||||
|
@ -120,7 +122,7 @@ class SUServo:
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def write(self, addr, value):
|
def write(self, addr, value):
|
||||||
"""Write to Servo memory.
|
"""Write to servo memory.
|
||||||
|
|
||||||
This method advances the timeline by one coarse RTIO cycle.
|
This method advances the timeline by one coarse RTIO cycle.
|
||||||
|
|
||||||
|
@ -132,7 +134,7 @@ class SUServo:
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def read(self, addr):
|
def read(self, addr):
|
||||||
"""Read from Servo memory.
|
"""Read from servo memory.
|
||||||
|
|
||||||
This method does not advance the timeline but consumes all slack.
|
This method does not advance the timeline but consumes all slack.
|
||||||
|
|
||||||
|
@ -145,14 +147,16 @@ class SUServo:
|
||||||
def set_config(self, enable):
|
def set_config(self, enable):
|
||||||
"""Set SU Servo configuration.
|
"""Set SU Servo configuration.
|
||||||
|
|
||||||
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 enable (int): Enable servo operation. Enabling starts servo
|
||||||
iterations beginning with the ADC sampling stage. This also
|
iterations beginning with the ADC sampling stage. The first DDS
|
||||||
provides a mean for synchronization of Servo updates to other RTIO
|
update will happen about two servo cycles (~2.3 µs) after enabling
|
||||||
activity.
|
the servo. The delay is deterministic.
|
||||||
Disabling takes up to 2 Servo cycles (~2.2 µs) to clear the
|
This also provides a mean for synchronization of servo updates to
|
||||||
|
other RTIO activity.
|
||||||
|
Disabling takes up to two servo cycles (~2.3 µs) to clear the
|
||||||
processing pipeline.
|
processing pipeline.
|
||||||
"""
|
"""
|
||||||
self.write(CONFIG_ADDR, enable)
|
self.write(CONFIG_ADDR, enable)
|
||||||
|
@ -163,8 +167,8 @@ class SUServo:
|
||||||
|
|
||||||
This method does not advance the timeline but consumes all slack.
|
This method does not advance the timeline but consumes all slack.
|
||||||
|
|
||||||
The ``done`` bit indicates that a SUServo cycle has completed.
|
The ``done`` bit indicates that a SU Servo cycle has completed.
|
||||||
It is pulsed for one RTIO cycle every SUServo cycle and asserted
|
It is pulsed for one RTIO cycle every SU Servo cycle and asserted
|
||||||
continuously when the servo is not ``enabled`` and the pipeline has
|
continuously when the servo is not ``enabled`` and the pipeline has
|
||||||
drained (the last DDS update is done).
|
drained (the last DDS update is done).
|
||||||
|
|
||||||
|
@ -246,10 +250,13 @@ class Channel:
|
||||||
def set(self, en_out, en_iir=0, profile=0):
|
def set(self, en_out, en_iir=0, profile=0):
|
||||||
"""Operate channel.
|
"""Operate channel.
|
||||||
|
|
||||||
This method does not advance the timeline.
|
This method does not advance the timeline. Output RF switch setting
|
||||||
Output RF switch setting takes effect immediately.
|
takes effect immediately and is independent of any other activity
|
||||||
IIR updates take place once the RF switch has been enabled for the
|
(profile settings, other channels). The RF switch behaves like
|
||||||
configured delay and the profile setting has been stable.
|
``TTLOut``. RTIO event replacement is supported. IIR updates take place
|
||||||
|
once the RF switch has been enabled for the configured delay and the
|
||||||
|
profile setting has been stable. Profile changes take between one and
|
||||||
|
two servo cycles to reach the DDS.
|
||||||
|
|
||||||
:param en_out: RF switch enable
|
:param en_out: RF switch enable
|
||||||
:param en_iir: IIR updates enable
|
:param en_iir: IIR updates enable
|
||||||
|
@ -279,7 +286,7 @@ class Channel:
|
||||||
def set_dds(self, profile, frequency, offset, phase=0.):
|
def set_dds(self, profile, frequency, offset, phase=0.):
|
||||||
"""Set profile DDS coefficients.
|
"""Set profile DDS coefficients.
|
||||||
|
|
||||||
This method advances the timeline by four Servo memory accesses.
|
This method advances the timeline by four servo memory accesses.
|
||||||
Profile parameter changes are not synchronized. Activate a different
|
Profile parameter changes are not synchronized. Activate a different
|
||||||
profile or stop the servo to ensure synchronous changes.
|
profile or stop the servo to ensure synchronous changes.
|
||||||
|
|
||||||
|
@ -332,7 +339,7 @@ class Channel:
|
||||||
: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).
|
||||||
"""
|
"""
|
||||||
base = (self.servo_channel << 8) | (profile << 3)
|
base = (self.servo_channel << 8) | (profile << 3)
|
||||||
self.servo.write(base + 3, adc | (dly << 8))
|
self.servo.write(base + 3, adc | (dly << 8))
|
||||||
|
@ -344,7 +351,7 @@ class Channel:
|
||||||
def set_iir(self, profile, adc, gain, corner=0., limit=0., delay=0.):
|
def set_iir(self, profile, adc, gain, corner=0., limit=0., delay=0.):
|
||||||
"""Set profile IIR coefficients.
|
"""Set profile IIR coefficients.
|
||||||
|
|
||||||
This method advances the timeline by four Servo memory accesses.
|
This method advances the timeline by four servo memory accesses.
|
||||||
Profile parameter changes are not synchronized. Activate a different
|
Profile parameter changes are not synchronized. Activate a different
|
||||||
profile or stop the servo to ensure synchronous changes.
|
profile or stop the servo to ensure synchronous changes.
|
||||||
|
|
||||||
|
@ -374,7 +381,12 @@ class Channel:
|
||||||
:param limit: Integrator gain limit (1). When 0 (the default) the
|
:param limit: Integrator gain limit (1). When 0 (the default) the
|
||||||
integrator gain limit is infinite. Positive.
|
integrator gain limit is infinite. Positive.
|
||||||
:param delay: Delay (in seconds, 0-300 µs) before allowing IIR updates
|
:param delay: Delay (in seconds, 0-300 µs) before allowing IIR updates
|
||||||
after invoking :meth:`set`.
|
after invoking :meth:`set`. This is rounded to the nearest number
|
||||||
|
of servo cycles (~1.2 µs). Since the RF switch (:meth:`set`) can be
|
||||||
|
opened at any time relative to the servo cycle, the first DDS
|
||||||
|
update that carries updated IIR data will occur approximately
|
||||||
|
between ``delay + 1 cycle`` and ``delay + 2 cycles`` after
|
||||||
|
:meth:`set`.
|
||||||
"""
|
"""
|
||||||
B_NORM = 1 << COEFF_SHIFT + 1
|
B_NORM = 1 << COEFF_SHIFT + 1
|
||||||
A_NORM = 1 << COEFF_SHIFT
|
A_NORM = 1 << COEFF_SHIFT
|
||||||
|
@ -424,11 +436,14 @@ class Channel:
|
||||||
def get_profile_mu(self, profile, data):
|
def get_profile_mu(self, profile, data):
|
||||||
"""Retrieve profile data.
|
"""Retrieve profile data.
|
||||||
|
|
||||||
The data is returned in the `data` argument as:
|
Profile data is returned in the ``data`` argument in machine units
|
||||||
`[ftw >> 16, b1, pow, adc | (delay << 8), offset, a1, ftw, b0]`.
|
packed as: ``[ftw >> 16, b1, pow, adc | (delay << 8), offset, a1,
|
||||||
|
ftw & 0xffff, b0]``.
|
||||||
|
|
||||||
|
.. seealso:: The individual fields are described in
|
||||||
|
:meth:`set_iir_mu` and :meth:`set_dds_mu`.
|
||||||
|
|
||||||
This method advances the timeline by 32 µs and consumes all slack.
|
This method advances the timeline by 32 µs and consumes all slack.
|
||||||
Profile data is returned
|
|
||||||
|
|
||||||
:param profile: Profile number (0-31)
|
:param profile: Profile number (0-31)
|
||||||
:param data: List of 8 integers to write the profile data into
|
:param data: List of 8 integers to write the profile data into
|
||||||
|
@ -473,11 +488,11 @@ class Channel:
|
||||||
The IIR state is also know as the "integrator", or the DDS amplitude
|
The IIR state is also know as the "integrator", or the DDS amplitude
|
||||||
scale factor. It is 18 bits wide and unsigned.
|
scale factor. It is 18 bits wide and unsigned.
|
||||||
|
|
||||||
This method must not be used when the Servo
|
This method must not be used when the servo could be writing to the
|
||||||
could be writing to the same location. Either deactivate the profile,
|
same location. Either deactivate the profile, or deactivate IIR
|
||||||
or deactivate IIR updates, or disable Servo iterations.
|
updates, or disable servo iterations.
|
||||||
|
|
||||||
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
|
||||||
|
@ -493,11 +508,11 @@ class Channel:
|
||||||
The IIR state is also know as the "integrator", or the DDS amplitude
|
The IIR state is also know as the "integrator", or the DDS amplitude
|
||||||
scale factor. It is 18 bits wide and unsigned.
|
scale factor. It is 18 bits wide and unsigned.
|
||||||
|
|
||||||
This method must not be used when the Servo
|
This method must not be used when the servo could be writing to the
|
||||||
could be writing to the same location. Either deactivate the profile,
|
same location. Either deactivate the profile, or deactivate IIR
|
||||||
or deactivate IIR updates, or disable Servo iterations.
|
updates, or disable servo iterations.
|
||||||
|
|
||||||
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: IIR state in units of full scale
|
:param y: IIR state in units of full scale
|
||||||
|
|
Loading…
Reference in New Issue