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.
This commit is contained in:
parent
6bb22dfe6b
commit
0b3c4b50fa
|
@ -17,7 +17,8 @@ class SPIMaster(Module, AutoCSR):
|
||||||
configurable data_width and frequency.
|
configurable data_width and frequency.
|
||||||
"""
|
"""
|
||||||
pads_layout = [("clk", 1), ("cs_n", 1), ("mosi", 1), ("miso", 1)]
|
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:
|
if pads is None:
|
||||||
pads = Record(self.pads_layout)
|
pads = Record(self.pads_layout)
|
||||||
if not hasattr(pads, "cs_n"):
|
if not hasattr(pads, "cs_n"):
|
||||||
|
@ -96,15 +97,17 @@ class SPIMaster(Module, AutoCSR):
|
||||||
for i in range(len(pads.cs_n)):
|
for i in range(len(pads.cs_n)):
|
||||||
self.comb += pads.cs_n[i].eq(~self.cs[i] | ~xfer)
|
self.comb += pads.cs_n[i].eq(~self.cs[i] | ~xfer)
|
||||||
|
|
||||||
# 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 = Array(self.mosi[i] for i in range(data_width))
|
||||||
|
mosi_bit = Signal(max=data_width)
|
||||||
self.sync += [
|
self.sync += [
|
||||||
If(self.start,
|
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,
|
).Elif(clk_rise & shift,
|
||||||
mosi_data.eq(Cat(Signal(), mosi_data))
|
mosi_bit.eq(mosi_bit - 1)
|
||||||
).Elif(clk_fall,
|
),
|
||||||
pads.mosi.eq(mosi_data[-1])
|
If(clk_fall,
|
||||||
|
pads.mosi.eq(mosi_data[mosi_bit])
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ class TestSPI(unittest.TestCase):
|
||||||
spi_master = SPIMaster(pads=None, data_width=32, sys_clk_freq=100e6, spi_clk_freq=5e6)
|
spi_master = SPIMaster(pads=None, data_width=32, sys_clk_freq=100e6, spi_clk_freq=5e6)
|
||||||
self.assertEqual(hasattr(spi_master, "pads"), 1)
|
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):
|
def generator(dut):
|
||||||
yield dut.loopback.eq(1)
|
yield dut.loopback.eq(1)
|
||||||
yield dut.mosi.eq(0xdeadbeef)
|
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)
|
dut = SPIMaster(pads=None, data_width=32, sys_clk_freq=100e6, spi_clk_freq=5e6, with_csr=False)
|
||||||
run_simulation(dut, generator(dut))
|
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):
|
def test_spi_slave_syntax(self):
|
||||||
spi_slave = SPISlave(pads=None, data_width=32)
|
spi_slave = SPISlave(pads=None, data_width=32)
|
||||||
self.assertEqual(hasattr(spi_slave, "pads"), 1)
|
self.assertEqual(hasattr(spi_slave, "pads"), 1)
|
||||||
|
|
Loading…
Reference in New Issue