suservo: clarify timings

close #1027
This commit is contained in:
Robert Jördens 2018-06-01 06:14:30 +00:00
parent a42f774440
commit 22506e849f
1 changed files with 53 additions and 38 deletions

View File

@ -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)
@ -37,7 +37,8 @@ class SUServo:
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. SU Servo 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 SU Servo 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.
@ -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)
@ -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