cores/spi: Add Manual CS Mode (to allow doing Bulk Xfers without external changes), also cleanup/simplify a bit CSR descriptions.
This commit is contained in:
parent
ac73474d66
commit
8ce7c583e6
|
@ -26,6 +26,7 @@ class SPIMaster(Module, AutoCSR):
|
|||
pads = Record(self.pads_layout)
|
||||
if not hasattr(pads, "cs_n"):
|
||||
pads.cs_n = Signal()
|
||||
assert len(pads.cs_n) <= 16
|
||||
self.pads = pads
|
||||
self.data_width = data_width
|
||||
|
||||
|
@ -36,6 +37,7 @@ class SPIMaster(Module, AutoCSR):
|
|||
self.mosi = Signal(data_width)
|
||||
self.miso = Signal(data_width)
|
||||
self.cs = Signal(len(pads.cs_n), reset=1)
|
||||
self.cs_mode = Signal()
|
||||
self.loopback = Signal()
|
||||
self.clk_divider = Signal(16, reset=math.ceil(sys_clk_freq/spi_clk_freq))
|
||||
|
||||
|
@ -45,7 +47,7 @@ class SPIMaster(Module, AutoCSR):
|
|||
# # #
|
||||
|
||||
clk_enable = Signal()
|
||||
cs_enable = Signal()
|
||||
xfer_enable = Signal()
|
||||
count = Signal(max=data_width)
|
||||
mosi_latch = Signal()
|
||||
miso_latch = Signal()
|
||||
|
@ -79,13 +81,13 @@ class SPIMaster(Module, AutoCSR):
|
|||
fsm.act("START",
|
||||
NextValue(count, 0),
|
||||
If(clk_fall,
|
||||
cs_enable.eq(1),
|
||||
xfer_enable.eq(1),
|
||||
NextState("RUN")
|
||||
)
|
||||
)
|
||||
fsm.act("RUN",
|
||||
clk_enable.eq(1),
|
||||
cs_enable.eq(1),
|
||||
xfer_enable.eq(1),
|
||||
If(clk_fall,
|
||||
NextValue(count, count + 1),
|
||||
If(count == (self.length - 1),
|
||||
|
@ -94,7 +96,7 @@ class SPIMaster(Module, AutoCSR):
|
|||
)
|
||||
)
|
||||
fsm.act("STOP",
|
||||
cs_enable.eq(1),
|
||||
xfer_enable.eq(1),
|
||||
If(clk_rise,
|
||||
miso_latch.eq(1),
|
||||
self.irq.eq(1),
|
||||
|
@ -105,7 +107,10 @@ class SPIMaster(Module, AutoCSR):
|
|||
# Chip Select generation -------------------------------------------------------------------
|
||||
if hasattr(pads, "cs_n"):
|
||||
for i in range(len(pads.cs_n)):
|
||||
self.sync += pads.cs_n[i].eq(~self.cs[i] | ~cs_enable)
|
||||
# CS set when enabled and (Xfer enabled or Manual CS mode selected).
|
||||
cs = (self.cs[i] & (xfer_enable | (self.cs_mode == 1)))
|
||||
# CS Output/Invert.
|
||||
self.sync += pads.cs_n[i].eq(~cs)
|
||||
|
||||
# Master Out Slave In (MOSI) generation (generated on spi_clk falling edge) ----------------
|
||||
mosi_data = Signal(data_width)
|
||||
|
@ -116,7 +121,7 @@ class SPIMaster(Module, AutoCSR):
|
|||
mosi_data.eq(self.mosi),
|
||||
mosi_sel.eq((self.length-1) if mode == "aligned" else (data_width-1)),
|
||||
).Elif(clk_fall,
|
||||
If(cs_enable, pads.mosi.eq(mosi_array[mosi_sel])),
|
||||
If(xfer_enable, pads.mosi.eq(mosi_array[mosi_sel])),
|
||||
mosi_sel.eq(mosi_sel - 1)
|
||||
),
|
||||
]
|
||||
|
@ -136,30 +141,54 @@ class SPIMaster(Module, AutoCSR):
|
|||
self.sync += If(miso_latch, self.miso.eq(miso_data))
|
||||
|
||||
def add_csr(self, with_cs=True, with_loopback=True):
|
||||
self._control = CSRStorage(fields=[
|
||||
CSRField("start", size=1, offset=0, pulse=True, description="Write ``1`` to start SPI Xfer"),
|
||||
CSRField("length", size=8, offset=8, description="SPI Xfer length (in bits).")
|
||||
], description="SPI Control.")
|
||||
self._status = CSRStatus(fields=[
|
||||
CSRField("done", size=1, offset=0, description="SPI Xfer done when read as ``1``.")
|
||||
], description="SPI Status.")
|
||||
self._mosi = CSRStorage(self.data_width, reset_less=True, description="SPI MOSI data (MSB-first serialization).")
|
||||
self._miso = CSRStatus(self.data_width, description="SPI MISO data (MSB-first de-serialization).")
|
||||
# Control / Status.
|
||||
self._control = CSRStorage(description="SPI Control.", fields=[
|
||||
CSRField("start", size=1, offset=0, pulse=True, description="SPI Xfer Start (Write ``1`` to start Xfer)."),
|
||||
CSRField("length", size=8, offset=8, description="SPI Xfer Length (in bits).")
|
||||
])
|
||||
self._status = CSRStatus(description="SPI Status.", fields=[
|
||||
CSRField("done", size=1, offset=0, description="SPI Xfer Done (when read as ``1``).")
|
||||
])
|
||||
self.comb += [
|
||||
self.start.eq(self._control.fields.start),
|
||||
self.length.eq(self._control.fields.length),
|
||||
self.mosi.eq(self._mosi.storage),
|
||||
self._status.fields.done.eq(self.done),
|
||||
]
|
||||
|
||||
# MOSI/MISO.
|
||||
self._mosi = CSRStorage(self.data_width, reset_less=True, description="SPI MOSI data (MSB-first serialization).")
|
||||
self._miso = CSRStatus(self.data_width, description="SPI MISO data (MSB-first de-serialization).")
|
||||
self.comb += [
|
||||
self.mosi.eq(self._mosi.storage),
|
||||
self._miso.status.eq(self.miso),
|
||||
]
|
||||
|
||||
# Chip Select.
|
||||
if with_cs:
|
||||
self._cs = CSRStorage(fields=[
|
||||
CSRField("sel", len(self.cs), reset=1, description="Write ``1`` to corresponding bit to enable Xfer for chip.")
|
||||
], description="SPI Chip Select.")
|
||||
self.comb += self.cs.eq(self._cs.storage)
|
||||
self._cs = CSRStorage(description="SPI CS Chip-Select and Mode.", fields=[
|
||||
CSRField("sel", size=len(self.cs), offset=0, reset=1, values=[
|
||||
("``0b0..001``", "Chip ``0`` selected for SPI Xfer."),
|
||||
("``0b1..000``", "Chip ``N`` selected for SPI Xfer.")
|
||||
]),
|
||||
CSRField("mode", size=1, offset=16, reset=0, values=[
|
||||
("``0b0``", "Normal operation (CS handled by Core)."),
|
||||
("``0b1``", "Manual operation (CS handled by User, direct recopy of ``sel``), useful for Bulk transfers.")
|
||||
]),
|
||||
])
|
||||
self.comb += [
|
||||
self.cs.eq(self._cs.fields.sel),
|
||||
self.cs_mode.eq(self._cs.fields.mode)
|
||||
]
|
||||
|
||||
# Loopback.
|
||||
if with_loopback:
|
||||
self._loopback = CSRStorage(description="SPI loopback mode.\n\n Write ``1`` to enable MOSI to MISO internal loopback.")
|
||||
self.comb += self.loopback.eq(self._loopback.storage)
|
||||
self._loopback = CSRStorage(description="SPI Loopback Mode.", fields=[
|
||||
CSRField("mode", size=1, values=[
|
||||
("``0b0``", "Normal operation."),
|
||||
("``0b1``", "Loopback operation (MOSI to MISO).")
|
||||
])
|
||||
])
|
||||
self.comb += self.loopback.eq(self._loopback.fields.mode)
|
||||
|
||||
def add_clk_divider(self):
|
||||
self._clk_divider = CSRStorage(16, description="SPI Clk Divider.", reset=self.clk_divider.reset)
|
||||
|
|
Loading…
Reference in New Issue