mirror of https://github.com/m-labs/artiq.git
117 lines
4.2 KiB
Python
117 lines
4.2 KiB
Python
from migen import *
|
|
|
|
from misoc.cores.spi2 import SPIMachine, SPIInterfaceXC7Diff, SPIInterface
|
|
from artiq.gateware.rtio import rtlink
|
|
|
|
|
|
class SPIMaster(Module):
|
|
"""
|
|
RTIO SPI Master version 2.
|
|
|
|
Register address and bit map:
|
|
|
|
data (address 0):
|
|
32 write/read data
|
|
|
|
config (address 1):
|
|
1 offline: all pins high-z (reset=1)
|
|
1 end: end transaction with next transfer (reset=1)
|
|
1 input: submit read data on RTIO input when readable (reset=0)
|
|
1 cs_polarity: active level of chip select (reset=0)
|
|
1 clk_polarity: idle level of clk (reset=0)
|
|
1 clk_phase: first edge after cs assertion to sample data on (reset=0)
|
|
(clk_polarity, clk_phase) == (CPOL, CPHA) in Freescale language.
|
|
(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
|
|
There is never a clk edge during a cs edge.
|
|
1 lsb_first: LSB is the first bit on the wire (reset=0)
|
|
1 half_duplex: 3-wire SPI, in/out on mosi (reset=0)
|
|
5 length: 1-32 bits = length + 1 (reset=0)
|
|
3 padding
|
|
8 div: counter load value to divide this module's clock
|
|
to generate the SPI write clk (reset=0)
|
|
f_clk/f_spi == div + 2
|
|
8 cs: active high bit pattern of chip selects (reset=0)
|
|
"""
|
|
def __init__(self, pads, pads_n=None):
|
|
to_rio_phy = ClockDomainsRenamer("rio_phy")
|
|
if pads_n is None:
|
|
interface = SPIInterface(pads)
|
|
else:
|
|
interface = SPIInterfaceXC7Diff(pads, pads_n)
|
|
interface = to_rio_phy(interface)
|
|
spi = to_rio_phy(SPIMachine(data_width=32, div_width=8))
|
|
self.submodules += interface, spi
|
|
|
|
self.rtlink = rtlink.Interface(
|
|
rtlink.OInterface(len(spi.reg.pdo), address_width=1,
|
|
enable_replace=False),
|
|
rtlink.IInterface(len(spi.reg.pdi), timestamped=False)
|
|
)
|
|
|
|
###
|
|
|
|
config = Record([
|
|
("offline", 1),
|
|
("end", 1),
|
|
("input", 1),
|
|
("cs_polarity", 1),
|
|
("clk_polarity", 1),
|
|
("clk_phase", 1),
|
|
("lsb_first", 1),
|
|
("half_duplex", 1),
|
|
("length", 5),
|
|
("padding", 3),
|
|
("div", 8),
|
|
("cs", 8),
|
|
])
|
|
assert len(config) == len(spi.reg.pdo) == len(spi.reg.pdi) == 32
|
|
|
|
config.offline.reset = 1
|
|
config.end.reset = 1
|
|
read = Signal()
|
|
|
|
self.sync.rio_phy += [
|
|
If(self.rtlink.i.stb,
|
|
read.eq(0)
|
|
),
|
|
If(self.rtlink.o.stb & spi.writable,
|
|
If(self.rtlink.o.address,
|
|
config.raw_bits().eq(self.rtlink.o.data)
|
|
).Else(
|
|
read.eq(config.input)
|
|
)
|
|
),
|
|
]
|
|
|
|
self.comb += [
|
|
spi.length.eq(config.length),
|
|
spi.end.eq(config.end),
|
|
spi.cg.div.eq(config.div),
|
|
spi.clk_phase.eq(config.clk_phase),
|
|
spi.reg.lsb_first.eq(config.lsb_first),
|
|
|
|
interface.half_duplex.eq(config.half_duplex),
|
|
interface.cs.eq(config.cs),
|
|
interface.cs_polarity.eq(Replicate(
|
|
config.cs_polarity, len(interface.cs_polarity))),
|
|
interface.clk_polarity.eq(config.clk_polarity),
|
|
interface.offline.eq(config.offline),
|
|
interface.cs_next.eq(spi.cs_next),
|
|
interface.clk_next.eq(spi.clk_next),
|
|
interface.ce.eq(spi.ce),
|
|
interface.sample.eq(spi.reg.sample),
|
|
spi.reg.sdi.eq(interface.sdi),
|
|
interface.sdo.eq(spi.reg.sdo),
|
|
|
|
spi.load.eq(self.rtlink.o.stb & spi.writable &
|
|
~self.rtlink.o.address),
|
|
spi.reg.pdo.eq(self.rtlink.o.data),
|
|
self.rtlink.o.busy.eq(~spi.writable),
|
|
self.rtlink.i.stb.eq(spi.readable & read),
|
|
self.rtlink.i.data.eq(spi.reg.pdi)
|
|
]
|
|
self.probes = []
|