forked from M-Labs/artiq
1
0
Fork 0

doc: reST formatting

This commit is contained in:
architeuthidae 2024-08-01 12:28:59 +08:00 committed by Sébastien Bourdeauducq
parent 42b48598e5
commit ebab2c4d34
5 changed files with 92 additions and 154 deletions

View File

@ -100,19 +100,11 @@ Create a new file ``rtio.py`` containing the following: ::
delay(2*us) delay(2*us)
self.ttl0.pulse(2*us) self.ttl0.pulse(2*us)
In its :meth:`~artiq.language.environment.HasEnvironment.build` method, the experiment obtains the core device and a TTL device called ``ttl0`` as defined in the device database. In its :meth:`~artiq.language.environment.HasEnvironment.build` method, the experiment obtains the core device and a TTL device called ``ttl0`` as defined in the device database. In ARTIQ, TTL is used roughly synonymous with "a single generic digital signal" and does not refer to a specific signaling standard or voltage/current levels.
In ARTIQ, TTL is used roughly synonymous with "a single generic digital signal" and does not refer to a specific signaling standard or voltage/current levels.
When :meth:`~artiq.language.environment.Experiment.run`, the experiment first ensures that ``ttl0`` is in output mode and actively driving the device it is connected to. When :meth:`~artiq.language.environment.Experiment.run`, the experiment first ensures that ``ttl0`` is in output mode and actively driving the device it is connected to.Bidirectional TTL channels (i.e. :class:`~artiq.coredevice.ttl.TTLInOut`) are in input (high impedance) mode by default, output-only TTL channels (:class:`~artiq.coredevice.ttl.TTLOut`) are always in output mode. There are no input-only TTL channels.
Bidirectional TTL channels (i.e. :class:`~artiq.coredevice.ttl.TTLInOut`) are in input (high impedance) mode by default, output-only TTL channels (:class:`~artiq.coredevice.ttl.TTLOut`) are always in output mode.
There are no input-only TTL channels.
The experiment then drives one million 2 µs long pulses separated by 2 µs each. The experiment then drives one million 2 µs long pulses separated by 2 µs each. Connect an oscilloscope or logic analyzer to TTL0 and run ``artiq_run rtio.py``. Notice that the generated signal's period is precisely 4 µs, and that it has a duty cycle of precisely 50%. This is not what one would expect if the delay and the pulse were implemented with register-based general purpose input output (GPIO) that is CPU-controlled. The signal's period would depend on CPU speed, and overhead from the loop, memory management, function calls, etc., all of which are hard to predict and variable. Any asymmetry in the overhead would manifest itself in a distorted and variable duty cycle.
Connect an oscilloscope or logic analyzer to TTL0 and run ``artiq_run rtio.py``.
Notice that the generated signal's period is precisely 4 µs, and that it has a duty cycle of precisely 50%.
This is not what one would expect if the delay and the pulse were implemented with register-based general purpose input output (GPIO) that is CPU-controlled.
The signal's period would depend on CPU speed, and overhead from the loop, memory management, function calls, etc., all of which are hard to predict and variable.
Any asymmetry in the overhead would manifest itself in a distorted and variable duty cycle.
Instead, inside the core device, output timing is generated by the gateware and the CPU only programs switching commands with certain timestamps that the CPU computes. Instead, inside the core device, output timing is generated by the gateware and the CPU only programs switching commands with certain timestamps that the CPU computes.
@ -166,11 +158,7 @@ Try the following code and observe the generated pulses on a 2-channel oscillosc
self.ttl1.pulse(4*us) self.ttl1.pulse(4*us)
delay(4*us) delay(4*us)
ARTIQ can implement ``with parallel`` blocks without having to resort to any of the typical parallel processing approaches. ARTIQ can implement ``with parallel`` blocks without having to resort to any of the typical parallel processing approaches. It simply remembers its position on the timeline (``now_mu``) when entering the ``parallel`` block and resets to that position after each individual statement. At the end of the block, the cursor is advanced to the furthest position it reached during the block. In other words, the statements in a ``parallel`` block are actually executed sequentially. Only the RTIO events generated by the statements are *scheduled* in parallel.
It simply remembers its position on the timeline (``now_mu``) when entering the ``parallel`` block and resets to that position after each individual statement.
At the end of the block, the cursor is advanced to the furthest position it reached during the block.
In other words, the statements in a ``parallel`` block are actually executed sequentially.
Only the RTIO events generated by the statements are *scheduled* in parallel.
Remember that while ``now_mu`` resets at the beginning of each statement in a ``parallel`` block, the wall clock advances regardless. If a particular statement takes a long time to execute (which is different from -- and unrelated to! -- the events *scheduled* by the statement taking a long time), the wall clock may advance past the reset value, putting any subsequent statements inside the block into a situation of negative slack (i.e., resulting in :exc:`~artiq.coredevice.exceptions.RTIOUnderflow` ). Sometimes underflows may be avoided simply by reordering statements within the parallel block. This especially applies to input methods, which generally necessarily block CPU progress until the wall clock has caught up to or overtaken the cursor. Remember that while ``now_mu`` resets at the beginning of each statement in a ``parallel`` block, the wall clock advances regardless. If a particular statement takes a long time to execute (which is different from -- and unrelated to! -- the events *scheduled* by the statement taking a long time), the wall clock may advance past the reset value, putting any subsequent statements inside the block into a situation of negative slack (i.e., resulting in :exc:`~artiq.coredevice.exceptions.RTIOUnderflow` ). Sometimes underflows may be avoided simply by reordering statements within the parallel block. This especially applies to input methods, which generally necessarily block CPU progress until the wall clock has caught up to or overtaken the cursor.

