forked from M-Labs/artiq
ttl: Add target RTIO time argument to timestamp/count functions
Software-based tracking of timestamps is problematic (e.g. when using DMA, see GitHub #1113).
This commit is contained in:
parent
2a0e1dabfb
commit
cbdef0225c
|
@ -112,8 +112,6 @@ class TTLInOut:
|
||||||
self.core = dmgr.get(core_device)
|
self.core = dmgr.get(core_device)
|
||||||
self.channel = channel
|
self.channel = channel
|
||||||
|
|
||||||
self.i_previous_timestamp = numpy.int64(0)
|
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set_oe(self, oe):
|
def set_oe(self, oe):
|
||||||
rtio_output(now_mu(), self.channel, 1, 1 if oe else 0)
|
rtio_output(now_mu(), self.channel, 1, 1 if oe else 0)
|
||||||
|
@ -184,88 +182,112 @@ class TTLInOut:
|
||||||
@kernel
|
@kernel
|
||||||
def _set_sensitivity(self, value):
|
def _set_sensitivity(self, value):
|
||||||
rtio_output(now_mu(), self.channel, 2, value)
|
rtio_output(now_mu(), self.channel, 2, value)
|
||||||
self.i_previous_timestamp = now_mu()
|
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def gate_rising_mu(self, duration):
|
def gate_rising_mu(self, duration):
|
||||||
"""Register rising edge events for the specified duration
|
"""Register rising edge events for the specified duration
|
||||||
(in machine units).
|
(in machine units).
|
||||||
|
|
||||||
The time cursor is advanced by the specified duration."""
|
The time cursor is advanced by the specified duration.
|
||||||
|
|
||||||
|
:return: The timeline cursor at the end of the gate window.
|
||||||
|
"""
|
||||||
self._set_sensitivity(1)
|
self._set_sensitivity(1)
|
||||||
delay_mu(duration)
|
delay_mu(duration)
|
||||||
self._set_sensitivity(0)
|
self._set_sensitivity(0)
|
||||||
|
return now_mu()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def gate_falling_mu(self, duration):
|
def gate_falling_mu(self, duration):
|
||||||
"""Register falling edge events for the specified duration
|
"""Register falling edge events for the specified duration
|
||||||
(in machine units).
|
(in machine units).
|
||||||
|
|
||||||
The time cursor is advanced by the specified duration."""
|
The time cursor is advanced by the specified duration.
|
||||||
|
|
||||||
|
:return: The timeline cursor at the end of the gate window.
|
||||||
|
"""
|
||||||
self._set_sensitivity(2)
|
self._set_sensitivity(2)
|
||||||
delay_mu(duration)
|
delay_mu(duration)
|
||||||
self._set_sensitivity(0)
|
self._set_sensitivity(0)
|
||||||
|
return now_mu()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def gate_both_mu(self, duration):
|
def gate_both_mu(self, duration):
|
||||||
"""Register both rising and falling edge events for the specified
|
"""Register both rising and falling edge events for the specified
|
||||||
duration (in machine units).
|
duration (in machine units).
|
||||||
|
|
||||||
The time cursor is advanced by the specified duration."""
|
The time cursor is advanced by the specified duration.
|
||||||
|
|
||||||
|
:return: The timeline cursor at the end of the gate window.
|
||||||
|
"""
|
||||||
self._set_sensitivity(3)
|
self._set_sensitivity(3)
|
||||||
delay_mu(duration)
|
delay_mu(duration)
|
||||||
self._set_sensitivity(0)
|
self._set_sensitivity(0)
|
||||||
|
return now_mu()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def gate_rising(self, duration):
|
def gate_rising(self, duration):
|
||||||
"""Register rising edge events for the specified duration
|
"""Register rising edge events for the specified duration
|
||||||
(in seconds).
|
(in seconds).
|
||||||
|
|
||||||
The time cursor is advanced by the specified duration."""
|
The time cursor is advanced by the specified duration.
|
||||||
|
|
||||||
|
:return: The timeline cursor at the end of the gate window.
|
||||||
|
"""
|
||||||
self._set_sensitivity(1)
|
self._set_sensitivity(1)
|
||||||
delay(duration)
|
delay(duration)
|
||||||
self._set_sensitivity(0)
|
self._set_sensitivity(0)
|
||||||
|
return now_mu()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def gate_falling(self, duration):
|
def gate_falling(self, duration):
|
||||||
"""Register falling edge events for the specified duration
|
"""Register falling edge events for the specified duration
|
||||||
(in seconds).
|
(in seconds).
|
||||||
|
|
||||||
The time cursor is advanced by the specified duration."""
|
The time cursor is advanced by the specified duration.
|
||||||
|
|
||||||
|
:return: The timeline cursor at the end of the gate window.
|
||||||
|
"""
|
||||||
self._set_sensitivity(2)
|
self._set_sensitivity(2)
|
||||||
delay(duration)
|
delay(duration)
|
||||||
self._set_sensitivity(0)
|
self._set_sensitivity(0)
|
||||||
|
return now_mu()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def gate_both(self, duration):
|
def gate_both(self, duration):
|
||||||
"""Register both rising and falling edge events for the specified
|
"""Register both rising and falling edge events for the specified
|
||||||
duration (in seconds).
|
duration (in seconds).
|
||||||
|
|
||||||
The time cursor is advanced by the specified duration."""
|
The time cursor is advanced by the specified duration.
|
||||||
|
|
||||||
|
:return: The timeline cursor at the end of the gate window.
|
||||||
|
"""
|
||||||
self._set_sensitivity(3)
|
self._set_sensitivity(3)
|
||||||
delay(duration)
|
delay(duration)
|
||||||
self._set_sensitivity(0)
|
self._set_sensitivity(0)
|
||||||
|
return now_mu()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def count(self):
|
def count(self, up_to_timestamp_mu):
|
||||||
"""Poll the RTIO input during all the previously programmed gate
|
"""Poll the RTIO input up to the specified timestamp, and returns the
|
||||||
openings, and returns the number of registered events.
|
number of registered events.
|
||||||
|
|
||||||
This function does not interact with the time cursor."""
|
This function does not interact with the timeline cursor."""
|
||||||
count = 0
|
count = 0
|
||||||
while rtio_input_timestamp(self.i_previous_timestamp, self.channel) >= 0:
|
while rtio_input_timestamp(up_to_timestamp_mu, self.channel) >= 0:
|
||||||
count += 1
|
count += 1
|
||||||
return count
|
return count
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def timestamp_mu(self):
|
def timestamp_mu(self, up_to_timestamp_mu):
|
||||||
"""Poll the RTIO input and returns an event timestamp (in machine
|
"""Poll the RTIO input and returns an event timestamp (in machine
|
||||||
units), according to the gating.
|
units) according to the selected gates, or -1 if no event occured before
|
||||||
|
the specified timestamp.
|
||||||
|
|
||||||
If the gate is permanently closed, returns a negative value.
|
If the gate is permanently closed, returns a negative value.
|
||||||
|
|
||||||
This function does not interact with the time cursor."""
|
This function does not interact with the timeline cursor."""
|
||||||
return rtio_input_timestamp(self.i_previous_timestamp, self.channel)
|
return rtio_input_timestamp(up_to_timestamp_mu, self.channel)
|
||||||
|
|
||||||
# Input API: sampling
|
# Input API: sampling
|
||||||
@kernel
|
@kernel
|
||||||
|
|
|
@ -152,7 +152,7 @@ class KasliTester(EnvExperiment):
|
||||||
for _ in range(n):
|
for _ in range(n):
|
||||||
ttl_out.pulse(2*us)
|
ttl_out.pulse(2*us)
|
||||||
delay(2*us)
|
delay(2*us)
|
||||||
return ttl_in.count() == n
|
return ttl_in.count(now_mu()) == n
|
||||||
|
|
||||||
def test_ttl_ins(self):
|
def test_ttl_ins(self):
|
||||||
print("*** Testing TTL inputs.")
|
print("*** Testing TTL inputs.")
|
||||||
|
|
|
@ -38,13 +38,13 @@ class PhotonHistogram(EnvExperiment):
|
||||||
self.bd_dds.set(self.detect_f)
|
self.bd_dds.set(self.detect_f)
|
||||||
with parallel:
|
with parallel:
|
||||||
self.bd_sw.pulse(self.detect_t)
|
self.bd_sw.pulse(self.detect_t)
|
||||||
self.pmt.gate_rising(self.detect_t)
|
gate_end_mu = self.pmt.gate_rising(self.detect_t)
|
||||||
|
|
||||||
self.program_cooling()
|
self.program_cooling()
|
||||||
self.bd_sw.on()
|
self.bd_sw.on()
|
||||||
self.bdd_sw.on()
|
self.bdd_sw.on()
|
||||||
|
|
||||||
return self.pmt.count()
|
return self.pmt.count(gate_end_mu)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
|
@ -66,8 +66,8 @@ class TDR(EnvExperiment):
|
||||||
self.pmt0.gate_both_mu(2*p)
|
self.pmt0.gate_both_mu(2*p)
|
||||||
self.ttl2.pulse_mu(p)
|
self.ttl2.pulse_mu(p)
|
||||||
for i in range(len(self.t)):
|
for i in range(len(self.t)):
|
||||||
ti = self.pmt0.timestamp_mu()
|
ti = self.pmt0.timestamp_mu(now_mu())
|
||||||
if ti <= 0:
|
if ti <= 0:
|
||||||
raise PulseNotReceivedError()
|
raise PulseNotReceivedError()
|
||||||
self.t[i] = int(self.t[i] + ti - t0)
|
self.t[i] = int(self.t[i] + ti - t0)
|
||||||
self.pmt0.count() # flush
|
self.pmt0.count(now_mu()) # flush
|
||||||
|
|
|
@ -21,7 +21,7 @@ class AluminumSpectroscopy(EnvExperiment):
|
||||||
state_0_count = 0
|
state_0_count = 0
|
||||||
for count in range(100):
|
for count in range(100):
|
||||||
self.mains_sync.gate_rising(1*s/60)
|
self.mains_sync.gate_rising(1*s/60)
|
||||||
at_mu(self.mains_sync.timestamp_mu() + 100*us)
|
at_mu(self.mains_sync.timestamp_mu(now_mu()) + 100*us)
|
||||||
delay(10*us)
|
delay(10*us)
|
||||||
self.laser_cooling.pulse(100*MHz, 100*us)
|
self.laser_cooling.pulse(100*MHz, 100*us)
|
||||||
delay(5*us)
|
delay(5*us)
|
||||||
|
@ -35,8 +35,7 @@ class AluminumSpectroscopy(EnvExperiment):
|
||||||
delay(5*us)
|
delay(5*us)
|
||||||
with parallel:
|
with parallel:
|
||||||
self.state_detection.pulse(100*MHz, 10*us)
|
self.state_detection.pulse(100*MHz, 10*us)
|
||||||
self.pmt.gate_rising(10*us)
|
photon_count = self.pmt.count(self.pmt.gate_rising(10*us))
|
||||||
photon_count = self.pmt.count()
|
|
||||||
if (photon_count < self.photon_limit_low or
|
if (photon_count < self.photon_limit_low or
|
||||||
photon_count > self.photon_limit_high):
|
photon_count > self.photon_limit_high):
|
||||||
break
|
break
|
||||||
|
|
|
@ -49,13 +49,13 @@ class Input:
|
||||||
delay(duration)
|
delay(duration)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def count(self):
|
def count(self, up_to_timestamp_mu):
|
||||||
result = self.prng.randrange(0, 100)
|
result = self.prng.randrange(0, 100)
|
||||||
time.manager.event(("count", self.name, result))
|
time.manager.event(("count", self.name, result))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def timestamp_mu(self):
|
def timestamp_mu(self, up_to_timestamp_mu):
|
||||||
result = time.manager.get_time_mu()
|
result = time.manager.get_time_mu()
|
||||||
result += self.prng.randrange(100, 1000)
|
result += self.prng.randrange(100, 1000)
|
||||||
time.manager.event(("timestamp_mu", self.name, result))
|
time.manager.event(("timestamp_mu", self.name, result))
|
||||||
|
|
|
@ -21,11 +21,10 @@ class CreateTTLPulse(EnvExperiment):
|
||||||
def run(self):
|
def run(self):
|
||||||
self.core.break_realtime()
|
self.core.break_realtime()
|
||||||
with parallel:
|
with parallel:
|
||||||
self.loop_in.gate_both_mu(1200)
|
|
||||||
with sequential:
|
with sequential:
|
||||||
delay_mu(100)
|
delay_mu(100)
|
||||||
self.loop_out.pulse_mu(1000)
|
self.loop_out.pulse_mu(1000)
|
||||||
self.loop_in.count()
|
self.loop_in.count(self.loop_in.gate_both_mu(1200))
|
||||||
|
|
||||||
|
|
||||||
class WriteLog(EnvExperiment):
|
class WriteLog(EnvExperiment):
|
||||||
|
|
|
@ -68,7 +68,7 @@ class RTT(EnvExperiment):
|
||||||
delay(1*us)
|
delay(1*us)
|
||||||
t0 = now_mu()
|
t0 = now_mu()
|
||||||
self.ttl_inout.pulse(1*us)
|
self.ttl_inout.pulse(1*us)
|
||||||
t1 = self.ttl_inout.timestamp_mu()
|
t1 = self.ttl_inout.timestamp_mu(now_mu())
|
||||||
if t1 < 0:
|
if t1 < 0:
|
||||||
raise PulseNotReceived()
|
raise PulseNotReceived()
|
||||||
self.set_dataset("rtt", self.core.mu_to_seconds(t1 - t0))
|
self.set_dataset("rtt", self.core.mu_to_seconds(t1 - t0))
|
||||||
|
@ -92,7 +92,7 @@ class Loopback(EnvExperiment):
|
||||||
delay(1*us)
|
delay(1*us)
|
||||||
t0 = now_mu()
|
t0 = now_mu()
|
||||||
self.loop_out.pulse(1*us)
|
self.loop_out.pulse(1*us)
|
||||||
t1 = self.loop_in.timestamp_mu()
|
t1 = self.loop_in.timestamp_mu(now_mu())
|
||||||
if t1 < 0:
|
if t1 < 0:
|
||||||
raise PulseNotReceived()
|
raise PulseNotReceived()
|
||||||
self.set_dataset("rtt", self.core.mu_to_seconds(t1 - t0))
|
self.set_dataset("rtt", self.core.mu_to_seconds(t1 - t0))
|
||||||
|
@ -115,7 +115,7 @@ class ClockGeneratorLoopback(EnvExperiment):
|
||||||
with sequential:
|
with sequential:
|
||||||
delay(200*ns)
|
delay(200*ns)
|
||||||
self.loop_clock_out.set(1*MHz)
|
self.loop_clock_out.set(1*MHz)
|
||||||
self.set_dataset("count", self.loop_clock_in.count())
|
self.set_dataset("count", self.loop_clock_in.count(now_mu()))
|
||||||
|
|
||||||
|
|
||||||
class PulseRate(EnvExperiment):
|
class PulseRate(EnvExperiment):
|
||||||
|
@ -203,7 +203,7 @@ class LoopbackCount(EnvExperiment):
|
||||||
for i in range(self.npulses):
|
for i in range(self.npulses):
|
||||||
delay(25*ns)
|
delay(25*ns)
|
||||||
self.loop_out.pulse(25*ns)
|
self.loop_out.pulse(25*ns)
|
||||||
self.set_dataset("count", self.loop_in.count())
|
self.set_dataset("count", self.loop_in.count(now_mu()))
|
||||||
|
|
||||||
|
|
||||||
class IncorrectLevel(Exception):
|
class IncorrectLevel(Exception):
|
||||||
|
|
|
@ -159,8 +159,7 @@ Input channels detect events, timestamp them, and place them in a buffer for the
|
||||||
The following example counts the rising edges occurring during a precisely timed 500 ns interval.
|
The following example counts the rising edges occurring during a precisely timed 500 ns interval.
|
||||||
If more than 20 rising edges were received it outputs a pulse::
|
If more than 20 rising edges were received it outputs a pulse::
|
||||||
|
|
||||||
input.gate_rising(500*ns)
|
if input.count(input.gate_rising(500*ns)) > 20:
|
||||||
if input.count() > 20:
|
|
||||||
delay(2*us)
|
delay(2*us)
|
||||||
output.pulse(500*ns)
|
output.pulse(500*ns)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue