mirror of
https://github.com/m-labs/artiq.git
synced 2024-12-25 03:08:27 +08:00
gateware.spi: design sketch
This commit is contained in:
parent
fb929c8599
commit
e7146cc999
13
artiq/gateware/rtio/phy/spi.py
Normal file
13
artiq/gateware/rtio/phy/spi.py
Normal file
@ -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, onehot=False, **kwargs):
|
||||
self.submodules._ll = ClockDomainsRenamer("rio")(
|
||||
SPIMasterWB(pads, **kwargs))
|
||||
self.submodules._rt2wb = RT2WB(2, self._ll.bus)
|
||||
self.rtlink = self._rt2wb.rtlink
|
||||
self.probes = []
|
109
artiq/gateware/spi.py
Normal file
109
artiq/gateware/spi.py
Normal file
@ -0,0 +1,109 @@
|
||||
from migen import *
|
||||
from migen.genlib.fsm import *
|
||||
from migen.genlib.misc import WaitTimer
|
||||
from misoc.interconnect import wishbone
|
||||
|
||||
|
||||
class SPIMaster(Module):
|
||||
"""SPI Master.
|
||||
|
||||
Notes:
|
||||
* If there is a miso wire in pads, the input and output are done with
|
||||
two signals (a.k.a. 4-wire SPI), else mosi is used for both output
|
||||
and input (a.k.a. 3-wire SPI).
|
||||
* Every transfer consists of a 0-32 bit write followed by a 0-32
|
||||
bit read.
|
||||
* cs_n is always asserted at the beginning and deasserted
|
||||
at the end of the tranfer.
|
||||
* 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.
|
||||
* If config.cs_polarity == 0 (cs active low, the default),
|
||||
"cs_n all deasserted" means "all cs_n bits high".
|
||||
* The first bit output on mosi is always the MSB/LSB (depending on
|
||||
config.lsb_first) of the data register, independent of
|
||||
xfer.write_len. The last bit input from miso always ends up in
|
||||
the LSB/MSB (respectively) of the data register, independent of
|
||||
read_len.
|
||||
* For 4-wire SPI only the sum of read_len and write_len matters. The
|
||||
behavior is the same no matter how the transfer length is divided
|
||||
between the two. For 3-wire SPI, the direction of mosi/miso is
|
||||
switched from output to input after write_len cycles, at the
|
||||
"output" clk edge corresponding to bit write_len + 1 of the transfer.
|
||||
* Data output on mosi in 4-wire SPI during the read cycles is
|
||||
undefined. Data in the data register outside the
|
||||
least/most (depending on config.lsb_first) significant read_len
|
||||
bits is undefined.
|
||||
* The transfer is complete when the wishbone transaction is ack-ed.
|
||||
* Input data from the last transaction can be read from the data
|
||||
register at any time.
|
||||
|
||||
Transaction Sequence:
|
||||
* if desired, write the xfer register to change lengths and cs_n.
|
||||
* write the data register (also for zero-length writes),
|
||||
writing triggers the transfer and the transfer is complete when the
|
||||
write is complete.
|
||||
* if desired, read the data register
|
||||
|
||||
Register address and bit map:
|
||||
|
||||
config (address 0):
|
||||
1 offline: all pins high-z (reset=1)
|
||||
1 cs_polarity: active level of chip select (reset=0)
|
||||
1 clk_polarity: idle level for clk (reset=0)
|
||||
1 clk_phase: first edge after cs assertion to sample data on (reset=0)
|
||||
(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
|
||||
1 lsb_first: LSB is the first bit on the wire (reset=0)
|
||||
11 undefined
|
||||
16 speed: divider from this module's clock to the SPI clk
|
||||
(minimum=2, reset=4)
|
||||
clk pulses are asymmetric if speed is odd, favoring longer setup
|
||||
over hold times
|
||||
|
||||
xfer (address 1):
|
||||
16 cs: active high bit mask of chip selects to assert
|
||||
6 write_len: 0-32 bits
|
||||
2 undefined
|
||||
6 read_len: 0-32 bits
|
||||
2 undefined
|
||||
|
||||
data (address 2):
|
||||
32 write/read data
|
||||
"""
|
||||
def __init__(self, pads, bus=None):
|
||||
if bus is None:
|
||||
bus = wishbone.Interface(data_width=32)
|
||||
self.bus = bus
|
||||
|
||||
###
|
||||
|
||||
|
||||
def _test_gen(bus):
|
||||
yield from bus.write(0, 0 | (5 << 16))
|
||||
yield
|
||||
yield from bus.write(1, 1 | (24 << 16) | (16 << 24))
|
||||
yield
|
||||
yield from bus.write(2, 0x12345678)
|
||||
yield
|
||||
r = (yield from bus.read(2))
|
||||
print(r)
|
||||
yield
|
||||
|
||||
|
||||
class _TestPads:
|
||||
def __init__(self):
|
||||
self.cs_n = Signal(3)
|
||||
self.clk = Signal()
|
||||
self.mosi = Signal()
|
||||
self.miso = Signal()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pads = _TestPads()
|
||||
dut = SPIMaster(pads)
|
||||
run_simulation(dut, _test_gen(dut.bus), vcd_name="spi_master.vcd")
|
Loading…
Reference in New Issue
Block a user