artiq/artiq/gateware/rtio/phy/spi2.py

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 = []