misoclib/com: add spi (only SPIMaster for now)

This commit is contained in:
Florent Kermarrec 2015-02-28 09:41:20 +01:00
parent 2c51adcd68
commit a43c555ee3
2 changed files with 237 additions and 0 deletions

View File

@ -0,0 +1,153 @@
from migen.fhdl.std import *
from migen.bank.description import *
from migen.genlib.fsm import FSM, NextState
class SPIMaster(Module, AutoCSR):
def __init__(self, pads, width=24, div=2, cpha=1):
self.pads = pads
self._ctrl = CSR()
self._length = CSRStorage(8)
self._status = CSRStatus()
if hasattr(pads, "mosi"):
self._mosi = CSRStorage(width)
if hasattr(pads, "miso"):
self._miso = CSRStatus(width)
self.irq = Signal()
###
# ctrl
start = Signal()
length = self._length.storage
enable_cs = Signal()
enable_shift = Signal()
done = Signal()
self.comb += [
start.eq(self._ctrl.re & self._ctrl.r[0]),
self._status.status.eq(done)
]
# clk
i = Signal(max=div)
clk_en = Signal()
set_clk = Signal()
clr_clk = Signal()
self.sync += [
If(set_clk,
pads.clk.eq(enable_cs)
),
If(clr_clk,
pads.clk.eq(0),
i.eq(0)
).Else(
i.eq(i + 1),
)
]
self.comb +=[
set_clk.eq(i==div//2-1),
clr_clk.eq(i==div-1)
]
# fsm
cnt = Signal(8)
clr_cnt = Signal()
inc_cnt = Signal()
self.sync += \
If(clr_cnt,
cnt.eq(0)
).Elif(inc_cnt,
cnt.eq(cnt+1)
)
fsm = FSM(reset_state="IDLE")
self.submodules += fsm
fsm.act("IDLE",
If(start,
NextState("WAIT_CLK")
),
done.eq(1),
clr_cnt.eq(1)
)
fsm.act("WAIT_CLK",
If(clr_clk,
NextState("SHIFT")
),
)
fsm.act("SHIFT",
If(cnt == length,
NextState("END")
).Else(
inc_cnt.eq(clr_clk),
),
enable_cs.eq(1),
enable_shift.eq(1),
)
fsm.act("END",
If(set_clk,
NextState("IDLE")
),
enable_shift.eq(1),
self.irq.eq(1)
)
# miso
if hasattr(pads, "miso"):
miso = Signal()
sr_miso = Signal(width)
# (cpha = 1: capture on clk falling edge)
if cpha:
self.sync += \
If(enable_shift,
If(clr_clk,
miso.eq(pads.miso),
).Elif(set_clk,
sr_miso.eq(Cat(miso, sr_miso[:-1]))
)
)
# (cpha = 0: capture on clk rising edge)
else:
self.sync += \
If(enable_shift,
If(set_clk,
miso.eq(pads.miso),
).Elif(clr_clk,
sr_miso.eq(Cat(miso, sr_miso[:-1]))
)
)
self.comb += self._miso.status.eq(sr_miso)
# mosi
if hasattr(pads, "mosi"):
mosi = Signal()
sr_mosi = Signal(width)
# (cpha = 1: propagated on clk rising edge)
if cpha:
self.sync += \
If(start,
sr_mosi.eq(self._mosi.storage)
).Elif(clr_clk & enable_shift,
sr_mosi.eq(Cat(Signal(), sr_mosi[:-1]))
).Elif(set_clk,
pads.mosi.eq(sr_mosi[-1])
)
# (cpha = 0: propagated on clk falling edge)
else:
self.sync += [
If(start,
sr_mosi.eq(self._mosi.storage)
).Elif(set_clk & enable_shift,
sr_mosi.eq(Cat(Signal(), sr_mosi[:-1]))
).Elif(clr_clk,
pads.mosi.eq(sr_mosi[-1])
)
]
# cs_n
self.comb += pads.cs_n.eq(~enable_cs)

View File

@ -0,0 +1,84 @@
from migen.fhdl.std import *
from migen.genlib.record import *
from migen.sim.generic import run_simulation
from misoclib.com.spi import SPIMaster
class SPISlave(Module):
def __init__(self, pads, width):
self.pads = pads
self.width = width
###
self.mosi = 0
self.miso = 0
self.last_cs_n = 1
self.last_clk = 0
def get_mosi(self):
return self.mosi
def set_miso(self, value):
self.miso = value
def do_simulation(self, selfp):
# detect edges
cs_n_rising = 0
cs_n_falling = 0
clk_rising = 0
clk_falling = 0
if selfp.pads.cs_n and not self.last_cs_n:
cs_n_rising = 1
if not selfp.pads.cs_n and self.last_cs_n:
cs_n_falling = 1
if selfp.pads.clk and not self.last_clk:
clk_rising = 1
if not selfp.pads.clk and self.last_clk:
clk_falling = 1
# input mosi
if clk_falling and not selfp.pads.cs_n:
self.mosi = self.mosi << 1
self.mosi |= selfp.pads.mosi
# output miso
if (clk_rising and not selfp.pads.cs_n):
selfp.pads.miso = (self.miso >> (self.width-1)) & 0x1
self.miso = self.miso << 1
# save signal states
self.last_cs_n = selfp.pads.cs_n
self.last_clk = selfp.pads.clk
def spi_access(selfp, length, mosi):
selfp.spi_master._mosi.storage = mosi
yield
selfp.spi_master._ctrl.r = (length << 8) | 1
selfp.spi_master._ctrl.re = 1
yield
selfp.spi_master._ctrl.r = 0
selfp.spi_master._ctrl.re = 0
yield
while not (selfp.spi_master._status.status & 0x1):
yield
class TB(Module):
def __init__(self):
pads = Record([("cs_n", 1), ("clk", 1), ("mosi", 1), ("miso", 1)])
self.submodules.spi_master = SPIMaster(pads, 24, 4)
self.submodules.spi_slave = SPISlave(pads, 24)
def gen_simulation(self, selfp):
for i in range(16):
yield
self.spi_slave.set_miso(0x123457)
yield from spi_access(selfp, 8, 0x123457)
print("%08x" %self.spi_slave.get_mosi())
print("%08x" %selfp.spi_master._miso.status)
if __name__ == "__main__":
run_simulation(TB(), ncycles=1000, vcd_name="my.vcd", keep_files=True)