From 0b3c4b50fa99cd92ba83ea64a1386b94195a35d4 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Wed, 22 Apr 2020 13:15:07 +0200 Subject: [PATCH] soc/cores/spi: add optional aligned mode. In aligned mode, MOSI and MISO bits are located on the LSBs and first transmitted MOSI bit is length - 1 bit. --- litex/soc/cores/spi.py | 17 ++++++++++------- test/test_spi.py | 18 +++++++++++++++++- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/litex/soc/cores/spi.py b/litex/soc/cores/spi.py index fdf263e75..fe09f5e9e 100644 --- a/litex/soc/cores/spi.py +++ b/litex/soc/cores/spi.py @@ -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"): @@ -96,15 +97,17 @@ class SPIMaster(Module, AutoCSR): 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]) ) ] diff --git a/test/test_spi.py b/test/test_spi.py index 1cfffd57e..92d1ad827 100644 --- a/test/test_spi.py +++ b/test/test_spi.py @@ -13,7 +13,7 @@ class TestSPI(unittest.TestCase): 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) @@ -29,6 +29,22 @@ class TestSPI(unittest.TestCase): 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)