phaser: add helpers to align updates to the RTIO timeline

Signed-off-by: Etienne Wodey <etienne.wodey@aqt.eu>
This commit is contained in:
Etienne Wodey 2021-09-01 17:39:08 +02:00
parent 11790c6d7c
commit 65f8a97b56
2 changed files with 33 additions and 1 deletions

View File

@ -18,6 +18,7 @@ Highlights:
- Improved documentation - Improved documentation
- Expose the DAC coarse mixer and ``sif_sync`` - Expose the DAC coarse mixer and ``sif_sync``
- Exposes upconverter calibration and enabling/disabling of upconverter LO & RF outputs. - Exposes upconverter calibration and enabling/disabling of upconverter LO & RF outputs.
- Add helpers to align Phaser updates to the RTIO timeline (``get_next_frame_timestamp()``)
* ``get()``, ``get_mu()``, ``get_att()``, and ``get_att_mu()`` functions added for AD9910 and AD9912 * ``get()``, ``get_mu()``, ``get_att()``, and ``get_att_mu()`` functions added for AD9910 and AD9912
* New hardware support: * New hardware support:
- HVAMP_8CH 8 channel HV amplifier for Fastino / Zotino - HVAMP_8CH 8 channel HV amplifier for Fastino / Zotino

View File

@ -1,7 +1,8 @@
from numpy import int32, int64 from numpy import int32, int64
from artiq.language.core import kernel, delay_mu, delay from artiq.language.core import kernel, delay_mu, delay
from artiq.coredevice.rtio import rtio_output, rtio_input_data from artiq.coredevice.rtio import rtio_output, rtio_input_data, rtio_input_timestamp
from artiq.coredevice.core import rtio_get_counter
from artiq.language.units import us, ns, ms, MHz from artiq.language.units import us, ns, ms, MHz
from artiq.language.types import TInt32 from artiq.language.types import TInt32
from artiq.coredevice.dac34h84 import DAC34H84 from artiq.coredevice.dac34h84 import DAC34H84
@ -160,6 +161,7 @@ class Phaser:
# self.core.seconds_to_mu(10*8*4*ns) # unfortunately this returns 319 # self.core.seconds_to_mu(10*8*4*ns) # unfortunately this returns 319
assert self.core.ref_period == 1*ns assert self.core.ref_period == 1*ns
self.t_frame = 10*8*4 self.t_frame = 10*8*4
self.frame_tstamp = int64(0)
self.clk_sel = clk_sel self.clk_sel = clk_sel
self.tune_fifo_offset = tune_fifo_offset self.tune_fifo_offset = tune_fifo_offset
self.sync_dly = sync_dly self.sync_dly = sync_dly
@ -197,6 +199,9 @@ class Phaser:
raise ValueError("large number of frame CRC errors") raise ValueError("large number of frame CRC errors")
delay(.1*ms) # slack delay(.1*ms) # slack
# determine the origin for frame-aligned timestamps
self.measure_frame_timestamp()
# reset # reset
self.set_cfg(dac_resetb=0, dac_sleep=1, dac_txena=0, self.set_cfg(dac_resetb=0, dac_sleep=1, dac_txena=0,
trf0_ps=1, trf1_ps=1, trf0_ps=1, trf1_ps=1,
@ -468,6 +473,32 @@ class Phaser:
""" """
return self.read8(PHASER_ADDR_CRC_ERR) return self.read8(PHASER_ADDR_CRC_ERR)
@kernel
def measure_frame_timestamp(self):
"""Perform a register read and record the exact frame timing in `self.frame_tstamp`.
Deterministic timing requires updates to be schedule at multiples of `self.t_frame` later.
See `get_next_frame_timestamp()`.
"""
rtio_output((self.channel_base << 8) | (PHASER_ADDR_BOARD_ID & 0x7f), 0) # can read any register
delay_mu(int64(self.t_frame))
self.frame_tstamp = rtio_input_timestamp(rtio_get_counter() + 0xffffff, self.channel_base)
delay(10*ms)
@kernel
def get_next_frame_timestamp(self, after_timestamp_mu = int64(-1)):
"""Return the RTIO timestamp of the next frame after `after_timestamp_mu`.
If `after_timestamp_mu < 0`, return the next frame after `now_mu()`.
Updates scheduled at this timestamp and multiples of `self.t_frame` later will
have deterministic latency with respect to the RTIO timeline.
"""
if after_timestamp_mu < 0:
after_timestamp_mu = now_mu()
n = int64((after_timestamp_mu - self.frame_tstamp) / self.t_frame)
return self.frame_tstamp + (n + 1) * self.t_frame
@kernel @kernel
def set_sync_dly(self, dly): def set_sync_dly(self, dly):
"""Set SYNC delay. """Set SYNC delay.