forked from M-Labs/artiq
wrpll: add I2CMasterMachine
This commit is contained in:
parent
1fd2322662
commit
959679d8b7
|
@ -5,6 +5,148 @@ from migen.genlib.cdc import MultiReg, PulseSynchronizer, BlindTransfer
|
|||
from misoc.interconnect.csr import *
|
||||
|
||||
|
||||
class I2CClockGen(Module):
|
||||
def __init__(self, width):
|
||||
self.load = Signal(width)
|
||||
self.clk2x = Signal()
|
||||
|
||||
cnt = Signal.like(self.load)
|
||||
self.comb += [
|
||||
self.clk2x.eq(cnt == 0),
|
||||
]
|
||||
self.sync += [
|
||||
If(self.clk2x,
|
||||
cnt.eq(self.load),
|
||||
).Else(
|
||||
cnt.eq(cnt - 1),
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
class I2CMasterMachine(Module):
|
||||
def __init__(self, clock_width):
|
||||
self.scl = Signal(reset=1)
|
||||
self.sda_o = Signal(reset=1)
|
||||
self.sda_i = Signal()
|
||||
|
||||
self.submodules.cg = CEInserter()(I2CClockGen(clock_width))
|
||||
self.idle = Signal()
|
||||
self.start = Signal()
|
||||
self.stop = Signal()
|
||||
self.write = Signal()
|
||||
self.read = Signal()
|
||||
self.ack = Signal()
|
||||
self.data = Signal(8)
|
||||
|
||||
###
|
||||
|
||||
busy = Signal()
|
||||
bits = Signal(4)
|
||||
|
||||
fsm = CEInserter()(FSM("IDLE"))
|
||||
self.submodules += fsm
|
||||
|
||||
fsm.act("IDLE",
|
||||
If(self.start,
|
||||
NextState("START0"),
|
||||
).Elif(self.stop & self.start,
|
||||
NextState("RESTART0"),
|
||||
).Elif(self.stop,
|
||||
NextState("STOP0"),
|
||||
).Elif(self.write,
|
||||
NextValue(bits, 8),
|
||||
NextState("WRITE0"),
|
||||
).Elif(self.read,
|
||||
NextValue(bits, 8),
|
||||
NextState("READ0"),
|
||||
)
|
||||
)
|
||||
|
||||
fsm.act("START0",
|
||||
NextValue(self.scl, 1),
|
||||
NextState("START1"))
|
||||
fsm.act("START1",
|
||||
NextValue(self.sda_o, 0),
|
||||
NextState("IDLE"))
|
||||
|
||||
fsm.act("RESTART0",
|
||||
NextValue(self.scl, 0),
|
||||
NextState("RESTART1"))
|
||||
fsm.act("RESTART1",
|
||||
NextValue(self.sda_o, 1),
|
||||
NextState("START0"))
|
||||
|
||||
fsm.act("STOP0",
|
||||
NextValue(self.scl, 0),
|
||||
NextState("STOP1"))
|
||||
fsm.act("STOP1",
|
||||
NextValue(self.scl, 1),
|
||||
NextValue(self.sda_o, 0),
|
||||
NextState("STOP2"))
|
||||
fsm.act("STOP2",
|
||||
NextValue(self.sda_o, 1),
|
||||
NextState("IDLE"))
|
||||
|
||||
fsm.act("WRITE0",
|
||||
NextValue(self.scl, 0),
|
||||
If(bits == 0,
|
||||
NextValue(self.sda_o, 1),
|
||||
NextState("READACK0"),
|
||||
).Else(
|
||||
NextValue(self.sda_o, self.data[7]),
|
||||
NextState("WRITE1"),
|
||||
)
|
||||
)
|
||||
fsm.act("WRITE1",
|
||||
NextValue(self.scl, 1),
|
||||
NextValue(self.data[1:], self.data[:-1]),
|
||||
NextValue(bits, bits - 1),
|
||||
NextState("WRITE0"),
|
||||
)
|
||||
fsm.act("READACK0",
|
||||
NextValue(self.scl, 1),
|
||||
NextState("READACK1"),
|
||||
)
|
||||
fsm.act("READACK1",
|
||||
NextValue(self.ack, ~self.sda_i),
|
||||
NextState("IDLE")
|
||||
)
|
||||
|
||||
fsm.act("READ0",
|
||||
NextValue(self.scl, 0),
|
||||
NextState("READ1"),
|
||||
)
|
||||
fsm.act("READ1",
|
||||
NextValue(self.data[0], self.sda_i),
|
||||
NextValue(self.scl, 0),
|
||||
If(bits == 0,
|
||||
NextValue(self.sda_o, ~self.ack),
|
||||
NextState("WRITEACK0"),
|
||||
).Else(
|
||||
NextValue(self.sda_o, 1),
|
||||
NextState("READ2"),
|
||||
)
|
||||
)
|
||||
fsm.act("READ2",
|
||||
NextValue(self.scl, 1),
|
||||
NextValue(self.data[:-1], self.data[1:]),
|
||||
NextValue(bits, bits - 1),
|
||||
NextState("READ1"),
|
||||
)
|
||||
fsm.act("WRITEACK0",
|
||||
NextValue(self.scl, 1),
|
||||
NextState("IDLE"),
|
||||
)
|
||||
|
||||
run = Signal()
|
||||
self.comb += [
|
||||
run.eq(self.start | self.stop | self.write | self.read),
|
||||
self.idle.eq(~run & fsm.ongoing("IDLE")),
|
||||
self.cg.ce.eq(~self.idle),
|
||||
fsm.ce.eq(run | self.cg.clk2x),
|
||||
]
|
||||
|
||||
|
||||
class ADPLLProgrammer(Module):
|
||||
def __init__(self):
|
||||
self.i2c_divider = Signal(16)
|
||||
|
@ -18,11 +160,21 @@ class ADPLLProgrammer(Module):
|
|||
self.scl = Signal()
|
||||
self.sda_i = Signal()
|
||||
self.sda_o = Signal()
|
||||
self.sda_oe = Signal()
|
||||
|
||||
self.scl.attr.add("no_retiming")
|
||||
self.sda_o.attr.add("no_retiming")
|
||||
self.sda_oe.attr.add("no_retiming")
|
||||
|
||||
# # #
|
||||
|
||||
master = I2CMasterMachine(16)
|
||||
self.submodules += master
|
||||
|
||||
self.comb += [
|
||||
master.cg.load.eq(self.i2c_divider.storage),
|
||||
self.scl.eq(master.scl),
|
||||
master.sda_i.eq(self.sda_i),
|
||||
self.sda_o.eq(master.sda_o)
|
||||
]
|
||||
|
||||
|
||||
class Si549(Module, AutoCSR):
|
||||
|
@ -56,6 +208,10 @@ class Si549(Module, AutoCSR):
|
|||
programmer.adpll_stb.eq(self.adpll_stb)
|
||||
]
|
||||
|
||||
self.gpio_enable.storage.attr.add("no_retiming")
|
||||
self.gpio_out.storage.attr.add("no_retiming")
|
||||
self.gpio_oe.storage.attr.add("no_retiming")
|
||||
|
||||
# SCL GPIO and mux
|
||||
ts_scl = TSTriple(1)
|
||||
self.specials += ts_scl.get_tristate(pads.scl)
|
||||
|
@ -64,7 +220,6 @@ class Si549(Module, AutoCSR):
|
|||
self.comb += self.gpio_in.status[0].eq(status)
|
||||
|
||||
self.specials += MultiReg(ts_scl.i, status)
|
||||
self.gpio_enable.storage.attr.add("no_retiming")
|
||||
self.comb += [
|
||||
If(self.gpio_enable.storage,
|
||||
ts_scl.o.eq(self.gpio_out.storage[0]),
|
||||
|
@ -83,14 +238,13 @@ class Si549(Module, AutoCSR):
|
|||
self.comb += self.gpio_in.status[1].eq(status)
|
||||
|
||||
self.specials += MultiReg(ts_sda.i, status)
|
||||
self.gpio_enable.storage.attr.add("no_retiming")
|
||||
self.comb += [
|
||||
If(self.gpio_enable.storage,
|
||||
ts_sda.o.eq(self.gpio_out.storage[1]),
|
||||
ts_sda.oe.eq(self.gpio_oe.storage[1])
|
||||
).Else(
|
||||
ts_sda.o.eq(programmer.sda_o),
|
||||
ts_sda.oe.eq(programmer.sda_oe)
|
||||
ts_sda.o.eq(0),
|
||||
ts_sda.oe.eq(~programmer.sda_o)
|
||||
)
|
||||
]
|
||||
self.specials += MultiReg(ts_sda.i, programmer.sda_i, "helper")
|
||||
|
|
Loading…
Reference in New Issue