-
Notifications
You must be signed in to change notification settings - Fork 201
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* spimaster: (52 commits) runtime/rtio: rtio_process_exceptional_status() has only one user coredevice.spi, doc/manual: add spi kc705: move ttl channels together again, update doc runtime: rt2wb_input -> rtio_input_data examples/tdr: adapt to compiler changes bridge: really fix O/OE runtime: define constants for ttl addresses coredevice.ttl: fix sensitivity bridge: fix ttl o/oe addresses runtime: refactor ttl*() rtio: rm rtio_write_and_process_status coredevice.spi: unused import rt2wb, exceptions: remove RTIOTimeout gateware.spi: delay only writes to data register, update doc nist_clock: disable spi1/2 runtime/rt2wb: use input/output terminology and add (async) input examples: update device_db for nist_clock spi gateware.spi: rework wb bus sequence nist_clock: rename spi*.ce to spi*.cs_n nist_clock: add SPIMasters to spi buses ...
Showing
21 changed files
with
973 additions
and
159 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from artiq.language.core import syscall | ||
from artiq.language.types import TInt64, TInt32, TNone | ||
|
||
|
||
@syscall | ||
def rtio_output(time_mu: TInt64, channel: TInt32, addr: TInt32, data: TInt32 | ||
) -> TNone: | ||
raise NotImplementedError("syscall not simulated") | ||
|
||
|
||
@syscall | ||
def rtio_input_timestamp(timeout_mu: TInt64, channel: TInt32) -> TInt64: | ||
raise NotImplementedError("syscall not simulated") | ||
|
||
|
||
@syscall | ||
def rtio_input_data(channel: TInt32) -> TInt32: | ||
raise NotImplementedError("syscall not simulated") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,246 @@ | ||
from artiq.language.core import (kernel, seconds_to_mu, now_mu, | ||
delay_mu, int) | ||
from artiq.language.units import MHz | ||
from artiq.coredevice.rtio import rtio_output, rtio_input_data | ||
|
||
|
||
SPI_DATA_ADDR, SPI_XFER_ADDR, SPI_CONFIG_ADDR = range(3) | ||
( | ||
SPI_OFFLINE, | ||
SPI_ACTIVE, | ||
SPI_PENDING, | ||
SPI_CS_POLARITY, | ||
SPI_CLK_POLARITY, | ||
SPI_CLK_PHASE, | ||
SPI_LSB_FIRST, | ||
SPI_HALF_DUPLEX, | ||
) = (1 << i for i in range(8)) | ||
|
||
SPI_RT2WB_READ = 1 << 2 | ||
|
||
|
||
class SPIMaster: | ||
"""Core device Serial Peripheral Interface (SPI) bus master. | ||
Owns one SPI bus. | ||
**Transfer Sequence**: | ||
* If desired, write the ``config`` register (:meth:`set_config`) | ||
to configure and activate the core. | ||
* If desired, write the ``xfer`` register (:meth:`set_xfer`) | ||
to set ``cs_n``, ``write_length``, and ``read_length``. | ||
* :meth:`write` to the ``data`` register (also for transfers with | ||
zero bits to be written). Writing starts the transfer. | ||
* If desired, :meth:`read_sync` (or :meth:`read_async` followed by a | ||
:meth:`input_async` later) the ``data`` register corresponding to | ||
the last completed transfer. | ||
* If desired, :meth:`set_xfer` for the next transfer. | ||
* If desired, :meth:`write` ``data`` queuing the next | ||
(possibly chained) transfer. | ||
:param ref_period: clock period of the SPI core. | ||
:param channel: RTIO channel number of the SPI bus to control. | ||
""" | ||
def __init__(self, dmgr, ref_period, channel): | ||
self.core = dmgr.get("core") | ||
self.ref_period = ref_period | ||
self.ref_period_mu = int(seconds_to_mu(ref_period, self.core)) | ||
self.channel = channel | ||
self.write_period_mu = int(0) | ||
self.read_period_mu = int(0) | ||
self.xfer_period_mu = int(0) | ||
# A full transfer takes write_period_mu + xfer_period_mu. | ||
# Chained transfers can happen every xfer_period_mu. | ||
# The second transfer of a chain can be written 2*ref_period_mu | ||
# after the first. Read data is available every xfer_period_mu starting | ||
# a bit after xfer_period_mu (depending on clk_phase). | ||
# To chain transfers together, new data must be written before | ||
# pending transfer's read data becomes available. | ||
|
||
@kernel | ||
def set_config(self, flags=0, write_freq=20*MHz, read_freq=20*MHz): | ||
"""Set the configuration register. | ||
* If ``config.cs_polarity`` == 0 (```cs`` active low, the default), | ||
"``cs_n`` all deasserted" means "all ``cs_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"), | ||
otherwise ``mosi`` must be used for both output and input | ||
("3-wire SPI") and ``config.half_duplex`` must to be set | ||
when reading data is desired or when the slave drives the | ||
``mosi`` signal at any point. | ||
* The first bit output on ``mosi`` is always the MSB/LSB (depending | ||
on ``config.lsb_first``) of the ``data`` register, independent of | ||
``xfer.write_length``. The last bit input from ``miso`` always ends | ||
up in the LSB/MSB (respectively) of the ``data`` register, | ||
independent of ``xfer.read_length``. | ||
* Writes to the ``config`` register take effect immediately. | ||
**Configuration flags**: | ||
* :const:`SPI_OFFLINE`: all pins high-z (reset=1) | ||
* :const:`SPI_ACTIVE`: transfer in progress (read-only) | ||
* :const:`SPI_PENDING`: transfer pending in intermediate buffer | ||
(read-only) | ||
* :const:`SPI_CS_POLARITY`: active level of ``cs_n`` (reset=0) | ||
* :const:`SPI_CLK_POLARITY`: idle level of ``clk`` (reset=0) | ||
* :const:`SPI_CLK_PHASE`: first edge after ``cs`` assertion to sample | ||
data on (reset=0). In Motorola/Freescale SPI language | ||
(:const:`SPI_CLK_POLARITY`, :const:`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 | ||
* :const:`SPI_LSB_FIRST`: LSB is the first bit on the wire (reset=0) | ||
* :const:`SPI_HALF_DUPLEX`: 3-wire SPI, in/out on ``mosi`` (reset=0) | ||
This method advances the timeline by the duration of the | ||
RTIO-to-Wishbone bus transaction (three RTIO clock cycles). | ||
:param flags: A bit map of `SPI_*` flags. | ||
:param write_freq: Desired SPI clock frequency during write bits. | ||
:param read_freq: Desired SPI clock frequency during read bits. | ||
""" | ||
write_div = round(1/(write_freq*self.ref_period)) | ||
read_div = round(1/(read_freq*self.ref_period)) | ||
self.set_config_mu(flags, write_div, read_div) | ||
|
||
@kernel | ||
def set_config_mu(self, flags=0, write_div=6, read_div=6): | ||
"""Set the ``config`` register (in SPI bus machine units). | ||
.. seealso:: :meth:`set_config` | ||
:param write_div: Counter load value to divide the RTIO | ||
clock by to generate the SPI write clk. (minimum=2, reset=2) | ||
``f_rtio_clk/f_spi_write == write_div``. If ``write_div`` is odd, | ||
the setup phase of the SPI clock is biased to longer lengths | ||
by one RTIO clock cycle. | ||
:param read_div: Ditto for the read clock. | ||
""" | ||
rtio_output(now_mu(), self.channel, SPI_CONFIG_ADDR, flags | | ||
((write_div - 2) << 16) | ((read_div - 2) << 24)) | ||
self.write_period_mu = int(write_div*self.ref_period_mu) | ||
self.read_period_mu = int(read_div*self.ref_period_mu) | ||
delay_mu(3*self.ref_period_mu) | ||
|
||
@kernel | ||
def set_xfer(self, chip_select=0, write_length=0, read_length=0): | ||
"""Set the ``xfer`` register. | ||
* Every transfer consists of a write of ``write_length`` bits | ||
immediately followed by a read of ``read_length`` bits. | ||
* ``cs_n`` is asserted at the beginning and deasserted at the end | ||
of the transfer if there is no other transfer pending. | ||
* ``cs_n`` handling is agnostic to whether it is one-hot or decoded | ||
somewhere downstream. If it is decoded, "``cs_n`` all deasserted" | ||
should be handled accordingly (no slave selected). | ||
If it is one-hot, asserting multiple slaves should only be attempted | ||
if ``miso`` is either not connected between slaves, or open | ||
collector, or correctly multiplexed externally. | ||
* For 4-wire SPI only the sum of ``read_length`` and ``write_length`` | ||
matters. The behavior is the same (except for clock speeds) no matter | ||
how the total transfer length is divided between the two. For | ||
3-wire SPI, the direction of ``mosi`` is switched from output to | ||
input after ``write_length`` bits. | ||
* Data output on ``mosi`` in 4-wire SPI during the read cycles is what | ||
is found in the data register at the time. | ||
Data in the ``data`` register outside the least/most (depending | ||
on ``config.lsb_first``) significant ``read_length`` bits is what is | ||
seen on ``miso`` (or ``mosi`` if ``config.half_duplex``) | ||
during the write cycles. | ||
* Writes to ``xfer`` are synchronized to the start of the next | ||
(possibly chained) transfer. | ||
This method advances the timeline by the duration of the | ||
RTIO-to-Wishbone bus transaction (three RTIO clock cycles). | ||
:param chip_select: Bit mask of chip selects to assert. Or number of | ||
the chip select to assert if ``cs`` is decoded downstream. | ||
(reset=0) | ||
:param write_length: Number of bits to write during the next transfer. | ||
(reset=0) | ||
:param read_length: Number of bits to read during the next transfer. | ||
(reset=0) | ||
""" | ||
rtio_output(now_mu(), self.channel, SPI_XFER_ADDR, | ||
chip_select | (write_length << 16) | (read_length << 24)) | ||
self.xfer_period_mu = int(write_length*self.write_period_mu + | ||
read_length*self.read_period_mu) | ||
delay_mu(3*self.ref_period_mu) | ||
|
||
@kernel | ||
def write(self, data): | ||
"""Write data to data register. | ||
* The ``data`` register and the shift register are 32 bits wide. | ||
If there are no writes to the register, ``miso`` data reappears on | ||
``mosi`` after 32 cycles. | ||
* A wishbone data register write is acknowledged when the | ||
transfer has been written to the intermediate buffer. | ||
It will be started when there are no other transactions being | ||
executed, either beginning a new SPI transfer of chained | ||
to an in-flight transfer. | ||
* Writes take three ``ref_period`` cycles unless another | ||
chained transfer is pending and the transfer being | ||
executed is not complete. | ||
* The SPI ``data`` register is double-buffered: Once a transfer has | ||
started, new write data can be written, queuing a new transfer. | ||
Transfers submitted this way are chained and executed without | ||
deasserting ``cs`` in between. Once a transfer completes, | ||
the previous transfer's read data is available in the | ||
``data`` register. | ||
This method advances the timeline by the duration of the | ||
RTIO-to-Wishbone bus transaction (three RTIO clock cycles). | ||
""" | ||
rtio_output(now_mu(), self.channel, SPI_DATA_ADDR, data) | ||
delay_mu(3*self.ref_period_mu) | ||
|
||
@kernel | ||
def read_async(self): | ||
"""Trigger an asynchronous read from the data register. | ||
Reads always finish in two cycles. | ||
Every data register read triggered by a :meth:`read_async` | ||
must be matched by a :meth:`input_async` to retrieve the data. | ||
This method advances the timeline by the duration of the | ||
RTIO-to-Wishbone bus transaction (three RTIO clock cycles). | ||
""" | ||
rtio_output(now_mu(), self.channel, SPI_DATA_ADDR | SPI_RT2WB_READ, 0) | ||
delay_mu(3*self.ref_period_mu) | ||
|
||
@kernel | ||
def input_async(self): | ||
"""Retrieves data written asynchronously. | ||
:meth:`input_async` must match a preeeding :meth:`read_async`. | ||
""" | ||
return rtio_input_data(self.channel) | ||
|
||
@kernel | ||
def read_sync(self): | ||
"""Read the ``data`` register synchronously. | ||
This is a shortcut for :meth:`read_async` followed by | ||
:meth:`input_async`. | ||
""" | ||
self.read_async() | ||
return self.input_async() | ||
|
||
@kernel | ||
def _get_xfer_sync(self): | ||
rtio_output(now_mu(), self.channel, SPI_XFER_ADDR | SPI_RT2WB_READ, 0) | ||
return rtio_input_data(self.channel) | ||
|
||
@kernel | ||
def _get_config_sync(self): | ||
rtio_output(now_mu(), self.channel, SPI_CONFIG_ADDR | SPI_RT2WB_READ, | ||
0) | ||
return rtio_input_data(self.channel) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
from migen import * | ||
|
||
from artiq.gateware.spi import SPIMaster as SPIMasterWB | ||
from artiq.gateware.rtio.phy.wishbone import RT2WB | ||
|
||
|
||
class SPIMaster(Module): | ||
def __init__(self, pads, **kwargs): | ||
self.submodules._ll = ClockDomainsRenamer("rio")( | ||
SPIMasterWB(pads, **kwargs)) | ||
self.submodules._rt2wb = RT2WB(2, self._ll.bus) | ||
self.rtlink = self._rt2wb.rtlink | ||
self.probes = [] |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,8 @@ | ||
#ifndef __TTL_H | ||
#define __TTL_H | ||
|
||
void ttl_set_o(long long int timestamp, int channel, int value); | ||
void ttl_set_oe(long long int timestamp, int channel, int oe); | ||
void ttl_set_sensitivity(long long int timestamp, int channel, int sensitivity); | ||
long long int ttl_get(int channel, long long int time_limit); | ||
void ttl_clock_set(long long int timestamp, int channel, int ftw); | ||
#define TTL_O_ADDR 0 | ||
#define TTL_OE_ADDR 1 | ||
#define TTL_SENSITIVITY_ADDR 2 | ||
|
||
#endif /* __TTL_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters