Skip to content

Commit

Permalink
soc/cores/spi: add optional aligned mode.
Browse files Browse the repository at this point in the history
In aligned mode, MOSI and MISO bits are located on the LSBs and first transmitted MOSI bit is length - 1 bit.
  • Loading branch information
enjoy-digital committed Apr 22, 2020
1 parent 6bb22df commit 0b3c4b5
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 8 deletions.
17 changes: 10 additions & 7 deletions litex/soc/cores/spi.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ class SPIMaster(Module, AutoCSR):
configurable data_width and frequency.
"""
pads_layout = [("clk", 1), ("cs_n", 1), ("mosi", 1), ("miso", 1)]
def __init__(self, pads, data_width, sys_clk_freq, spi_clk_freq, with_csr=True):
def __init__(self, pads, data_width, sys_clk_freq, spi_clk_freq, with_csr=True, mode="raw"):
assert mode in ["raw", "aligned"]
if pads is None:
pads = Record(self.pads_layout)
if not hasattr(pads, "cs_n"):
Expand Down Expand Up @@ -96,15 +97,17 @@ def __init__(self, pads, data_width, sys_clk_freq, spi_clk_freq, with_csr=True):
for i in range(len(pads.cs_n)):
self.comb += pads.cs_n[i].eq(~self.cs[i] | ~xfer)

# Master Out Slave In (MOSI) generation (generated on spi_clk falling edge) ---------------
mosi_data = Signal(data_width)
# Master Out Slave In (MOSI) generation (generated on spi_clk falling edge) ----------------
mosi_data = Array(self.mosi[i] for i in range(data_width))
mosi_bit = Signal(max=data_width)
self.sync += [
If(self.start,
mosi_data.eq(self.mosi)
mosi_bit.eq(self.length - 1 if mode == "aligned" else data_width - 1),
).Elif(clk_rise & shift,
mosi_data.eq(Cat(Signal(), mosi_data))
).Elif(clk_fall,
pads.mosi.eq(mosi_data[-1])
mosi_bit.eq(mosi_bit - 1)
),
If(clk_fall,
pads.mosi.eq(mosi_data[mosi_bit])
)
]

Expand Down
18 changes: 17 additions & 1 deletion test/test_spi.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def test_spi_master_syntax(self):
spi_master = SPIMaster(pads=None, data_width=32, sys_clk_freq=100e6, spi_clk_freq=5e6)
self.assertEqual(hasattr(spi_master, "pads"), 1)

def test_spi_master_xfer_loopback(self):
def test_spi_master_xfer_loopback_32b_32b(self):
def generator(dut):
yield dut.loopback.eq(1)
yield dut.mosi.eq(0xdeadbeef)
Expand All @@ -29,6 +29,22 @@ def generator(dut):
dut = SPIMaster(pads=None, data_width=32, sys_clk_freq=100e6, spi_clk_freq=5e6, with_csr=False)
run_simulation(dut, generator(dut))

def test_spi_master_xfer_loopback_32b_16b(self):
def generator(dut):
yield dut.loopback.eq(1)
yield dut.mosi.eq(0xbeef)
yield dut.length.eq(16)
yield dut.start.eq(1)
yield
yield dut.start.eq(0)
yield
while (yield dut.done) == 0:
yield
self.assertEqual((yield dut.miso), 0xbeef)

dut = SPIMaster(pads=None, data_width=32, sys_clk_freq=100e6, spi_clk_freq=5e6, with_csr=False, mode="aligned")
run_simulation(dut, generator(dut))

def test_spi_slave_syntax(self):
spi_slave = SPISlave(pads=None, data_width=32)
self.assertEqual(hasattr(spi_slave, "pads"), 1)
Expand Down

0 comments on commit 0b3c4b5

Please sign in to comment.