Core drivers reference¶
These drivers are for the core device and the peripherals closely integrated into it, which do not use the controller mechanism.
System drivers¶
artiq.coredevice.core
module¶
- class artiq.coredevice.core.Core(dmgr, host, ref_period, ref_multiplier=8, target='rv32g')[source]¶
Core device driver.
- Parameters:
host – hostname or IP address of the core device.
ref_period – period of the reference clock for the RTIO subsystem. On platforms that use clock multiplication and SERDES-based PHYs, this is the period after multiplication. For example, with a RTIO core clocked at 125MHz and a SERDES multiplication factor of 8, the reference period is 1ns. The time machine unit is equal to this period.
ref_multiplier – ratio between the RTIO fine timestamp frequency and the RTIO coarse timestamp frequency (e.g. SERDES multiplication factor).
- break_realtime()[source]¶
Set the time cursor after the current value of the hardware RTIO counter plus a margin of 125000 machine units.
If the time cursor is already after that position, this function does nothing.
- get_rtio_counter_mu()[source]¶
Retrieve the current value of the hardware RTIO timeline counter.
As the timing of kernel code executed on the CPU is inherently non-deterministic, the return value is by necessity only a lower bound for the actual value of the hardware register at the instant when execution resumes in the caller.
For a more detailed description of these concepts, see ARTIQ Real-Time I/O Concepts.
- get_rtio_destination_status(destination)[source]¶
Returns whether the specified RTIO destination is up. This is particularly useful in startup kernels to delay startup until certain DRTIO destinations are up.
- mu_to_seconds(mu)[source]¶
Convert machine units (RTIO cycles) to seconds.
- Parameters:
mu – cycle count to convert.
- precompile(function, *args, **kwargs)[source]¶
Precompile a kernel and return a callable that executes it on the core device at a later time.
Arguments to the kernel are set at compilation time and passed to this function, as additional positional and keyword arguments. The returned callable accepts no arguments.
Precompiled kernels may use RPCs.
Object attributes at the beginning of a precompiled kernel execution have the values they had at precompilation time. If up-to-date values are required, use RPC to read them. Similarly, modified values are not written back, and explicit RPC should be used to modify host objects. Carefully review the source code of drivers calls used in precompiled kernels, as they may rely on host object attributes being transfered between kernel calls. Examples include code used to control DDS phase, and Urukul RF switch control via the CPLD register.
The return value of the callable is the return value of the kernel, if any.
The callable may be called several times.
- reset()[source]¶
Clear RTIO FIFOs, release RTIO PHY reset, and set the time cursor at the current value of the hardware RTIO counter plus a margin of 125000 machine units.
- seconds_to_mu(seconds)[source]¶
Convert seconds to the corresponding number of machine units (RTIO cycles).
- Parameters:
seconds – time (in seconds) to convert.
- wait_until_mu(cursor_mu)[source]¶
Block execution until the hardware RTIO counter reaches the given value (see
get_rtio_counter_mu()
).If the hardware counter has already passed the given time, the function returns immediately.
artiq.coredevice.exceptions
module¶
- exception artiq.coredevice.exceptions.CacheError[source]¶
Raised when putting a value into a cache row would violate memory safety.
- class artiq.coredevice.exceptions.CoreException(exceptions, exception_info, traceback, stack_pointers)[source]¶
Information about an exception raised or passed through the core device.
- exception artiq.coredevice.exceptions.DMAError[source]¶
Raised when performing an invalid DMA operation.
- exception artiq.coredevice.exceptions.InternalError[source]¶
Raised when the runtime encounters an internal error condition.
- exception artiq.coredevice.exceptions.RTIODestinationUnreachable[source]¶
Raised with a RTIO operation could not be completed due to a DRTIO link being down.
- exception artiq.coredevice.exceptions.RTIOOverflow[source]¶
Raised when at least one event could not be registered into the RTIO input FIFO because it was full (CPU not reading fast enough).
This does not interrupt operations further than cancelling the current read attempt and discarding some events. Reading can be reattempted after the exception is caught, and events will be partially retrieved.
artiq.coredevice.dma
module¶
Direct Memory Access (DMA) extension.
This feature allows storing pre-defined sequences of output RTIO events into the core device’s SDRAM, and playing them back at higher speeds than the CPU alone could achieve.
- class artiq.coredevice.dma.CoreDMA(dmgr, core_device='core')[source]¶
Core device Direct Memory Access (DMA) driver.
Gives access to the DMA functionality of the core device.
- get_handle(name)[source]¶
Returns a handle to a previously recorded DMA trace. The returned handle is only valid until the next call to
record()
orerase()
.
- playback(name)[source]¶
Replays a previously recorded DMA trace. This function blocks until the entire trace is submitted to the RTIO FIFOs.
- playback_handle(handle)[source]¶
Replays a handle obtained with
get_handle()
. Using this function is much faster thanplayback()
for replaying a set of traces repeatedly, but incurs the overhead of managing the handles onto the programmer.
- class artiq.coredevice.dma.DMARecordContextManager[source]¶
Context manager returned by
CoreDMA.record()
.Upon entering, starts recording a DMA trace. All RTIO operations are redirected to a newly created DMA buffer after this call, and
now
is reset to zero.Upon leaving, stops recording a DMA trace. All recorded RTIO operations are stored in a newly created trace, and
now
is restored to the value it had before the context manager was entered.
artiq.coredevice.cache
module¶
- class artiq.coredevice.cache.CoreCache(dmgr, core_device='core')[source]¶
Core device cache access
- get(key)[source]¶
Extract a value from the core device cache. After a value is extracted, it cannot be replaced with another value using
put()
until all kernel functions finish executing; attempting to replace it will result in aartiq.coredevice.exceptions.CacheError
.If the cache does not contain any value associated with
key
, an empty list is returned.The value is not copied, so mutating it will change what’s stored in the cache.
- Parameters:
key (str) – cache key
- Returns:
a list of 32-bit integers
Digital I/O drivers¶
artiq.coredevice.ttl
module¶
Drivers for TTL signals on RTIO.
TTL channels (including the clock generator) all support output event
replacement. For example, pulses of “zero” length (e.g. TTLInOut.on()
immediately followed by TTLInOut.off()
, without a delay) are suppressed.
- class artiq.coredevice.ttl.TTLClockGen(dmgr, channel, acc_width=24, core_device='core')[source]¶
RTIO TTL clock generator driver.
This should be used with TTL channels that have a clock generator built into the gateware (not compatible with regular TTL channels).
The time cursor is not modified by any function in this class.
- Parameters:
channel – channel number
acc_width – accumulator width in bits
- frequency_to_ftw(frequency)[source]¶
Returns the frequency tuning word corresponding to the given frequency.
- ftw_to_frequency(ftw)[source]¶
Returns the frequency corresponding to the given frequency tuning word.
- set_mu(frequency)[source]¶
Set the frequency of the clock, in machine units, at the current position of the time cursor.
This also sets the phase, as the time of the first generated rising edge corresponds to the time of the call.
The clock generator contains a 24-bit phase accumulator operating on the RTIO clock. At each RTIO clock tick, the frequency tuning word is added to the phase accumulator. The most significant bit of the phase accumulator is connected to the TTL line. Setting the frequency tuning word has the additional effect of setting the phase accumulator to 0x800000.
Due to the way the clock generator operates, frequency tuning words that are not powers of two cause jitter of one RTIO clock cycle at the output.
- class artiq.coredevice.ttl.TTLInOut(dmgr, channel, gate_latency_mu=None, core_device='core')[source]¶
RTIO TTL input/output driver.
In output mode, provides functions to set the logic level on the signal.
In input mode, provides functions to analyze the incoming signal, with real-time gating to prevent overflows.
RTIO TTLs supports zero-length transition suppression. For example, if two pulses are emitted back-to-back with no delay between them, they will be merged into a single pulse with a duration equal to the sum of the durations of the original pulses.
This should be used with bidirectional channels.
Note that the channel is in input mode by default. If you need to drive a signal, you must call
output()
. If the channel is in output mode most of the time in your setup, it is a good idea to calloutput()
in the startup kernel.There are three input APIs: gating, sampling and watching. When one API is active (e.g. the gate is open, or the input events have not been fully read out), another API must not be used simultaneously.
- Parameters:
channel – channel number
- count(up_to_timestamp_mu)[source]¶
Consume RTIO input events until the hardware timestamp counter has reached the specified timestamp and return the number of observed events.
This function does not interact with the timeline cursor.
See the
gate_*()
family of methods to select the input transitions that generate events, andtimestamp_mu()
to obtain the timestamp of the first event rather than an accumulated count.- Parameters:
up_to_timestamp_mu – The timestamp up to which execution is blocked, that is, up to which input events are guaranteed to be taken into account. (Events with later timestamps might still be registered if they are already available.)
- Returns:
The number of events before the timeout elapsed (0 if none observed).
Examples
To count events on channel
ttl_input
, up to the current timeline position:ttl_input.count(now_mu())
If other events are scheduled between the end of the input gate period and when the number of events is counted, using
now_mu()
as timeout consumes an unnecessary amount of timeline slack. In such cases, it can be beneficial to pass a more precise timestamp, for example:gate_end_mu = ttl_input.gate_rising(100 * us) # Schedule a long pulse sequence, represented here by a delay. delay(10 * ms) # Get number of rising edges. This will block until the end of # the gate window, but does not wait for the long pulse sequence # afterwards, thus (likely) completing with a large amount of # slack left. num_rising_edges = ttl_input.count(gate_end_mu)
The
gate_*()
family of methods return the cursor at the end of the window, allowing this to be expressed in a compact fashion:ttl_input.count(ttl_input.gate_rising(100 * us))
- gate_both(duration)[source]¶
Register both rising and falling edge events for the specified duration (in seconds).
The time cursor is advanced by the specified duration.
- Returns:
The timeline cursor at the end of the gate window, for convenience when used with
count()
/timestamp_mu()
.
- gate_both_mu(duration)[source]¶
Register both rising and falling edge events for the specified duration (in machine units).
The time cursor is advanced by the specified duration.
- Returns:
The timeline cursor at the end of the gate window, for convenience when used with
count()
/timestamp_mu()
.
- gate_falling(duration)[source]¶
Register falling edge events for the specified duration (in seconds).
The time cursor is advanced by the specified duration.
- Returns:
The timeline cursor at the end of the gate window, for convenience when used with
count()
/timestamp_mu()
.
- gate_falling_mu(duration)[source]¶
Register falling edge events for the specified duration (in machine units).
The time cursor is advanced by the specified duration.
- Returns:
The timeline cursor at the end of the gate window, for convenience when used with
count()
/timestamp_mu()
.
- gate_rising(duration)[source]¶
Register rising edge events for the specified duration (in seconds).
The time cursor is advanced by the specified duration.
- Returns:
The timeline cursor at the end of the gate window, for convenience when used with
count()
/timestamp_mu()
.
- gate_rising_mu(duration)[source]¶
Register rising edge events for the specified duration (in machine units).
The time cursor is advanced by the specified duration.
- Returns:
The timeline cursor at the end of the gate window, for convenience when used with
count()
/timestamp_mu()
.
- input()[source]¶
Set the direction to input at the current position of the time cursor.
There must be a delay of at least one RTIO clock cycle before any other command can be issued.
This method only configures the direction at the FPGA. When using buffered I/O interfaces, such as the Sinara TTL cards, the buffer direction must be configured separately in the hardware.
- off()[source]¶
Set the output to a logic low state at the current position of the time cursor.
The channel must be in output mode.
The time cursor is not modified by this function.
- on()[source]¶
Set the output to a logic high state at the current position of the time cursor.
The channel must be in output mode.
The time cursor is not modified by this function.
- output()[source]¶
Set the direction to output at the current position of the time cursor.
There must be a delay of at least one RTIO clock cycle before any other command can be issued.
This method only configures the direction at the FPGA. When using buffered I/O interfaces, such as the Sinara TTL cards, the buffer direction must be configured separately in the hardware.
- pulse(duration)[source]¶
Pulse the output high for the specified duration (in seconds).
The time cursor is advanced by the specified duration.
- pulse_mu(duration)[source]¶
Pulse the output high for the specified duration (in machine units).
The time cursor is advanced by the specified duration.
- sample_get()[source]¶
Returns the value of a sample previously obtained with
sample_input()
.Multiple samples may be queued (using multiple calls to
sample_input()
) into the RTIO FIFOs and subsequently read out using multiple calls to this function.This function does not interact with the time cursor.
- sample_get_nonrt()[source]¶
Convenience function that obtains the value of a sample at the position of the time cursor, breaks realtime, and returns the sample value.
- sample_input()[source]¶
Instructs the RTIO core to read the value of the TTL input at the position of the time cursor.
The time cursor is not modified by this function.
- timestamp_mu(up_to_timestamp_mu)[source]¶
Return the timestamp of the next RTIO input event, or -1 if the hardware timestamp counter reaches the given value before an event is received.
This function does not interact with the timeline cursor.
See the
gate_*()
family of methods to select the input transitions that generate events, andcount()
for usage examples.- Parameters:
up_to_timestamp_mu – The timestamp up to which execution is blocked, that is, up to which input events are guaranteed to be taken into account. (Events with later timestamps might still be registered if they are already available.)
- Returns:
The timestamp (in machine units) of the first event received; -1 on timeout.
- watch_done()[source]¶
Stop watching the input at the position of the time cursor.
Returns
True
if the input has not changed state while it was being watched.The time cursor is not modified by this function. This function always makes the slack negative.
- watch_stay_off()[source]¶
Like
watch_stay_on()
, but for low levels.
- watch_stay_on()[source]¶
Checks that the input is at a high level at the position of the time cursor and keep checking until
watch_done()
is called.Returns
True
if the input is high. A call to this function must always be followed by an eventual call towatch_done()
(use e.g. a try/finally construct to ensure this).The time cursor is not modified by this function.
- class artiq.coredevice.ttl.TTLOut(dmgr, channel, core_device='core')[source]¶
RTIO TTL output driver.
This should be used with output-only channels.
- Parameters:
channel – channel number
- off()[source]¶
Set the output to a logic low state at the current position of the time cursor.
The time cursor is not modified by this function.
- on()[source]¶
Set the output to a logic high state at the current position of the time cursor.
The time cursor is not modified by this function.
artiq.coredevice.edge_counter
module¶
Driver for RTIO-enabled TTL edge counter.
Like for the TTL input PHYs, sensitivity can be configured over RTIO
(gate_rising()
, etc.). In contrast to the former, however, the count is
accumulated in gateware, and only a single input event is generated at the end
of each gate period:
with parallel:
doppler_cool()
self.pmt_counter.gate_rising(1 * ms)
with parallel:
readout()
self.pmt_counter.gate_rising(100 * us)
print("Doppler cooling counts:", self.pmt_counter.fetch_count())
print("Readout counts:", self.pmt_counter.fetch_count())
For applications where the timestamps of the individual input events are not
required, this has two advantages over TTLInOut.count()
beyond raw
throughput. First, it is easy to count events during multiple separate periods
without blocking to read back counts in between, as illustrated in the above
example. Secondly, as each count total only takes up a single input event, it
is much easier to acquire counts on several channels in parallel without
risking input FIFO overflows:
# Using the TTLInOut driver, pmt_1 input events are only processed
# after pmt_0 is done counting. To avoid RTIOOverflows, a round-robin
# scheme would have to be implemented manually.
with parallel:
self.pmt_0.gate_rising(10 * ms)
self.pmt_1.gate_rising(10 * ms)
counts_0 = self.pmt_0.count(now_mu()) # blocks
counts_1 = self.pmt_1.count(now_mu())
#
# Using gateware counters, only a single input event each is
# generated, greatly reducing the load on the input FIFOs:
with parallel:
self.pmt_0_counter.gate_rising(10 * ms)
self.pmt_1_counter.gate_rising(10 * ms)
counts_0 = self.pmt_0_counter.fetch_count() # blocks
counts_1 = self.pmt_1_counter.fetch_count()
See artiq.gateware.rtio.phy.edge_counter
and
artiq.gateware.eem.DIO.add_std()
for the gateware components.
- exception artiq.coredevice.edge_counter.CounterOverflow[source]¶
Raised when an edge counter value is read which indicates that the counter might have overflowed.
- class artiq.coredevice.edge_counter.EdgeCounter(dmgr, channel, gateware_width=31, core_device='core')[source]¶
RTIO TTL edge counter driver driver.
Like for regular TTL inputs, timeline periods where the counter is sensitive to a chosen set of input transitions can be specified. Unlike the former, however, the specified edges do not create individual input events; rather, the total count can be requested as a single input event from the core (typically at the end of the gate window).
- Parameters:
channel – The RTIO channel of the gateware phy.
gateware_width – The width of the gateware counter register, in bits. This is only used for overflow handling; to change the size, the gateware needs to be rebuilt.
- fetch_count() numpy.int32 [source]¶
Wait for and return count total from previously requested input event.
It is valid to trigger multiple gate periods without immediately reading back the count total; the results will be returned in order on subsequent fetch calls.
This function blocks until a result becomes available.
- fetch_timestamped_count(timeout_mu=<Mock name='mock.int64()' id='140737286669456'>) -> (numpy.int64, numpy.int32)[source]¶
Wait for and return the timestamp and count total of a previously requested input event.
It is valid to trigger multiple gate periods without immediately reading back the count total; the results will be returned in order on subsequent fetch calls.
This function blocks until a result becomes available or the given timeout elapses.
- Returns:
A tuple of timestamp (-1 if timeout elapsed) and counter value. (The timestamp is that of the requested input event – typically the gate closing time – and not that of any input edges.)
- gate_both(duration)[source]¶
Count both rising and falling edges for the given duration, and request the total at the end.
The counter is reset at the beginning of the gate period. Use
set_config()
directly for more detailed control.- Parameters:
duration – The duration for which the gate is to stay open.
- Returns:
The timestamp at the end of the gate period, in machine units.
- gate_both_mu(duration_mu)[source]¶
See
gate_both_mu()
.
- gate_falling(duration)[source]¶
Count falling edges for the given duration and request the total at the end.
The counter is reset at the beginning of the gate period. Use
set_config()
directly for more detailed control.- Parameters:
duration – The duration for which the gate is to stay open.
- Returns:
The timestamp at the end of the gate period, in machine units.
- gate_falling_mu(duration_mu)[source]¶
See
gate_falling()
.
- gate_rising(duration)[source]¶
Count rising edges for the given duration and request the total at the end.
The counter is reset at the beginning of the gate period. Use
set_config()
directly for more detailed control.- Parameters:
duration – The duration for which the gate is to stay open.
- Returns:
The timestamp at the end of the gate period, in machine units.
- gate_rising_mu(duration_mu)[source]¶
See
gate_rising()
.
- set_config(count_rising: bool, count_falling: bool, send_count_event: bool, reset_to_zero: bool)[source]¶
Emit an RTIO event at the current timeline position to set the gateware configuration.
For most use cases, the gate_* wrappers will be more convenient.
- Parameters:
count_rising – Whether to count rising signal edges.
count_falling – Whether to count falling signal edges.
send_count_event – If True, an input event with the current counter value is generated on the next clock cycle (once).
reset_to_zero – If True, the counter value is reset to zero on the next clock cycle (once).
artiq.coredevice.shiftreg
module¶
artiq.coredevice.spi2
module¶
Driver for generic SPI on RTIO.
This ARTIQ coredevice driver corresponds to the “new” MiSoC SPI core (v2).
Output event replacement is not supported and issuing commands at the same time is an error.
- class artiq.coredevice.spi2.NRTSPIMaster(dmgr, busno=0, core_device='core')[source]¶
Core device non-realtime Serial Peripheral Interface (SPI) bus master. Owns one non-realtime SPI bus.
With this driver, SPI transactions and are performed by the CPU without involving RTIO.
Realtime and non-realtime buses are separate and defined at bitstream compilation time.
See
SPIMaster
for a description of the methods.
- class artiq.coredevice.spi2.SPIMaster(dmgr, channel, div=0, length=0, core_device='core')[source]¶
Core device Serial Peripheral Interface (SPI) bus master.
Owns one SPI bus.
This ARTIQ coredevice driver corresponds to the “new” MiSoC SPI core (v2).
Transfer Sequence:
If necessary, set the
config
register (set_config()
andset_config_mu()
) to activate and configure the core and to set various transfer parameters like transfer length, clock divider, and chip selects.write()
to thedata
register. Writing starts the transfer.If the transfer included submitting the SPI input data as an RTIO input event (
SPI_INPUT
set), thenread()
thedata
.If
SPI_END
was not set, repeat the transfer sequence.
A transaction consists of one or more transfers. The chip select pattern is asserted for the entire length of the transaction. All but the last transfer are submitted with
SPI_END
cleared in the configuration register.- Parameters:
channel – RTIO channel number of the SPI bus to control.
div – Initial CLK divider, see also:
update_xfer_duration_mu()
length – Initial transfer length, see also:
update_xfer_duration_mu()
core_device – Core device name
- read()[source]¶
Read SPI data submitted by the SPI core.
For bit alignment and bit ordering see
set_config()
.This method does not alter the timeline.
- Returns:
SPI input data.
- set_config(flags, length, freq, cs)[source]¶
Set the configuration register.
If
SPI_CS_POLARITY
is cleared (cs
active low, the default), “cs
all deasserted” means “allcs_n
bits high”.cs_n
is not mandatory in the pads supplied to the gateware core. Framing and chip selection can also be handled independently through other means, e.g.TTLOut
.If there is a
miso
wire in the pads supplied in the gateware, input and output may be two signals (“4-wire SPI”), otherwisemosi
must be used for both output and input (“3-wire SPI”) andSPI_HALF_DUPLEX
must to be set when reading data or when the slave drives themosi
signal at any point.The first bit output on
mosi
is always the MSB/LSB (depending onSPI_LSB_FIRST
) of thedata
written, independent of thelength
of the transfer. The last bit input frommiso
always ends up in the LSB/MSB (respectively) of thedata
read, independent of thelength
of the transfer.cs
is asserted at the beginning and deasserted at the end of the transaction.cs
handling is agnostic to whether it is one-hot or decoded somewhere downstream. If it is decoded, “cs
all deasserted” should be handled accordingly (no slave selected). If it is one-hot, asserting multiple slaves should only be attempted ifmiso
is either not connected between slaves, or open collector, or correctly multiplexed externally.Changes to the configuration register take effect on the start of the next transfer with the exception of
SPI_OFFLINE
which takes effect immediately.The SPI core can only be written to when it is idle or waiting for the next transfer data. Writing (
set_config()
,set_config_mu()
orwrite()
) when the core is busy will result in an RTIO busy error being logged.
This method advances the timeline by one coarse RTIO clock cycle.
Configuration flags:
SPI_OFFLINE
: all pins high-z (reset=1)SPI_END
: transfer in progress (reset=1)SPI_INPUT
: submit SPI read data as RTIO input event when transfer is complete (reset=0)SPI_CS_POLARITY
: active level ofcs_n
(reset=0)SPI_CLK_POLARITY
: idle level ofclk
(reset=0)SPI_CLK_PHASE
: first edge aftercs
assertion to sample data on (reset=0). In Motorola/Freescale SPI language (SPI_CLK_POLARITY
,SPI_CLK_PHASE
) == (CPOL, CPHA):(0, 0): idle low, output on falling, input on rising
(0, 1): idle low, output on rising, input on falling
(1, 0): idle high, output on rising, input on falling
(1, 1): idle high, output on falling, input on rising
SPI_LSB_FIRST
: LSB is the first bit on the wire (reset=0)SPI_HALF_DUPLEX
: 3-wire SPI, in/out onmosi
(reset=0)
- Parameters:
flags – A bit map of SPI_* flags.
length – Number of bits to write during the next transfer. (reset=1)
freq – Desired SPI clock frequency. (reset=f_rtio/2)
cs – Bit pattern of chip selects to assert. Or number of the chip select to assert if
cs
is decoded downstream. (reset=0)
- set_config_mu(flags, length, div, cs)[source]¶
Set the
config
register (in SPI bus machine units).See also
- Parameters:
flags – A bit map of SPI_* flags.
length – Number of bits to write during the next transfer. (reset=1)
div – Counter load value to divide the RTIO clock by to generate the SPI clock. (minimum=2, reset=2)
f_rtio_clk/f_spi == div
. Ifdiv
is odd, the setup phase of the SPI clock is one coarse RTIO clock cycle longer than the hold phase.cs – Bit pattern of chip selects to assert. Or number of the chip select to assert if
cs
is decoded downstream. (reset=0)
- update_xfer_duration_mu(div, length)[source]¶
Calculate and set the transfer duration.
This method updates the SPI transfer duration which is used in
write()
to advance the timeline.Use this method (and avoid having to call
set_config_mu()
) when the divider and transfer length have been configured (usingset_config()
orset_config_mu()
) by previous experiments and are known.This method is portable and can also be called from e.g.
__init__()
.Warning
If this method is called while recording a DMA sequence, the playback of the sequence will not update the driver state. When required, update the driver state manually (by calling this method) after playing back a DMA sequence.
- Parameters:
div – SPI clock divider (see:
set_config_mu()
)length – SPI transfer length (see:
set_config_mu()
)
- write(data)[source]¶
Write SPI data to shift register register and start transfer.
The
data
register and the shift register are 32 bits wide.Data writes take one
ref_period
cycle.A transaction consisting of a single transfer (
SPI_END
) takesxfer_duration_mu
=(n + 1)*div
cycles RTIO time wheren
is the number of bits anddiv
is the SPI clock divider.Transfers in a multi-transfer transaction take up to one SPI clock cycle less time depending on multiple parameters. Advanced users may rewind the timeline appropriately to achieve faster multi-transfer transactions.
The SPI core will be busy for the duration of the SPI transfer.
For bit alignment and bit ordering see
set_config()
.The SPI core can only be written to when it is idle or waiting for the next transfer data. Writing (
set_config()
,set_config_mu()
orwrite()
) when the core is busy will result in an RTIO busy error being logged.
This method advances the timeline by the duration of one single-transfer SPI transaction (
xfer_duration_mu
).- Parameters:
data – SPI output data to be written.
artiq.coredevice.i2c
module¶
Non-realtime drivers for I2C chips on the core device.
- class artiq.coredevice.i2c.I2CSwitch(dmgr, busno=0, address=232, core_device='core')[source]¶
Driver for the I2C bus switch.
PCA954X (or other) type detection is done by the CPU during I2C init.
I2C transactions not real-time, and are performed by the CPU without involving RTIO.
On the KC705, this chip is used for selecting the I2C buses on the two FMC connectors. HPC=1, LPC=2.
- class artiq.coredevice.i2c.PCF8574A(dmgr, busno=0, address=124, core_device='core')[source]¶
Driver for the PCF8574 I2C remote 8-bit I/O expander.
I2C transactions not real-time, and are performed by the CPU without involving RTIO.
- class artiq.coredevice.i2c.TCA6424A(dmgr, busno=0, address=68, core_device='core')[source]¶
Driver for the TCA6424A I2C I/O expander.
I2C transactions not real-time, and are performed by the CPU without involving RTIO.
On the NIST QC2 hardware, this chip is used for switching the directions of TTL buffers.
- artiq.coredevice.i2c.i2c_poll(busno, busaddr)[source]¶
Poll I2C device at address.
- Parameters:
busno – I2C bus number
busaddr – 8 bit I2C device address (LSB=0)
- Returns:
True if the poll was ACKed
- artiq.coredevice.i2c.i2c_read_byte(busno, busaddr)[source]¶
Read one byte from a device.
- Parameters:
busno – I2C bus number
busaddr – 8 bit I2C device address (LSB=0)
- Returns:
Byte read
- artiq.coredevice.i2c.i2c_read_many(busno, busaddr, addr, data)[source]¶
Transfer multiple bytes from a device.
- Parameters:
busno – I2c bus number
busaddr – 8 bit I2C device address (LSB=0)
addr – 8 bit data address
data – List of integers to be filled with the data read. One entry ber byte.
- artiq.coredevice.i2c.i2c_write_byte(busno, busaddr, data, ack=True)[source]¶
Write one byte to a device.
- Parameters:
busno – I2C bus number
busaddr – 8 bit I2C device address (LSB=0)
data – Data byte to be written
nack – Allow NACK
- artiq.coredevice.i2c.i2c_write_many(busno, busaddr, addr, data, ack_last=True)[source]¶
Transfer multiple bytes to a device.
- Parameters:
busno – I2c bus number
busaddr – 8 bit I2C device address (LSB=0)
addr – 8 bit data address
data – Data bytes to be written
ack_last – Expect I2C ACK of the last byte written. If False, the last byte may be NACKed (e.g. EEPROM full page writes).
RF generation drivers¶
artiq.coredevice.urukul
module¶
- class artiq.coredevice.urukul.CPLD(dmgr, spi_device, io_update_device=None, dds_reset_device=None, sync_device=None, sync_sel=0, clk_sel=0, clk_div=0, rf_sw=0, refclk=125000000.0, att=0, sync_div=None, core_device='core')[source]¶
Urukul CPLD SPI router and configuration interface.
- Parameters:
spi_device – SPI bus device name
io_update_device – IO update RTIO TTLOut channel name
dds_reset_device – DDS reset RTIO TTLOut channel name
sync_device – AD9910 SYNC_IN RTIO TTLClockGen channel name
refclk – Reference clock (SMA, MMCX or on-board 100 MHz oscillator) frequency in Hz
clk_sel – Reference clock selection. For hardware revision >= 1.3 valid options are: 0 - internal 100MHz XO; 1 - front-panel SMA; 2 internal MMCX. For hardware revision <= v1.2 valid options are: 0 - either XO or MMCX dependent on component population; 1 SMA. Unsupported clocking options are silently ignored.
clk_div – Reference clock divider. Valid options are 0: variant dependent default (divide-by-4 for AD9910 and divide-by-1 for AD9912); 1: divide-by-1; 2: divide-by-2; 3: divide-by-4. On Urukul boards with CPLD gateware before v1.3.1 only the default (0, i.e. variant dependent divider) is valid.
sync_sel – SYNC (multi-chip synchronisation) signal source selection. 0 corresponds to SYNC_IN being supplied by the FPGA via the EEM connector. 1 corresponds to SYNC_OUT from DDS0 being distributed to the other chips.
rf_sw – Initial CPLD RF switch register setting (default: 0x0). Knowledge of this state is not transferred between experiments.
att – Initial attenuator setting shift register (default: 0x00000000). See also
get_att_mu()
which retrieves the hardware state without side effects. Knowledge of this state is not transferred between experiments.sync_div – SYNC_IN generator divider. The ratio between the coarse RTIO frequency and the SYNC_IN generator frequency (default: 2 if sync_device was specified).
core_device – Core device name
If the clocking is incorrect (for example, setting
clk_sel
to the front panel SMA with no clock connected), then theinit()
method of the DDS channels can fail with the error messagePLL lock timeout
.- att_to_mu(att: float) numpy.int32 [source]¶
Convert an attenuation setting in dB to machine units.
- Parameters:
att – Attenuation setting in dB.
- Returns:
Digital attenuation setting.
- cfg_sw(channel: numpy.int32, on: bool)[source]¶
Configure the RF switches through the configuration register.
These values are logically OR-ed with the LVDS lines on EEM1.
- Parameters:
channel – Channel index (0-3)
on – Switch value
- cfg_switches(state: numpy.int32)[source]¶
Configure all four RF switches through the configuration register.
- Parameters:
state – RF switch state as a 4 bit integer.
- cfg_write(cfg: numpy.int32)[source]¶
Write to the configuration register.
See
urukul_cfg()
for possible flags.- Parameters:
cfg – 24 bit data to be written. Will be stored at
cfg_reg
.
- get_att_mu() numpy.int32 [source]¶
Return the digital step attenuator settings in machine units.
The result is stored and will be used in future calls of
set_att_mu()
andset_att()
.See also
- Returns:
32 bit attenuator settings
- get_channel_att(channel: numpy.int32) float [source]¶
Get digital step attenuator value for a channel in SI units.
See also
- Parameters:
channel – Attenuator channel (0-3).
- Returns:
Attenuation setting in dB. Higher value is more attenuation. Minimum attenuation is 0*dB, maximum attenuation is 31.5*dB.
- get_channel_att_mu(channel: numpy.int32) numpy.int32 [source]¶
Get digital step attenuator value for a channel in machine units.
The result is stored and will be used in future calls of
set_att_mu()
andset_att()
.See also
- Parameters:
channel – Attenuator channel (0-3).
- Returns:
8-bit digital attenuation setting: 255 minimum attenuation, 0 maximum attenuation (31.5 dB)
- init(blind: bool = False)[source]¶
Initialize and detect Urukul.
Resets the DDS I/O interface and verifies correct CPLD gateware version. Does not pulse the DDS MASTER_RESET as that confuses the AD9910.
- Parameters:
blind – Do not attempt to verify presence and compatibility.
- mu_to_att(att_mu: numpy.int32) float [source]¶
Convert a digital attenuation setting to dB.
- Parameters:
att_mu – Digital attenuation setting.
- Returns:
Attenuation setting in dB.
- set_all_att_mu(att_reg: numpy.int32)[source]¶
Set all four digital step attenuators (in machine units).
See also
- Parameters:
att_reg – Attenuator setting string (32 bit)
- set_att(channel: numpy.int32, att: float)[source]¶
Set digital step attenuator in SI units.
This method will write the attenuator settings of all four channels.
See also
- Parameters:
channel – Attenuator channel (0-3).
att – Attenuation setting in dB. Higher value is more attenuation. Minimum attenuation is 0*dB, maximum attenuation is 31.5*dB.
- set_att_mu(channel: numpy.int32, att: numpy.int32)[source]¶
Set digital step attenuator in machine units.
This method will also write the attenuator settings of the three other channels. Use
get_att_mu()
to retrieve the hardware state set in previous experiments.- Parameters:
channel – Attenuator channel (0-3).
att – 8-bit digital attenuation setting: 255 minimum attenuation, 0 maximum attenuation (31.5 dB)
- set_profile(profile: numpy.int32)[source]¶
Set the PROFILE pins.
The PROFILE pins are common to all four DDS channels.
- Parameters:
profile – PROFILE pins in numeric representation (0-7).
- set_sync_div(div: numpy.int32)[source]¶
Set the SYNC_IN AD9910 pulse generator frequency and align it to the current RTIO timestamp.
The SYNC_IN signal is derived from the coarse RTIO clock and the divider must be a power of two. Configure
sync_sel == 0
.- Parameters:
div – SYNC_IN frequency divider. Must be a power of two. Minimum division ratio is 2. Maximum division ratio is 16.
- artiq.coredevice.urukul.urukul_cfg(rf_sw, led, profile, io_update, mask_nu, clk_sel, sync_sel, rst, io_rst, clk_div)[source]¶
Build Urukul CPLD configuration register
- artiq.coredevice.urukul.urukul_sta_ifc_mode(sta)[source]¶
Return the IFC_MODE status from Urukul status register value.
- artiq.coredevice.urukul.urukul_sta_pll_lock(sta)[source]¶
Return the PLL_LOCK status from Urukul status register value.
- artiq.coredevice.urukul.urukul_sta_proto_rev(sta)[source]¶
Return the PROTO_REV value from Urukul status register value.
artiq.coredevice.ad9910
module¶
- class artiq.coredevice.ad9910.AD9910(dmgr, chip_select, cpld_device, sw_device=None, pll_n=40, pll_cp=7, pll_vco=5, sync_delay_seed=- 1, io_update_delay=0, pll_en=1)[source]¶
AD9910 DDS channel on Urukul.
This class supports a single DDS channel and exposes the DDS, the digital step attenuator, and the RF switch.
- Parameters:
chip_select – Chip select configuration. On Urukul this is an encoded chip select and not “one-hot”: 3 to address multiple chips (as configured through CFG_MASK_NU), 4-7 for individual channels.
cpld_device – Name of the Urukul CPLD this device is on.
sw_device – Name of the RF switch device. The RF switch is a TTLOut channel available as the
sw
attribute of this instance.pll_n – DDS PLL multiplier. The DDS sample clock is f_ref/clk_div*pll_n where f_ref is the reference frequency and clk_div is the reference clock divider (both set in the parent Urukul CPLD instance).
pll_en – PLL enable bit, set to 0 to bypass PLL (default: 1). Note that when bypassing the PLL the red front panel LED may remain on.
pll_cp – DDS PLL charge pump setting.
pll_vco – DDS PLL VCO range selection.
sync_delay_seed – SYNC_IN delay tuning starting value. To stabilize the SYNC_IN delay tuning, run
tune_sync_delay()
once and set this to the delay tap number returned (default: -1 to signal no synchronization and no tuning duringinit()
). Can be a string of the form “eeprom_device:byte_offset” to read the value from a I2C EEPROM; in which case, io_update_delay must be set to the same string value.io_update_delay – IO_UPDATE pulse alignment delay. To align IO_UPDATE to SYNC_CLK, run
tune_io_update_delay()
and set this to the delay tap number returned. Can be a string of the form “eeprom_device:byte_offset” to read the value from a I2C EEPROM; in which case, sync_delay_seed must be set to the same string value.
- amplitude_to_asf(amplitude: float) numpy.int32 [source]¶
Return 14-bit amplitude scale factor corresponding to given fractional amplitude.
- amplitude_to_ram(amplitude: list(elt=float), ram: list(elt=numpy.int32))[source]¶
Convert amplitude values to RAM profile data.
To be used with
RAM_DEST_ASF
.- Parameters:
amplitude – List of amplitude values in units of full scale.
ram – List to write RAM data into. Suitable for
write_ram()
.
- asf_to_amplitude(asf: numpy.int32) float [source]¶
Return amplitude as a fraction of full scale corresponding to given amplitude scale factor.
- cfg_sw(state: bool)[source]¶
Set CPLD CFG RF switch state. The RF switch is controlled by the logical or of the CPLD configuration shift register RF switch bit and the SW TTL line (if used).
- Parameters:
state – CPLD CFG RF switch bit
- clear_smp_err()[source]¶
Clear the SMP_ERR flag and enables SMP_ERR validity monitoring.
Violations of the SYNC_IN sample and hold margins will result in SMP_ERR being asserted. This then also activates the red LED on the respective Urukul channel.
Also modifies CFR2.
- frequency_to_ftw(frequency: float) numpy.int32 [source]¶
Return the 32-bit frequency tuning word corresponding to the given frequency.
- frequency_to_ram(frequency: list(elt=float), ram: list(elt=numpy.int32))[source]¶
Convert frequency values to RAM profile data.
To be used with
RAM_DEST_FTW
.- Parameters:
frequency – List of frequency values in Hz.
ram – List to write RAM data into. Suitable for
write_ram()
.
- ftw_to_frequency(ftw: numpy.int32) float [source]¶
Return the frequency corresponding to the given frequency tuning word.
- get(profile: numpy.int32 = 7)[source]¶
Get the frequency, phase, and amplitude.
See also
- Parameters:
profile – Profile number to get (0-7, default: 7)
- Returns:
A tuple
(frequency, phase, amplitude)
- get_amplitude() float [source]¶
Get the value stored to the AD9910’s amplitude scale factor (ASF) register.
- Returns:
amplitude in units of full scale.
- get_asf() numpy.int32 [source]¶
Get the value stored to the AD9910’s amplitude scale factor (ASF) register.
- Returns:
Amplitude scale factor
- get_att() float [source]¶
Get digital step attenuator value in SI units.
- Returns:
Attenuation in dB.
- get_att_mu() numpy.int32 [source]¶
Get digital step attenuator value in machine units.
- Returns:
Attenuation setting, 8 bit digital.
- get_frequency() float [source]¶
Get the value stored to the AD9910’s frequency tuning word (FTW) register.
- Returns:
frequency in Hz.
- get_ftw() numpy.int32 [source]¶
Get the value stored to the AD9910’s frequency tuning word (FTW) register.
- Returns:
Frequency tuning word
- get_mu(profile: numpy.int32 = 7)[source]¶
Get the frequency tuning word, phase offset word, and amplitude scale factor.
See also
- Parameters:
profile – Profile number to get (0-7, default: 7)
- Returns:
A tuple
(ftw, pow, asf)
- get_phase() float [source]¶
Get the value stored to the AD9910’s phase offset word (POW) register.
- Returns:
phase offset in turns.
- get_pow() numpy.int32 [source]¶
Get the value stored to the AD9910’s phase offset word (POW) register.
- Returns:
Phase offset word
- init(blind: bool = False)[source]¶
Initialize and configure the DDS.
Sets up SPI mode, confirms chip presence, powers down unused blocks, configures the PLL, waits for PLL lock. Uses the IO_UPDATE signal multiple times.
- Parameters:
blind – Do not read back DDS identity and do not wait for lock.
- measure_io_update_alignment(delay_start: numpy.int64, delay_stop: numpy.int64) numpy.int32 [source]¶
Use the digital ramp generator to locate the alignment between IO_UPDATE and SYNC_CLK.
The ramp generator is set up to a linear frequency ramp (dFTW/t_SYNC_CLK=1) and started at a coarse RTIO time stamp plus delay_start and stopped at a coarse RTIO time stamp plus delay_stop.
- Parameters:
delay_start – Start IO_UPDATE delay in machine units.
delay_stop – Stop IO_UPDATE delay in machine units.
- Returns:
Odd/even SYNC_CLK cycle indicator.
- pow_to_turns(pow_: numpy.int32) float [source]¶
Return the phase in turns corresponding to a given phase offset word.
- power_down(bits: numpy.int32 = 15)[source]¶
Power down DDS.
- Parameters:
bits – Power down bits, see datasheet
- read16(addr: numpy.int32) numpy.int32 [source]¶
Read from 16 bit register.
- Parameters:
addr – Register address
- read32(addr: numpy.int32) numpy.int32 [source]¶
Read from 32 bit register.
- Parameters:
addr – Register address
- read64(addr: numpy.int32) numpy.int64 [source]¶
Read from 64 bit register.
- Parameters:
addr – Register address
- Returns:
64 bit integer register value
- read_ram(data: list(elt=numpy.int32))[source]¶
Read data from RAM.
The profile to read from and the step, start, and end address need to be configured before and separately using
set_profile_ram()
and the parent CPLD set_profile.- Parameters:
data – List to be filled with data read from RAM.
- set(frequency: float = 0.0, phase: float = 0.0, amplitude: float = 1.0, phase_mode: numpy.int32 = -1, ref_time_mu: numpy.int64 = <Mock name='mock.int64()' id='140737286669456'>, profile: numpy.int32 = 7, ram_destination: numpy.int32 = -1) float [source]¶
Set DDS data in SI units.
See also
- Parameters:
frequency – Frequency in Hz
phase – Phase tuning word in turns
amplitude – Amplitude in units of full scale
phase_mode – Phase mode constant
ref_time_mu – Fiducial time stamp in machine units
profile – Single tone profile to affect.
ram_destination – RAM destination.
- Returns:
Resulting phase offset in turns
- set_amplitude(amplitude: float)[source]¶
Set the value stored to the AD9910’s amplitude scale factor (ASF) register.
- Parameters:
amplitude – amplitude to be stored, in units of full scale.