wrpll: add I2CMasterMachine

This commit is contained in:
Sebastien Bourdeauducq 2019-08-27 18:02:05 +08:00
parent 1fd2322662
commit 959679d8b7

View File

@ -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")