View File

@ -3,30 +3,19 @@ List of available NDSPs
The following network device support packages are available for ARTIQ. If you would like to add yours to this list, just send us an email or a pull request. The following network device support packages are available for ARTIQ. If you would like to add yours to this list, just send us an email or a pull request.
+---------------------------------+-----------------------------------+----------------------------------+-------------------------------------------------------------------+--------------------------------------------------------+ .. csv-table::
| Equipment | Nix package | MSYS2 package | Documentation | URL | :header: Equipment, Nix package, MSYS2 package, Documentation, URL
+=================================+===================================+==================================+===================================================================+========================================================+
| PDQ2 | Not available | Not available | `HTML <https://pdq.readthedocs.io>`_ | https://github.com/m-labs/pdq | PDQ2, Not available, Not available, `HTML <https://pdq.readthedocs.io>`_, `GitHub <https://github.com/m-labs/pdq>`__
+---------------------------------+-----------------------------------+----------------------------------+-------------------------------------------------------------------+--------------------------------------------------------+ Lab Brick Digital Attenuator, ``lda``, ``lda``, Not available, `GitHub <https://github.com/m-labs/lda>`__
| Lab Brick Digital Attenuator | ``lda`` | ``lda`` | Not available | https://github.com/m-labs/lda | Novatech 4098B, ``novatech409b``, ``novatech409b``, Not available, `GitHub <https://github.com/m-labs/novatech409b>`__
+---------------------------------+-----------------------------------+----------------------------------+-------------------------------------------------------------------+--------------------------------------------------------+ Thorlabs T-Cubes, ``thorlabs_tcube``, ``thorlabs_tcube``, Not available, `GitHub <https://github.com/m-labs/thorlabs_tcube>`__
| Novatech 409B | ``novatech409b`` | ``novatech409b`` | Not available | https://github.com/m-labs/novatech409b | Korad KA3005P, ``korad_ka3005p``, ``korad_ka3005p``, Not available, `GitHub <https://github.com/m-labs/korad_ka3005p>`__
+---------------------------------+-----------------------------------+----------------------------------+-------------------------------------------------------------------+--------------------------------------------------------+ Newfocus 8742, ``newfocus8742``, ``newfocus8742``, Not available, `GitHub <https://github.com/quartiq/newfocus8742>`__
| Thorlabs T-Cubes | ``thorlabs_tcube`` | ``thorlabs_tcube`` | Not available | https://github.com/m-labs/thorlabs_tcube | Princeton Instruments PICam, Not available, Not available, Not available, `GitHub <https://github.com/quartiq/picam>`__
+---------------------------------+-----------------------------------+----------------------------------+-------------------------------------------------------------------+--------------------------------------------------------+ Anel HUT2 power distribution, ``hut2``, Not available, Not available, `GitHub <https://github.com/quartiq/hut2>`__
| Korad KA3005P | ``korad_ka3005p`` | ``korad_ka3005p`` | Not available | https://github.com/m-labs/korad_ka3005p | TOPTICA lasers, ``toptica-lasersdk-artiq``, Not available, Not available, `GitHub <https://github.com/quartiq/lasersdk-artiq>`__
+---------------------------------+-----------------------------------+----------------------------------+-------------------------------------------------------------------+--------------------------------------------------------+ HighFinesse wavemeters, ``highfinesse-net``, Not available, Not available, `GitHub <https://github.com/quartiq/highfinesse-net>`__
| Newfocus 8742 | ``newfocus8742`` | ``newfocus8742`` | Not available | https://github.com/quartiq/newfocus8742 | InfluxDB database, Not available, Not available, `HTML <https://gitlab.com/charlesbaynham/artiq_influx_generic>`__, `GitHub <https://gitlab.com/charlesbaynham/artiq_influx_generic>`__
+---------------------------------+-----------------------------------+----------------------------------+-------------------------------------------------------------------+--------------------------------------------------------+
| Princeton Instruments PICam | Not available | Not available | Not available | https://github.com/quartiq/picam |
+---------------------------------+-----------------------------------+----------------------------------+-------------------------------------------------------------------+--------------------------------------------------------+
| Anel HUT2 power distribution | ``hut2`` | Not available | Not available | https://github.com/quartiq/hut2 |
+---------------------------------+-----------------------------------+----------------------------------+-------------------------------------------------------------------+--------------------------------------------------------+
| TOPTICA lasers | ``toptica-lasersdk-artiq`` | Not available | Not available | https://github.com/quartiq/lasersdk-artiq |
+---------------------------------+-----------------------------------+----------------------------------+-------------------------------------------------------------------+--------------------------------------------------------+
| HighFinesse wavemeters | ``highfinesse-net`` | Not available | Not available | https://github.com/quartiq/highfinesse-net |
+---------------------------------+-----------------------------------+----------------------------------+-------------------------------------------------------------------+--------------------------------------------------------+
| InfluxDB database | Not available | Not available | `HTML <https://gitlab.com/charlesbaynham/artiq_influx_generic>`__ | https://gitlab.com/charlesbaynham/artiq_influx_generic |
+---------------------------------+-----------------------------------+----------------------------------+-------------------------------------------------------------------+--------------------------------------------------------+
MSYS2 packages all start with the ``mingw-w64-clang-x86_64-`` prefix. MSYS2 packages all start with the ``mingw-w64-clang-x86_64-`` prefix.

