From 3a6ed63f0a343ab545878db54879141ba6824746 Mon Sep 17 00:00:00 2001 From: occheung Date: Fri, 22 Jul 2022 17:46:35 +0800 Subject: [PATCH] 2118-2128: add RTIO constraint --- 2118-2128.tex | 44 ++++++++++++++++++++++++--------------- examples/ttl.py | 28 ------------------------- examples/ttl_in.py | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 44 deletions(-) create mode 100644 examples/ttl_in.py diff --git a/2118-2128.tex b/2118-2128.tex index 0a4d068..fd4ee79 100644 --- a/2118-2128.tex +++ b/2118-2128.tex @@ -559,32 +559,43 @@ Timing accuracy in the examples below is well under 1 nanosecond thanks to the A The channel should be configured as output in both the gateware and hardware. \inputcolorboxminted{firstline=9,lastline=14}{examples/ttl.py} +\subsection{Morse code} +This example demonstrates some basic algorithmic features of the ARTIQ-Python language. +\inputcolorboxminted{firstline=22,lastline=39}{examples/ttl.py} + +\newpage \subsection{Sub-coarse-RTIO-cycle pulse} With the use of the ARTIQ RTIO, only 1 event can be enqueued per coarse RTIO cycle, which is typically 8ns. Therefore, to emit a pulse that is less than 8ns, additional delay is needed such that the \texttt{ttl.on()} \& \texttt{ttl.off()} event are submitted at different coarse RTIO cycles. The TTL pulse must satisfy the minimum pulse width stated in the electircal specifications. -\inputcolorboxminted{firstline=88,lastline=92}{examples/ttl.py} +\inputcolorboxminted{firstline=60,lastline=64}{examples/ttl.py} + +\subsection{Edge counting in a 1ms window} +The \texttt{TTLInOut} class implements \texttt{gate\char`_rising()}, \texttt{gate\char`_falling()} \& \texttt{gate\char`_both()} for rising edge, falling edge, both rising edge \& falling edge detection respectively. +The channel should be configured as input in both the gateware and hardware. Invoke one of the 3 methods to start edge detection. +\inputcolorboxminted{firstline=14,lastline=15}{examples/ttl_in.py} +Input signal can generated from another TTL channel or from other sources. Manipulate the timeline cursor to generate TTL pulses using the same kernel. +\inputcolorboxminted{firstline=10,lastline=22}{examples/ttl_in.py} +The detected edges are registered to the RTIO input FIFO. By default, the FIFO can hold 64 events. The FIFO depth is defined by the \texttt{ififo\char`_depth} parameter for \texttt{Channel} class in \texttt{rtio/channel.py}. +Once the threshold is exceeded, an \texttt{RTIOOverflow} exception will be triggered when the input events are read by the kernel CPU. +Finally, invoke \texttt{count()} to retrieve the edge count from the input gate. + +The RTIO system can report at most 1 edge detection event for every coarse RTIO cycle. +For example, to guarantee all rising edges are counted (with \texttt{gate\char`_rising()} invoked), the theoretical minimum separation between rising edges is 1 coarse RTIO cycle (typically 8 ns) with consideration of the RTIO specification alone. +However, both the electircal specifications and the possibility of triggering \texttt{RTIOOverflow} should be considered. \newpage -\subsection{Morse code} -This example demonstrates some basic algorithmic features of the ARTIQ-Python language. -\inputcolorboxminted{firstline=22,lastline=39}{examples/ttl.py} - -\subsection{Counting rising edges in a 1ms window} -The channel should be configured as input in both the gateware and hardware. -\inputcolorboxminted{firstline=47,lastline=52}{examples/ttl.py} - -This example code uses the software counter, which has a maximum count rate of approximately 1 million events per second. +\subsection{Edge counting using \texttt{EdgeCounter}} +This example code uses the gateware counter to substitute the software counter, which has a maximum count rate of approximately 1 million events per second. If the gateware counter is enabled on the TTL channel, it can typically count up to 125 million events per second: -\inputcolorboxminted{firstline=60,lastline=65}{examples/ttl.py} +\inputcolorboxminted{firstline=31,lastline=36}{examples/ttl_in.py} +Edges are detected by comparing the current input state and that of the previous coarse RTIO cycle. +Therefore, the theoretical minimum separation between 2 opposite edges is 1 coarse RTIO cycle (typically 8 ns). -To count falling edges or both rising \& falling edges, use \texttt{gate\char`_falling()} or \texttt{gate\char`_both()}. - -\newpage \subsection{Responding to an external trigger} One channel needs to be configured as input, and the other as output. -\inputcolorboxminted{firstline=74,lastline=80}{examples/ttl.py} +\inputcolorboxminted{firstline=45,lastline=51}{examples/ttl_in.py} \subsection{62.5 MHz clock signal generation} A TTL channel can be configured as a \texttt{ClockGen} channel, which generates a periodic clock signal. @@ -592,7 +603,8 @@ Each channel has a phase accumulator operating on the RTIO clock, where it is in Therefore, jitter should be expected when the desired frequency cannot be obtained by dividing the coarse RTIO clock frequency with a power of 2. \\ Typically, with the coarse RTIO clock at 125 MHz, a \texttt{ClockGen} channel can generate up to 62.5 MHz. -\inputcolorboxminted{firstline=100,lastline=103}{examples/ttl.py} + +\inputcolorboxminted{firstline=72,lastline=75}{examples/ttl.py} \section{Ordering Information} To order, please visit \url{https://m-labs.hk} and select the 2118 BNC-TTL/2128 SMA-TTL in the ARTIQ Sinara crate configuration tool. The card may also be ordered separately by writing to \url{mailto:sales@m-labs.hk}. diff --git a/examples/ttl.py b/examples/ttl.py index c86ad50..29274d5 100644 --- a/examples/ttl.py +++ b/examples/ttl.py @@ -52,34 +52,6 @@ class SoftwareEdgeCount(EnvExperiment): print(counts) -class EdgeCounter(EnvExperiment): - def build(self): - self.setattr_device("core") - self.edgecounter0 = self.get_device("ttl0_counter") - - @kernel - def run(self): - self.core.reset() - self.edgecounter0.gate_rising(1*ms) - counts = self.edgecounter0.fetch_count() - print(counts) - - -class ExternalTrigger(EnvExperiment): - def build(self): - self.setattr_device("core") - self.ttlin = self.get_device("ttl0") - self.ttlout = self.get_device("ttl4") - - @kernel - def run(self): - self.core.reset() - gate_end_mu = self.ttlin.gate_rising(5*ms) - timestamp_mu = self.ttlin.timestamp_mu(gate_end_mu) - at_mu(timestamp_mu + self.core.seconds_to_mu(10*ms)) - self.ttlout.pulse(1*us) - - class ShortPulse(EnvExperiment): def build(self): self.setattr_device("core") diff --git a/examples/ttl_in.py b/examples/ttl_in.py new file mode 100644 index 0000000..b9ece47 --- /dev/null +++ b/examples/ttl_in.py @@ -0,0 +1,51 @@ +from artiq.experiment import * + + +class SoftwareEdgeCount(EnvExperiment): + def build(self): + self.setattr_device("core") + self.ttlin = self.get_device("ttl0") + self.ttlout = self.get_device("ttl7") + + @kernel + def run(self): + self.core.reset() + gate_start_mu = now_mu() + # Start input gate & advance timeline cursor to gate_end_mu + gate_end_mu = self.ttlin.gate_rising(1*ms) + at_mu(gate_start_mu) + + for _ in range(64): + self.ttlout.pulse(8*ns) + delay(8*ns) + + counts = self.ttlin.count(gate_end_mu) + print(counts) + + +class EdgeCounter(EnvExperiment): + def build(self): + self.setattr_device("core") + self.edgecounter0 = self.get_device("ttl0_counter") + + @kernel + def run(self): + self.core.reset() + self.edgecounter0.gate_rising(1*ms) + counts = self.edgecounter0.fetch_count() + print(counts) + + +class ExternalTrigger(EnvExperiment): + def build(self): + self.setattr_device("core") + self.ttlin = self.get_device("ttl0") + self.ttlout = self.get_device("ttl4") + + @kernel + def run(self): + self.core.reset() + gate_end_mu = self.ttlin.gate_rising(5*ms) + timestamp_mu = self.ttlin.timestamp_mu(gate_end_mu) + at_mu(timestamp_mu + self.core.seconds_to_mu(10*ms)) + self.ttlout.pulse(1*us)