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)
|
pads = Record(self.pads_layout)
|
||||||
if not hasattr(pads, "cs_n"):
|
if not hasattr(pads, "cs_n"):
|
||||||
pads.cs_n = Signal()
|
pads.cs_n = Signal()
|
||||||
|
assert len(pads.cs_n) <= 16
|
||||||
self.pads = pads
|
self.pads = pads
|
||||||
self.data_width = data_width
|
self.data_width = data_width
|
||||||
|
|
||||||
|
@ -36,6 +37,7 @@ class SPIMaster(Module, AutoCSR):
|
||||||
self.mosi = Signal(data_width)
|
self.mosi = Signal(data_width)
|
||||||
self.miso = Signal(data_width)
|
self.miso = Signal(data_width)
|
||||||
self.cs = Signal(len(pads.cs_n), reset=1)
|
self.cs = Signal(len(pads.cs_n), reset=1)
|
||||||
|
self.cs_mode = Signal()
|
||||||
self.loopback = Signal()
|
self.loopback = Signal()
|
||||||
self.clk_divider = Signal(16, reset=math.ceil(sys_clk_freq/spi_clk_freq))
|
self.clk_divider = Signal(16, reset=math.ceil(sys_clk_freq/spi_clk_freq))
|
||||||
|
|
||||||
|
@ -44,11 +46,11 @@ class SPIMaster(Module, AutoCSR):
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
clk_enable = Signal()
|
clk_enable = Signal()
|
||||||
cs_enable = Signal()
|
xfer_enable = Signal()
|
||||||
count = Signal(max=data_width)
|
count = Signal(max=data_width)
|
||||||
mosi_latch = Signal()
|
mosi_latch = Signal()
|
||||||
miso_latch = Signal()
|
miso_latch = Signal()
|
||||||
|
|
||||||
# Clock generation -------------------------------------------------------------------------
|
# Clock generation -------------------------------------------------------------------------
|
||||||
clk_divider = Signal(16)
|
clk_divider = Signal(16)
|
||||||
|
@ -79,13 +81,13 @@ class SPIMaster(Module, AutoCSR):
|
||||||
fsm.act("START",
|
fsm.act("START",
|
||||||
NextValue(count, 0),
|
NextValue(count, 0),
|
||||||
If(clk_fall,
|
If(clk_fall,
|
||||||
cs_enable.eq(1),
|
xfer_enable.eq(1),
|
||||||
NextState("RUN")
|
NextState("RUN")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fsm.act("RUN",
|
fsm.act("RUN",
|
||||||
clk_enable.eq(1),
|
clk_enable.eq(1),
|
||||||
cs_enable.eq(1),
|
xfer_enable.eq(1),
|
||||||
If(clk_fall,
|
If(clk_fall,
|
||||||
NextValue(count, count + 1),
|
NextValue(count, count + 1),
|
||||||
If(count == (self.length - 1),
|
If(count == (self.length - 1),
|
||||||
|
@ -94,7 +96,7 @@ class SPIMaster(Module, AutoCSR):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fsm.act("STOP",
|
fsm.act("STOP",
|
||||||
cs_enable.eq(1),
|
xfer_enable.eq(1),
|
||||||
If(clk_rise,
|
If(clk_rise,
|
||||||
miso_latch.eq(1),
|
miso_latch.eq(1),
|
||||||
self.irq.eq(1),
|
self.irq.eq(1),
|
||||||
|
@ -105,7 +107,10 @@ class SPIMaster(Module, AutoCSR):
|
||||||
# Chip Select generation -------------------------------------------------------------------
|
# Chip Select generation -------------------------------------------------------------------
|
||||||
if hasattr(pads, "cs_n"):
|
if hasattr(pads, "cs_n"):
|
||||||
for i in range(len(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) ----------------
|
# Master Out Slave In (MOSI) generation (generated on spi_clk falling edge) ----------------
|
||||||
mosi_data = Signal(data_width)
|
mosi_data = Signal(data_width)
|
||||||
|
@ -116,7 +121,7 @@ class SPIMaster(Module, AutoCSR):
|
||||||
mosi_data.eq(self.mosi),
|
mosi_data.eq(self.mosi),
|
||||||
mosi_sel.eq((self.length-1) if mode == "aligned" else (data_width-1)),
|
mosi_sel.eq((self.length-1) if mode == "aligned" else (data_width-1)),
|
||||||
).Elif(clk_fall,
|
).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)
|
mosi_sel.eq(mosi_sel - 1)
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -136,30 +141,54 @@ class SPIMaster(Module, AutoCSR):
|
||||||
self.sync += If(miso_latch, self.miso.eq(miso_data))
|
self.sync += If(miso_latch, self.miso.eq(miso_data))
|
||||||
|
|
||||||
def add_csr(self, with_cs=True, with_loopback=True):
|
def add_csr(self, with_cs=True, with_loopback=True):
|
||||||
self._control = CSRStorage(fields=[
|
# Control / Status.
|
||||||
CSRField("start", size=1, offset=0, pulse=True, description="Write ``1`` to start SPI Xfer"),
|
self._control = CSRStorage(description="SPI Control.", fields=[
|
||||||
CSRField("length", size=8, offset=8, description="SPI Xfer length (in bits).")
|
CSRField("start", size=1, offset=0, pulse=True, description="SPI Xfer Start (Write ``1`` to start Xfer)."),
|
||||||
], description="SPI Control.")
|
CSRField("length", size=8, offset=8, description="SPI Xfer Length (in bits).")
|
||||||
self._status = CSRStatus(fields=[
|
])
|
||||||
CSRField("done", size=1, offset=0, description="SPI Xfer done when read as ``1``.")
|
self._status = CSRStatus(description="SPI Status.", fields=[
|
||||||
], description="SPI Status.")
|
CSRField("done", size=1, offset=0, description="SPI Xfer Done (when read as ``1``).")
|
||||||
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.comb += [
|
||||||
self.start.eq(self._control.fields.start),
|
self.start.eq(self._control.fields.start),
|
||||||
self.length.eq(self._control.fields.length),
|
self.length.eq(self._control.fields.length),
|
||||||
self.mosi.eq(self._mosi.storage),
|
|
||||||
self._status.fields.done.eq(self.done),
|
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),
|
self._miso.status.eq(self.miso),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Chip Select.
|
||||||
if with_cs:
|
if with_cs:
|
||||||
self._cs = CSRStorage(fields=[
|
self._cs = CSRStorage(description="SPI CS Chip-Select and Mode.", fields=[
|
||||||
CSRField("sel", len(self.cs), reset=1, description="Write ``1`` to corresponding bit to enable Xfer for chip.")
|
CSRField("sel", size=len(self.cs), offset=0, reset=1, values=[
|
||||||
], description="SPI Chip Select.")
|
("``0b0..001``", "Chip ``0`` selected for SPI Xfer."),
|
||||||
self.comb += self.cs.eq(self._cs.storage)
|
("``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:
|
if with_loopback:
|
||||||
self._loopback = CSRStorage(description="SPI loopback mode.\n\n Write ``1`` to enable MOSI to MISO internal loopback.")
|
self._loopback = CSRStorage(description="SPI Loopback Mode.", fields=[
|
||||||
self.comb += self.loopback.eq(self._loopback.storage)
|
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):
|
def add_clk_divider(self):
|
||||||
self._clk_divider = CSRStorage(16, description="SPI Clk Divider.", reset=self.clk_divider.reset)
|
self._clk_divider = CSRStorage(16, description="SPI Clk Divider.", reset=self.clk_divider.reset)
|
||||||
|
|
Loading…
Reference in New Issue