forked from M-Labs/artiq
coredevice/ttl: port to NAC3
This commit is contained in:
parent
deb8a77464
commit
2f031285a4
|
@ -6,10 +6,10 @@ replacement. For example, pulses of "zero" length (e.g. :meth:`TTLInOut.on`
|
||||||
immediately followed by :meth:`TTLInOut.off`, without a delay) are suppressed.
|
immediately followed by :meth:`TTLInOut.off`, without a delay) are suppressed.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import numpy
|
from numpy import int32, int64
|
||||||
|
|
||||||
from artiq.language.core import *
|
from artiq.language.core import *
|
||||||
from artiq.language.types import *
|
from artiq.coredevice.core import Core
|
||||||
from artiq.coredevice.rtio import (rtio_output, rtio_input_timestamp,
|
from artiq.coredevice.rtio import (rtio_output, rtio_input_timestamp,
|
||||||
rtio_input_data)
|
rtio_input_data)
|
||||||
from artiq.coredevice.exceptions import RTIOOverflow
|
from artiq.coredevice.exceptions import RTIOOverflow
|
||||||
|
@ -22,6 +22,7 @@ from artiq.coredevice.exceptions import RTIOOverflow
|
||||||
# 3 Set input sensitivity and sample
|
# 3 Set input sensitivity and sample
|
||||||
|
|
||||||
|
|
||||||
|
@nac3
|
||||||
class TTLOut:
|
class TTLOut:
|
||||||
"""RTIO TTL output driver.
|
"""RTIO TTL output driver.
|
||||||
|
|
||||||
|
@ -29,7 +30,9 @@ class TTLOut:
|
||||||
|
|
||||||
:param channel: channel number
|
:param channel: channel number
|
||||||
"""
|
"""
|
||||||
kernel_invariants = {"core", "channel", "target_o"}
|
core: KernelInvariant[Core]
|
||||||
|
channel: KernelInvariant[int32]
|
||||||
|
target_o: KernelInvariant[int32]
|
||||||
|
|
||||||
def __init__(self, dmgr, channel, core_device="core"):
|
def __init__(self, dmgr, channel, core_device="core"):
|
||||||
self.core = dmgr.get(core_device)
|
self.core = dmgr.get(core_device)
|
||||||
|
@ -41,7 +44,7 @@ class TTLOut:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set_o(self, o):
|
def set_o(self, o: bool):
|
||||||
rtio_output(self.target_o, 1 if o else 0)
|
rtio_output(self.target_o, 1 if o else 0)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
|
@ -61,7 +64,7 @@ class TTLOut:
|
||||||
self.set_o(False)
|
self.set_o(False)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def pulse_mu(self, duration):
|
def pulse_mu(self, duration: int64):
|
||||||
"""Pulse the output high for the specified duration
|
"""Pulse the output high for the specified duration
|
||||||
(in machine units).
|
(in machine units).
|
||||||
|
|
||||||
|
@ -71,16 +74,17 @@ class TTLOut:
|
||||||
self.off()
|
self.off()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def pulse(self, duration):
|
def pulse(self, duration: float):
|
||||||
"""Pulse the output high for the specified duration
|
"""Pulse the output high 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."""
|
||||||
self.on()
|
self.on()
|
||||||
delay(duration)
|
self.core.delay(duration)
|
||||||
self.off()
|
self.off()
|
||||||
|
|
||||||
|
|
||||||
|
@nac3
|
||||||
class TTLInOut:
|
class TTLInOut:
|
||||||
"""RTIO TTL input/output driver.
|
"""RTIO TTL input/output driver.
|
||||||
|
|
||||||
|
@ -107,8 +111,13 @@ class TTLInOut:
|
||||||
|
|
||||||
:param channel: channel number
|
:param channel: channel number
|
||||||
"""
|
"""
|
||||||
kernel_invariants = {"core", "channel", "gate_latency_mu",
|
core: KernelInvariant[Core]
|
||||||
"target_o", "target_oe", "target_sens", "target_sample"}
|
channel: KernelInvariant[int32]
|
||||||
|
gate_latency_mu: KernelInvariant[int32]
|
||||||
|
target_o: KernelInvariant[int32]
|
||||||
|
target_oe: KernelInvariant[int32]
|
||||||
|
target_sens: KernelInvariant[int32]
|
||||||
|
target_sample: KernelInvariant[int32]
|
||||||
|
|
||||||
def __init__(self, dmgr, channel, gate_latency_mu=None,
|
def __init__(self, dmgr, channel, gate_latency_mu=None,
|
||||||
core_device="core"):
|
core_device="core"):
|
||||||
|
@ -129,7 +138,7 @@ class TTLInOut:
|
||||||
self.target_sample = (channel << 8) + 3
|
self.target_sample = (channel << 8) + 3
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set_oe(self, oe):
|
def set_oe(self, oe: bool):
|
||||||
rtio_output(self.target_oe, 1 if oe else 0)
|
rtio_output(self.target_oe, 1 if oe else 0)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
|
@ -159,7 +168,7 @@ class TTLInOut:
|
||||||
self.set_oe(False)
|
self.set_oe(False)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set_o(self, o):
|
def set_o(self, o: bool):
|
||||||
rtio_output(self.target_o, 1 if o else 0)
|
rtio_output(self.target_o, 1 if o else 0)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
|
@ -183,7 +192,7 @@ class TTLInOut:
|
||||||
self.set_o(False)
|
self.set_o(False)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def pulse_mu(self, duration):
|
def pulse_mu(self, duration: int64):
|
||||||
"""Pulse the output high for the specified duration
|
"""Pulse the output high for the specified duration
|
||||||
(in machine units).
|
(in machine units).
|
||||||
|
|
||||||
|
@ -193,22 +202,22 @@ class TTLInOut:
|
||||||
self.off()
|
self.off()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def pulse(self, duration):
|
def pulse(self, duration: float):
|
||||||
"""Pulse the output high for the specified duration
|
"""Pulse the output high 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."""
|
||||||
self.on()
|
self.on()
|
||||||
delay(duration)
|
self.core.delay(duration)
|
||||||
self.off()
|
self.off()
|
||||||
|
|
||||||
# Input API: gating
|
# Input API: gating
|
||||||
@kernel
|
@kernel
|
||||||
def _set_sensitivity(self, value):
|
def _set_sensitivity(self, value: int32):
|
||||||
rtio_output(self.target_sens, value)
|
rtio_output(self.target_sens, value)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def gate_rising_mu(self, duration):
|
def gate_rising_mu(self, duration: int64) -> int64:
|
||||||
"""Register rising edge events for the specified duration
|
"""Register rising edge events for the specified duration
|
||||||
(in machine units).
|
(in machine units).
|
||||||
|
|
||||||
|
@ -223,7 +232,7 @@ class TTLInOut:
|
||||||
return now_mu()
|
return now_mu()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def gate_falling_mu(self, duration):
|
def gate_falling_mu(self, duration: int64) -> int64:
|
||||||
"""Register falling edge events for the specified duration
|
"""Register falling edge events for the specified duration
|
||||||
(in machine units).
|
(in machine units).
|
||||||
|
|
||||||
|
@ -238,7 +247,7 @@ class TTLInOut:
|
||||||
return now_mu()
|
return now_mu()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def gate_both_mu(self, duration):
|
def gate_both_mu(self, duration: int64) -> int64:
|
||||||
"""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).
|
||||||
|
|
||||||
|
@ -253,7 +262,7 @@ class TTLInOut:
|
||||||
return now_mu()
|
return now_mu()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def gate_rising(self, duration):
|
def gate_rising(self, duration: float) -> int64:
|
||||||
"""Register rising edge events for the specified duration
|
"""Register rising edge events for the specified duration
|
||||||
(in seconds).
|
(in seconds).
|
||||||
|
|
||||||
|
@ -263,12 +272,12 @@ class TTLInOut:
|
||||||
convenience when used with :meth:`count`/:meth:`timestamp_mu`.
|
convenience when used with :meth:`count`/:meth:`timestamp_mu`.
|
||||||
"""
|
"""
|
||||||
self._set_sensitivity(1)
|
self._set_sensitivity(1)
|
||||||
delay(duration)
|
self.core.delay(duration)
|
||||||
self._set_sensitivity(0)
|
self._set_sensitivity(0)
|
||||||
return now_mu()
|
return now_mu()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def gate_falling(self, duration):
|
def gate_falling(self, duration: float) -> int64:
|
||||||
"""Register falling edge events for the specified duration
|
"""Register falling edge events for the specified duration
|
||||||
(in seconds).
|
(in seconds).
|
||||||
|
|
||||||
|
@ -279,12 +288,12 @@ class TTLInOut:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self._set_sensitivity(2)
|
self._set_sensitivity(2)
|
||||||
delay(duration)
|
self.core.delay(duration)
|
||||||
self._set_sensitivity(0)
|
self._set_sensitivity(0)
|
||||||
return now_mu()
|
return now_mu()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def gate_both(self, duration):
|
def gate_both(self, duration: float) -> int64:
|
||||||
"""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).
|
||||||
|
|
||||||
|
@ -294,12 +303,12 @@ class TTLInOut:
|
||||||
convenience when used with :meth:`count`/:meth:`timestamp_mu`.
|
convenience when used with :meth:`count`/:meth:`timestamp_mu`.
|
||||||
"""
|
"""
|
||||||
self._set_sensitivity(3)
|
self._set_sensitivity(3)
|
||||||
delay(duration)
|
self.core.delay(duration)
|
||||||
self._set_sensitivity(0)
|
self._set_sensitivity(0)
|
||||||
return now_mu()
|
return now_mu()
|
||||||
|
|
||||||
@kernel
|
# NAC3TODO @kernel
|
||||||
def count(self, up_to_timestamp_mu):
|
def count(self, up_to_timestamp_mu: int64) -> int32:
|
||||||
"""Consume RTIO input events until the hardware timestamp counter has
|
"""Consume RTIO input events until the hardware timestamp counter has
|
||||||
reached the specified timestamp and return the number of observed
|
reached the specified timestamp and return the number of observed
|
||||||
events.
|
events.
|
||||||
|
@ -347,12 +356,12 @@ class TTLInOut:
|
||||||
ttl_input.count(ttl_input.gate_rising(100 * us))
|
ttl_input.count(ttl_input.gate_rising(100 * us))
|
||||||
"""
|
"""
|
||||||
count = 0
|
count = 0
|
||||||
while rtio_input_timestamp(up_to_timestamp_mu + self.gate_latency_mu, self.channel) >= 0:
|
while rtio_input_timestamp(up_to_timestamp_mu + int64(self.gate_latency_mu), self.channel) >= int64(0):
|
||||||
count += 1
|
count += 1
|
||||||
return count
|
return count
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def timestamp_mu(self, up_to_timestamp_mu):
|
def timestamp_mu(self, up_to_timestamp_mu: int64) -> int64:
|
||||||
"""Return the timestamp of the next RTIO input event, or -1 if the
|
"""Return the timestamp of the next RTIO input event, or -1 if the
|
||||||
hardware timestamp counter reaches the given value before an event is
|
hardware timestamp counter reaches the given value before an event is
|
||||||
received.
|
received.
|
||||||
|
@ -370,7 +379,7 @@ class TTLInOut:
|
||||||
:return: The timestamp (in machine units) of the first event received;
|
:return: The timestamp (in machine units) of the first event received;
|
||||||
-1 on timeout.
|
-1 on timeout.
|
||||||
"""
|
"""
|
||||||
return rtio_input_timestamp(up_to_timestamp_mu + self.gate_latency_mu, self.channel)
|
return rtio_input_timestamp(up_to_timestamp_mu + int64(self.gate_latency_mu), self.channel)
|
||||||
|
|
||||||
# Input API: sampling
|
# Input API: sampling
|
||||||
@kernel
|
@kernel
|
||||||
|
@ -382,7 +391,7 @@ class TTLInOut:
|
||||||
rtio_output(self.target_sample, 0)
|
rtio_output(self.target_sample, 0)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def sample_get(self):
|
def sample_get(self) -> int32:
|
||||||
"""Returns the value of a sample previously obtained with
|
"""Returns the value of a sample previously obtained with
|
||||||
:meth:`sample_input`.
|
:meth:`sample_input`.
|
||||||
|
|
||||||
|
@ -394,7 +403,7 @@ class TTLInOut:
|
||||||
return rtio_input_data(self.channel)
|
return rtio_input_data(self.channel)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def sample_get_nonrt(self):
|
def sample_get_nonrt(self) -> int32:
|
||||||
"""Convenience function that obtains the value of a sample
|
"""Convenience function that obtains the value of a sample
|
||||||
at the position of the time cursor, breaks realtime, and
|
at the position of the time cursor, breaks realtime, and
|
||||||
returns the sample value."""
|
returns the sample value."""
|
||||||
|
@ -405,7 +414,7 @@ class TTLInOut:
|
||||||
|
|
||||||
# Input API: watching
|
# Input API: watching
|
||||||
@kernel
|
@kernel
|
||||||
def watch_stay_on(self):
|
def watch_stay_on(self) -> bool:
|
||||||
"""Checks that the input is at a high level at the position
|
"""Checks that the input is at a high level at the position
|
||||||
of the time cursor and keep checking until :meth:`watch_done`
|
of the time cursor and keep checking until :meth:`watch_done`
|
||||||
is called.
|
is called.
|
||||||
|
@ -420,13 +429,13 @@ class TTLInOut:
|
||||||
return rtio_input_data(self.channel) == 1
|
return rtio_input_data(self.channel) == 1
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def watch_stay_off(self):
|
def watch_stay_off(self) -> bool:
|
||||||
"""Like :meth:`watch_stay_on`, but for low levels."""
|
"""Like :meth:`watch_stay_on`, but for low levels."""
|
||||||
rtio_output(self.target_sample, 1) # gate rising
|
rtio_output(self.target_sample, 1) # gate rising
|
||||||
return rtio_input_data(self.channel) == 0
|
return rtio_input_data(self.channel) == 0
|
||||||
|
|
||||||
@kernel
|
# NAC3TODO @kernel
|
||||||
def watch_done(self):
|
def watch_done(self) -> bool:
|
||||||
"""Stop watching the input at the position of the time cursor.
|
"""Stop watching the input at the position of the time cursor.
|
||||||
|
|
||||||
Returns ``True`` if the input has not changed state while it
|
Returns ``True`` if the input has not changed state while it
|
||||||
|
@ -438,13 +447,14 @@ class TTLInOut:
|
||||||
rtio_output(self.target_sens, 0)
|
rtio_output(self.target_sens, 0)
|
||||||
success = True
|
success = True
|
||||||
try:
|
try:
|
||||||
while rtio_input_timestamp(now_mu() + self.gate_latency_mu, self.channel) != -1:
|
while rtio_input_timestamp(now_mu() + int64(self.gate_latency_mu), self.channel) != -1:
|
||||||
success = False
|
success = False
|
||||||
except RTIOOverflow:
|
except RTIOOverflow:
|
||||||
success = False
|
success = False
|
||||||
return success
|
return success
|
||||||
|
|
||||||
|
|
||||||
|
@nac3
|
||||||
class TTLClockGen:
|
class TTLClockGen:
|
||||||
"""RTIO TTL clock generator driver.
|
"""RTIO TTL clock generator driver.
|
||||||
|
|
||||||
|
@ -456,31 +466,35 @@ class TTLClockGen:
|
||||||
:param channel: channel number
|
:param channel: channel number
|
||||||
:param acc_width: accumulator width in bits
|
:param acc_width: accumulator width in bits
|
||||||
"""
|
"""
|
||||||
kernel_invariants = {"core", "channel", "target", "acc_width"}
|
core: KernelInvariant[Core]
|
||||||
|
channel: KernelInvariant[int32]
|
||||||
|
target: KernelInvariant[int32]
|
||||||
|
acc_width: KernelInvariant[int32]
|
||||||
|
|
||||||
def __init__(self, dmgr, channel, acc_width=24, core_device="core"):
|
def __init__(self, dmgr, channel, acc_width=24, core_device="core"):
|
||||||
self.core = dmgr.get(core_device)
|
self.core = dmgr.get(core_device)
|
||||||
self.channel = channel
|
self.channel = channel
|
||||||
self.target = channel << 8
|
self.target = channel << 8
|
||||||
|
self.acc_width = acc_width
|
||||||
self.acc_width = numpy.int64(acc_width)
|
|
||||||
|
|
||||||
@portable
|
@portable
|
||||||
def frequency_to_ftw(self, frequency):
|
def frequency_to_ftw(self, frequency: float) -> int32:
|
||||||
"""Returns the frequency tuning word corresponding to the given
|
"""Returns the frequency tuning word corresponding to the given
|
||||||
frequency.
|
frequency.
|
||||||
"""
|
"""
|
||||||
return round(2**self.acc_width*frequency*self.core.coarse_ref_period)
|
# NAC3TODO return round64(2**self.acc_width*frequency*self.core.coarse_ref_period)
|
||||||
|
return 0
|
||||||
|
|
||||||
@portable
|
@portable
|
||||||
def ftw_to_frequency(self, ftw):
|
def ftw_to_frequency(self, ftw: int32) -> float:
|
||||||
"""Returns the frequency corresponding to the given frequency tuning
|
"""Returns the frequency corresponding to the given frequency tuning
|
||||||
word.
|
word.
|
||||||
"""
|
"""
|
||||||
return ftw/self.core.coarse_ref_period/2**self.acc_width
|
# NAC3TODO return float(ftw)/self.core.coarse_ref_period/2**int64(self.acc_width)
|
||||||
|
return 0.0
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set_mu(self, frequency):
|
def set_mu(self, frequency: int32):
|
||||||
"""Set the frequency of the clock, in machine units, at the current
|
"""Set the frequency of the clock, in machine units, at the current
|
||||||
position of the time cursor.
|
position of the time cursor.
|
||||||
|
|
||||||
|
@ -500,7 +514,7 @@ class TTLClockGen:
|
||||||
rtio_output(self.target, frequency)
|
rtio_output(self.target, frequency)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set(self, frequency):
|
def set(self, frequency: float):
|
||||||
"""Like :meth:`set_mu`, but using Hz."""
|
"""Like :meth:`set_mu`, but using Hz."""
|
||||||
self.set_mu(self.frequency_to_ftw(frequency))
|
self.set_mu(self.frequency_to_ftw(frequency))
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ from types import SimpleNamespace
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"KernelInvariant",
|
"KernelInvariant", "round64",
|
||||||
"extern", "kernel", "portable", "nac3", "rpc",
|
"extern", "kernel", "portable", "nac3", "rpc",
|
||||||
"parallel", "sequential",
|
"parallel", "sequential",
|
||||||
"set_watchdog_factory", "watchdog", "TerminationRequested"
|
"set_watchdog_factory", "watchdog", "TerminationRequested"
|
||||||
|
@ -21,6 +21,10 @@ class KernelInvariant(Generic[T]):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def round64(x):
|
||||||
|
return round(x)
|
||||||
|
|
||||||
|
|
||||||
_allow_module_registration = True
|
_allow_module_registration = True
|
||||||
_registered_modules = set()
|
_registered_modules = set()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue