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)
@ -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