View File

@ -5,28 +5,17 @@ ARTIQ Real-Time I/O Concepts
The ARTIQ Real-Time I/O design employs several concepts to achieve its goals of high timing resolution on the nanosecond scale and low latency on the microsecond scale while still not sacrificing a readable and extensible language. The ARTIQ Real-Time I/O design employs several concepts to achieve its goals of high timing resolution on the nanosecond scale and low latency on the microsecond scale while still not sacrificing a readable and extensible language.
In a typical environment two very different classes of hardware need to be controlled. In a typical environment two very different classes of hardware need to be controlled. One class is the vast arsenal of diverse laboratory hardware that interfaces with and is controlled from a typical PC. The other is specialized real-time hardware that requires tight coupling and a low-latency interface to a CPU. The ARTIQ code that describes a given experiment is composed of two types of "programs": regular Python code that is executed on the host and ARTIQ *kernels* that are executed on a *core device*. The CPU that executes the ARTIQ kernels has direct access to specialized programmable I/O timing logic (part of the *gateware*). The two types of code can invoke each other and transitions between them are seamless.
One class is the vast arsenal of diverse laboratory hardware that interfaces with and is controlled from a typical PC.
The other is specialized real-time hardware that requires tight coupling and a low-latency interface to a CPU.
The ARTIQ code that describes a given experiment is composed of two types of "programs":
regular Python code that is executed on the host and ARTIQ *kernels* that are executed on a *core device*.
The CPU that executes the ARTIQ kernels has direct access to specialized programmable I/O timing logic (part of the *gateware*).
The two types of code can invoke each other and transitions between them are seamless.
The ARTIQ kernels do not interface with the real-time gateware directly. The ARTIQ kernels do not interface with the real-time gateware directly. That would lead to imprecise, indeterminate, and generally unpredictable timing. Instead the CPU operates at one end of a bank of FIFO (first-in-first-out) buffers while the real-time gateware at the other end guarantees the *all or nothing* level of excellent timing precision.
That would lead to imprecise, indeterminate, and generally unpredictable timing.
Instead the CPU operates at one end of a bank of FIFO (first-in-first-out) buffers while the real-time gateware at the other end guarantees the *all or nothing* level of excellent timing precision.
A FIFO for an output channel holds timestamps and event data describing when and what is to be executed. A FIFO for an output channel holds timestamps and event data describing when and what is to be executed. The CPU feeds events into this FIFO. A FIFO for an input channel contains timestamps and event data for events that have been recorded by the real-time gateware and are waiting to be read out by the CPU on the other end.
The CPU feeds events into this FIFO.
A FIFO for an input channel contains timestamps and event data for events that have been recorded by the real-time gateware and are waiting to be read out by the CPU on the other end.
Timeline and terminology Timeline and terminology
------------------------ ------------------------
The set of all input and output events on all channels constitutes the *timeline*. The set of all input and output events on all channels constitutes the *timeline*. A high-resolution wall clock (``rtio_counter_mu``) counts clock cycles and manages the precise timing of the events. Output events are executed when their timestamp matches the current clock value. Input events are recorded when they reach the gateware and stamped with the current clock value accordingly.
A high-resolution wall clock (``rtio_counter_mu``) counts clock cycles and manages the precise timing of the events. Output events are executed when their timestamp matches the current clock value. Input events are recorded when they reach the gateware and stamped with the current clock value accordingly.
The kernel runtime environment maintains a timeline cursor (called ``now_mu``) used as the timestamp when output events are submitted to the FIFOs. Both ``now_mu`` and ``rtio_counter_mu`` are counted in integer *machine units,* or mu, rather than SI units. The machine unit represents the maximum resolution of RTIO timing in an ARTIQ system. The duration of a machine unit is the *reference period* of the system, and may be changed by the user, but normally corresponds to a duration of one nanosecond. The kernel runtime environment maintains a timeline cursor (called ``now_mu``) used as the timestamp when output events are submitted to the FIFOs. Both ``now_mu`` and ``rtio_counter_mu`` are counted in integer *machine units,* or mu, rather than SI units. The machine unit represents the maximum resolution of RTIO timing in an ARTIQ system. The duration of a machine unit is the *reference period* of the system, and may be changed by the user, but normally corresponds to a duration of one nanosecond.
@ -34,34 +23,22 @@ The timeline cursor ``now_mu`` can be moved forward or backward on the timeline
RTIO timestamps, the timeline cursor, and the ``rtio_counter_mu`` wall clock are all counted relative to the core device startup/boot time. The wall clock keeps running across experiments. RTIO timestamps, the timeline cursor, and the ``rtio_counter_mu`` wall clock are all counted relative to the core device startup/boot time. The wall clock keeps running across experiments.
Absolute timestamps can be large numbers. Absolute timestamps can be large numbers. They are represented internally as 64-bit integers. With a typical one-nanosecond machine unit, this covers a range of hundreds of years. Conversions between such a large integer number and a floating point representation can cause loss of precision through cancellation. When computing the difference of absolute timestamps, use ``self.core.mu_to_seconds(t2-t1)``, not ``self.core.mu_to_seconds(t2)-self.core.mu_to_seconds(t1)`` (see :meth:`~artiq.coredevice.core.Core.mu_to_seconds`). When accumulating time, do it in machine units and not in SI units, so that rounding errors do not accumulate.
They are represented internally as 64-bit integers.
With a typical one-nanosecond machine unit, this covers a range of hundreds of years.
Conversions between such a large integer number and a floating point representation can cause loss of precision through cancellation.
When computing the difference of absolute timestamps, use ``self.core.mu_to_seconds(t2-t1)``, not ``self.core.mu_to_seconds(t2)-self.core.mu_to_seconds(t1)`` (see :meth:`~artiq.coredevice.core.Core.mu_to_seconds`).
When accumulating time, do it in machine units and not in SI units, so that rounding errors do not accumulate.
.. note:: .. note::
Absolute timestamps are also referred to as *RTIO fine timestamps,* because they run on a significantly finer resolution than the timestamps provided by the so-called *coarse RTIO clock,* the actual clocking signal provided to or generated by the core device. Absolute timestamps are also referred to as *RTIO fine timestamps,* because they run on a significantly finer resolution than the timestamps provided by the so-called *coarse RTIO clock,* the actual clocking signal provided to or generated by the core device. The frequency of the coarse RTIO clock is set by the core device :ref:`clocking settings <core-device-clocking>` but is most commonly 125MHz, which corresponds to eight one-nanosecond machine units per coarse RTIO cycle.
The frequency of the coarse RTIO clock is set by the core device :ref:`clocking settings <core-device-clocking>` but is most commonly 125MHz, which corresponds to eight one-nanosecond machine units per coarse RTIO cycle.
The *coarse timestamp* of an event is its timestamp as according to the lower resolution of the coarse clock. The *coarse timestamp* of an event is its timestamp as according to the lower resolution of the coarse clock. It is in practice a truncated version of the fine timestamp. In general, ARTIQ offers *precision* on the fine level, but *operates* at the coarse level; this is rarely relevant to the user, but understanding it may clarify the behavior of some RTIO issues (e.g. sequence errors).
It is in practice a truncated version of the fine timestamp.
In general, ARTIQ offers *precision* on the fine level, but *operates* at the coarse level; this is rarely relevant to the user, but understanding it may clarify the behavior of some RTIO issues (e.g. sequence errors).
.. Related: https://github.com/m-labs/artiq/issues/1237 .. Related: https://github.com/m-labs/artiq/issues/1237
The following basic example shows how to place output events on the timeline. The following basic example shows how to place output events on the timeline. It emits a precisely timed 2 µs pulse::
It emits a precisely timed 2 µs pulse::
ttl.on() ttl.on()
delay(2*us) delay(2*us)
ttl.off() ttl.off()
The device ``ttl`` represents a single digital output channel (:class:`artiq.coredevice.ttl.TTLOut`). The device ``ttl`` represents a single digital output channel (:class:`artiq.coredevice.ttl.TTLOut`). The :meth:`artiq.coredevice.ttl.TTLOut.on` method places an rising edge on the timeline at the current cursor position (``now_mu``). Then the cursor is moved forward 2 µs and a falling edge is placed at the new cursor position. Later, when the wall clock reaches the respective timestamps, the RTIO gateware executes the two events.
The :meth:`artiq.coredevice.ttl.TTLOut.on` method places an rising edge on the timeline at the current cursor position (``now_mu``).
Then the cursor is moved forward 2 µs and a falling edge is placed at the new cursor position.
Later, when the wall clock reaches the respective timestamps, the RTIO gateware executes the two events.
The following diagram shows what is going on at the different levels of the software and gateware stack (assuming one machine unit of time is 1 ns): The following diagram shows what is going on at the different levels of the software and gateware stack (assuming one machine unit of time is 1 ns):
@ -88,7 +65,7 @@ This sequence is exactly equivalent to::
ttl.pulse(2*us) ttl.pulse(2*us)
This method :meth:`artiq.coredevice.ttl.TTLOut.pulse` advances the timeline cursor (using :func:`~artiq.language.core.delay` internally) by exactly the amount given. Other methods such as :meth:`~artiq.coredevice.ttl.TTLOut.on`, :meth:`~artiq.coredevice.ttl.TTLOut.off`, :meth:`~artiq.coredevice.ad9914.AD9914.set` do not modify the timeline cursor. The latter are called *zero-duration* methods. This method :meth:`artiq.coredevice.ttl.TTLOut.pulse` advances the timeline cursor (using :func:`~artiq.language.core.delay` internally) by exactly the amount given. ther methods such as :meth:`~artiq.coredevice.ttl.TTLOut.on`, :meth:`~artiq.coredevice.ttl.TTLOut.off`, :meth:`~artiq.coredevice.ad9914.AD9914.set` do not modify the timeline cursor. The latter are called *zero-duration* methods.
Output errors and exceptions Output errors and exceptions
---------------------------- ----------------------------
@ -96,11 +73,7 @@ Output errors and exceptions
Underflows Underflows
^^^^^^^^^^ ^^^^^^^^^^
A RTIO ouput event must always be programmed with a timestamp in the future. A RTIO ouput event must always be programmed with a timestamp in the future. In other words, the timeline cursor ``now_mu`` must be in advance of the current wall clock ``rtio_counter_mu``: the past cannot be altered. The following example tries to place a rising edge event on the timeline. If the current cursor is in the past, an :class:`artiq.coredevice.exceptions.RTIOUnderflow` exception is thrown. The experiment attempts to handle the exception by moving the cursor forward and repeating the programming of the rising edge::
In other words, the timeline cursor ``now_mu`` must be in advance of the current wall clock ``rtio_counter_mu``: the past cannot be altered.
The following example tries to place a rising edge event on the timeline.
If the current cursor is in the past, an :class:`artiq.coredevice.exceptions.RTIOUnderflow` exception is thrown.
The experiment attempts to handle the exception by moving the cursor forward and repeating the programming of the rising edge::
try: try:
ttl.on() ttl.on()
@ -109,8 +82,7 @@ The experiment attempts to handle the exception by moving the cursor forward and
delay(16.6667*ms) delay(16.6667*ms)
ttl.on() ttl.on()
Once the timeline cursor has overtaken the wall clock, the exception does not reoccur and the event can be scheduled successfully. Once the timeline cursor has overtaken the wall clock, the exception does not reoccur and the event can be scheduled successfully. This can also be thought of as adding positive slack to the system.
This can also be thought of as adding positive slack to the system.
.. wavedrom:: .. wavedrom::
@ -180,17 +152,13 @@ Offending event(s) are discarded and the problem is reported asynchronously via
Input channels and events Input channels and events
------------------------- -------------------------
Input channels detect events, timestamp them, and place them in a buffer for the experiment to read out. Input channels detect events, timestamp them, and place them in a buffer for the experiment to read out. The following example counts the rising edges occurring during a precisely timed 500 ns interval. If more than 20 rising edges are received, it outputs a pulse::
The following example counts the rising edges occurring during a precisely timed 500 ns interval.
If more than 20 rising edges are received, it outputs a pulse::
if input.count(input.gate_rising(500*ns)) > 20: if input.count(input.gate_rising(500*ns)) > 20:
delay(2*us) delay(2*us)
output.pulse(500*ns) output.pulse(500*ns)
Note that many input methods will necessarily involve the wall clock catching up to the timeline cursor or advancing before it. Note that many input methods will necessarily involve the wall clock catching up to the timeline cursor or advancing before it. This is to be expected: managing output events means working to plan the future, but managing input events means working to react to the past. For input channels, it is the past that is under discussion.
This is to be expected: managing output events means working to plan the future, but managing input events means working to react to the past.
For input channels, it is the past that is under discussion.
In this case, the :meth:`~artiq.coredevice.ttl.TTLInOut.gate_rising` waits for the duration of the 500ns interval (or *gate window*) and records an event for each rising edge. At the end of the interval it exits, leaving the timeline cursor at the end of the interval (``now_mu = rtio_counter_mu``). :meth:`~artiq.coredevice.ttl.TTLInOut.count` unloads these events from the input buffers and counts the number of events recorded, during which the wall clock necessarily advances (``rtio_counter_mu > now_mu``). Accordingly, before we place any further output events, a :func:`~artiq.language.core.delay` is necessary to re-establish positive slack. In this case, the :meth:`~artiq.coredevice.ttl.TTLInOut.gate_rising` waits for the duration of the 500ns interval (or *gate window*) and records an event for each rising edge. At the end of the interval it exits, leaving the timeline cursor at the end of the interval (``now_mu = rtio_counter_mu``). :meth:`~artiq.coredevice.ttl.TTLInOut.count` unloads these events from the input buffers and counts the number of events recorded, during which the wall clock necessarily advances (``rtio_counter_mu > now_mu``). Accordingly, before we place any further output events, a :func:`~artiq.language.core.delay` is necessary to re-establish positive slack.
@ -220,13 +188,7 @@ Similar situations arise with methods such as :meth:`TTLInOut.sample_get <artiq.
Overflow exceptions Overflow exceptions
^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
The RTIO input channels buffer input events received while an input gate is open, or when using the sampling API (:meth:`TTLInOut.sample_input <artiq.coredevice.ttl.TTLInOut.sample_input>`) at certain points in time. The RTIO input channels buffer input events received while an input gate is open, or when using the sampling API (:meth:`TTLInOut.sample_input <artiq.coredevice.ttl.TTLInOut.sample_input>`) at certain points in time. The events are kept in a FIFO until the CPU reads them out via e.g. :meth:`~artiq.coredevice.ttl.TTLInOut.count`, :meth:`~artiq.coredevice.ttl.TTLInOut.timestamp_mu` or :meth:`~artiq.coredevice.ttl.TTLInOut.sample_get`. The size of these FIFOs is finite and specified in gateware; in practice, it is limited by the resources available to the FPGA, and therefore differs depending on the specific core device being used. If a FIFO is full and another event comes in, this causes an overflow condition. The condition is converted into an :class:`~artiq.coredevice.exceptions.RTIOOverflow` exception that is raised on a subsequent invocation of one of the readout methods. Overflow exceptions are generally best dealt with simply by reading out from the input buffers more frequently. In odd or particular cases, users may consider modifying the length of individual buffers in gateware.
The events are kept in a FIFO until the CPU reads them out via e.g. :meth:`~artiq.coredevice.ttl.TTLInOut.count`, :meth:`~artiq.coredevice.ttl.TTLInOut.timestamp_mu` or :meth:`~artiq.coredevice.ttl.TTLInOut.sample_get`.
The size of these FIFOs is finite and specified in gateware; in practice, it is limited by the resources available to the FPGA, and therefore differs depending on the specific core device being used.
If a FIFO is full and another event comes in, this causes an overflow condition.
The condition is converted into an :class:`~artiq.coredevice.exceptions.RTIOOverflow` exception that is raised on a subsequent invocation of one of the readout methods.
Overflow exceptions are generally best dealt with simply by reading out from the input buffers more frequently. In odd or particular cases, users may consider modifying the length of individual buffers in gateware.
.. note:: .. note::
It is not possible to provoke an :class:`~artiq.coredevice.exceptions.RTIOOverflow` on a RTIO output channel. While output buffers are also of finite size, and can be filled up, the CPU will simply stall the submission of further events until it is once again possible to buffer them. Among other things, this means that padding the timeline cursor with large amounts of positive slack is not always a valid strategy to avoid :class:`~artiq.coredevice.exceptions.RTIOOverflow` exceptions when generating fast event sequences. In practice only a fixed number of events can be generated in advance, and the rest of the processing will be carried out when the wall clock is much closer to ``now_mu``. It is not possible to provoke an :class:`~artiq.coredevice.exceptions.RTIOOverflow` on a RTIO output channel. While output buffers are also of finite size, and can be filled up, the CPU will simply stall the submission of further events until it is once again possible to buffer them. Among other things, this means that padding the timeline cursor with large amounts of positive slack is not always a valid strategy to avoid :class:`~artiq.coredevice.exceptions.RTIOOverflow` exceptions when generating fast event sequences. In practice only a fixed number of events can be generated in advance, and the rest of the processing will be carried out when the wall clock is much closer to ``now_mu``.
@ -251,8 +213,7 @@ Note that event spreading can be particularly helpful in DRTIO satellites, as it
Seamless handover Seamless handover
----------------- -----------------
The timeline cursor persists across kernel invocations. The timeline cursor persists across kernel invocations. This is demonstrated in the following example where a pulse is split across two kernels::
This is demonstrated in the following example where a pulse is split across two kernels::
def run(): def run():
k1() k1()