groovylight/groovylight/hub75.py
saji 37dabd603a coordinator works now
fixed some off by one errors to make the screen work good
2024-05-01 16:14:32 -05:00

115 lines
3.9 KiB
Python

# r0 g0 b0 gnd r1 g1 b1 e a b c d clk stb oe gnd
from litex.build.generic_platform import Signal, Subsignal, Pins
from litex.build.io import FSM, Module, Cat, Replicate
from litex.gen import ClockSignal, If, Instance, NextState, NextValue
def make_hub75_iodevice(index, basename):
b = basename
signals = ("hub75_iodev", index,
Subsignal("r0", Pins(f"{b}:0")),
Subsignal("g0", Pins(f"{b}:1")),
Subsignal("b0", Pins(f"{b}:2")),
Subsignal("r1", Pins(f"{b}:4")),
Subsignal("g1", Pins(f"{b}:5")),
Subsignal("b1", Pins(f"{b}:6")),
Subsignal("addr", Pins(f"{b}:8 {b}:9 {b}:10 {b}:11 {b}:7")),
Subsignal("clk", Pins(f"{b}:12")),
Subsignal("stb", Pins(f"{b}:13")),
Subsignal("oe", Pins(f"{b}:14")),
)
return [signals]
class Hub75Driver(Module):
def __init__(self, base_freq=60e6, linedepth=128):
if base_freq // 2 > 30e6:
raise RuntimeError("hi")
self.addr = Signal(5)
self.latch = Signal()
self.output_en = Signal()
color = Signal(24, reset=0xA0FF00)
self.rgb = Signal(6)
self.clock_out = Signal()
self.fsm = fsm = FSM()
self.submodules += self.fsm
bcm_value = Signal(3)
counter = Signal(32)
should_expose = (counter < (16 << bcm_value)) & (bcm_value != 0)
# this state both sets the OE low to drive the display with the previous frame
# while also loading the next row
# FIXME: there's a bug on the starting conditions right now, we are losing the lowest bit.
fsm.act("WRITEROW",
self.output_en.eq(~should_expose),
self.rgb[0].eq((color >> bcm_value) & 1),
self.rgb[3].eq((color >> bcm_value) & 1),
self.rgb[1].eq((color >> (bcm_value + 8)) & 1),
self.rgb[4].eq((color >> (bcm_value + 8)) & 1),
self.rgb[2].eq((color >> (bcm_value + 16)) & 1),
self.rgb[5].eq((color >> (bcm_value + 16)) & 1),
NextValue(counter, counter + 1),
If(counter < linedepth * 2,
self.clock_out.eq(counter[0]),
),
If(~(counter < linedepth * 2) & ~should_expose,
NextValue(counter, 0),
NextState("LATCH"),
),
)
fsm.act("EXPOSE",
self.output_en.eq(0),
If(counter < (16 << bcm_value),
NextValue(counter, counter + 1),
).Else(
NextValue(counter, 0),
NextState("LATCH"),
),
)
fsm.act("LATCH",
self.latch.eq(1),
self.output_en.eq(1),
NextValue(counter, 0),
If(bcm_value == 7,
NextValue(bcm_value, 0),
NextValue(self.addr, self.addr + 1),
).Else(
NextValue(bcm_value, bcm_value + 1),
),
NextState("WRITEROW"),
)
class Hub75VerilogDriver(Module):
def __init__(self):
self.o_addr = Signal(5)
self.o_display_clk = Signal()
self.o_latch = Signal()
self.o_out_enable = Signal()
self.o_panel_rgb0 = Signal(3)
self.o_panel_rgb1 = Signal(3)
inst = Instance("coordinator",
i_clk = ClockSignal(),
o_panel_rgb0 = self.o_panel_rgb0,
o_panel_rgb1 = self.o_panel_rgb1,
o_latch = self.o_latch,
o_display_clk = self.o_display_clk,
o_out_enable = self.o_out_enable,
o_display_addr = self.o_addr,
)
self.specials += inst