Browse Source

hub75sender use faster binary delay instead if PWM for dimming - running at 3 Bit 2300FPS

master
Wolfgang Villing 6 months ago
parent
commit
2359da6cb4
2 changed files with 69 additions and 40 deletions
  1. +3
    -1
      cl_min.py
  2. +66
    -39
      hub75sender.py

+ 3
- 1
cl_min.py View File

@ -28,7 +28,8 @@ import cv2
ios = [
("led", 0, Pins("j4:1 j4:5"), IOStandard("LVCMOS33")),
("j5", 0,
("j3", 0, Pins("j3:1 j3:5"), IOStandard("LVCMOS33")),
("j5", 0,
Subsignal("rgb", Pins("j5:0 j5:1 j5:2 j5:4 j5:5 j5:6")),
Subsignal("adr", Pins("j5:8 j5:9 j5:10 j5:11 j5:7")),
Subsignal("clk", Pins("j5:12")),
@ -93,6 +94,7 @@ class ClMini(SoCCore):
self.submodules.hub = Hub75Sender(64, 64, content, platform.request("j5"))
self.add_csr("hub_mem")
self.add_csr("hub")
self.comb += platform.request("j3").eq(Cat(self.hub.frameDone, self.hub.rowDone))
counter = Signal(32)
self.sync += counter.eq(counter + 1)


+ 66
- 39
hub75sender.py View File

@ -8,34 +8,48 @@ from migen import *
from migen.fhdl import verilog
from litex.soc.interconnect.csr import *
class ColorPWM(Module):
"""PWM dimming for RGB332 Colors"""
class ColorDim(Module):
"""Binary dimming for RGB332 Colors"""
def __init__(self):
maxPwm=6
self.pixUpper = Signal(8)
self.pixLower = Signal(8)
self.output = Signal(6)
self.resetCounter = Signal()
self.incrementCounter = Signal()
self.oen = Signal()
self.done = Signal()
self.active = Signal()
self.waitForLast = Signal()
pulseduration = Signal(22)
bitToCheck = Signal(3)
pwmCounter = Signal(max=maxPwm+1)
self.sync += If( self.resetCounter,
pwmCounter.eq(0)
pulseduration.eq(0),
bitToCheck.eq(0b100)
).Elif(self.incrementCounter,
If((pwmCounter == maxPwm),
pwmCounter.eq(0)
pulseduration.eq(bitToCheck << 5), # Multiply by 16 for Max Brightness
bitToCheck.eq(bitToCheck >> 1)
).Else(
If((pulseduration == 0),
pulseduration.eq(0)
).Else(
pwmCounter.eq(pwmCounter + 1)
pulseduration.eq(pulseduration - 1)
)
)
self.comb += self.active.eq(pulseduration != 0)
self.comb += self.oen.eq(pulseduration == 0)
self.comb += self.done.eq((bitToCheck == 0) & (pulseduration == 0))
self.comb += self.waitForLast.eq((bitToCheck == 0) & (pulseduration != 0))
r1, r2, g1, g2, b1, b2 = [Signal() for _ in range(6)]
self.comb += r1.eq(self.pixUpper[5:8] > pwmCounter)
self.comb += r2.eq(self.pixLower[5:8] > pwmCounter)
self.comb += g1.eq(self.pixUpper[2:5] > pwmCounter)
self.comb += g2.eq(self.pixLower[2:5] > pwmCounter)
self.comb += b1.eq(self.pixUpper[0:2] > pwmCounter[1:3])
self.comb += b2.eq(self.pixLower[0:2] > pwmCounter[1:3])
self.comb += r1.eq(self.pixUpper[5:8] & bitToCheck > 0)
self.comb += r2.eq(self.pixLower[5:8] & bitToCheck > 0)
self.comb += g1.eq(self.pixUpper[2:5] & bitToCheck > 0)
self.comb += g2.eq(self.pixLower[2:5] & bitToCheck > 0)
self.comb += b1.eq(self.pixUpper[0:2] & bitToCheck[1:3] > 0)
self.comb += b2.eq(self.pixLower[0:2] & bitToCheck[1:3] > 0)
self.comb += self.output.eq(Cat(r1, g1, b1, r2, g2, b2))
class Hub75Out(Module):
@ -59,7 +73,7 @@ class Hub75Sender(Module, AutoCSR):
ram = self.mem.get_port()
self.specials += ram
pwm = ColorPWM()
pwm = ColorDim()
self.submodules += pwm
# Pixel and Row counter
@ -69,24 +83,24 @@ class Hub75Sender(Module, AutoCSR):
# Output Ports
self.outAddr = Signal(5) # abcde
self.outClk = Signal()
self.outOe = Signal()
self.outLat = Signal()
self.outRGB = Signal(6) # (6) r0 r1 g0 g1 b0 b1
self.comb += self.outRGB.eq(pwm.output),
self.frameDone = Signal() # Debug
self.rowDone = Signal() # Debug
if out:
self.comb += out.rgb.eq(self.outRGB)
self.comb += out.adr.eq(self.outAddr)
self.comb += out.lat.eq(self.outLat)
self.comb += out.clk.eq(self.outClk)
self.comb += out.oen.eq(self.outOe ^ 1)
self.comb += out.oen.eq(pwm.oen)
fsm = FSM(reset_state="RESET")
self.submodules.fsm = fsm
fsm.act("RESET",
NextValue(self.pixCount, 0),
NextValue(self.outOe, 1),
NextValue(self.rowCount, 0),
pwm.resetCounter.eq(1),
NextState("AdrUp"))
@ -110,41 +124,54 @@ class Hub75Sender(Module, AutoCSR):
fsm.act("ClkOff", # Clock the Data out
NextValue(self.outClk, 0),
If(self.pixCount == numCols,
NextValue(self.outOe, 0),
#NextValue(self.rowCount, self.rowCount + 1),
If(pwm.active & (self.pixCount == numCols),
NextState("ClkOff") # Wait for last Dimming done
).Elif(self.pixCount == numCols,
NextValue(self.pixCount, 0),
NextState("OeOff") # Finished with Row
NextState("RowOk") # Finished with Row
).Else(
NextState("AdrUp")
# Skip AddrUp State and set Address here
ram.adr.eq(self.pixCount + (self.rowCount << rowCountShift)),
NextState("AdrLo")
))
fsm.act("OeOff", NextValue(self.outLat, 1), NextState("LatOn"))
fsm.act("LatOn", NextValue(self.outAddr, self.rowCount), NextState("AdrRow"))
fsm.act("RowOk", NextValue(self.outLat, 1), NextState("LatOn"))
fsm.act("LatOn", NextState("AdrRow"))
fsm.act("AdrRow", NextValue(self.outLat, 0), NextState("LatOff"))
fsm.act("LatOff", NextValue(self.outOe, 1), NextState("OeOn"))
fsm.act("OeOn",
If(self.rowCount == Constant(numRows/2 - 1),
NextValue(self.rowCount, 0),
pwm.incrementCounter.eq(1),
NextState("Done")
fsm.act("LatOff", pwm.incrementCounter.eq(1), NextState("CkCnt"))
fsm.act("CkCnt",
If(pwm.waitForLast,
NextState("CkCnt")
).Elif(pwm.done,
If(self.rowCount == Constant(numRows/2 - 1),
NextValue(self.rowCount, 0),
self.frameDone.eq(1)
).Else(
NextValue(self.rowCount, self.rowCount + 1),
),
NextState("OeOn"),
pwm.resetCounter.eq(1)
).Else(
NextValue(self.rowCount, self.rowCount + 1),
NextState("AdrUp"))
NextState("AdrUp")
)
)
fsm.act("Done", NextState("AdrUp"))
fsm.act("OeOn",
NextValue(self.outAddr, self.rowCount),
NextState("Done"))
fsm.act("Done", self.rowDone.eq(1), NextState("AdrUp"))
def testbench():
content = (0x00, 0x01, 0x02, 0x03, 0x14, 0x15, 0x16, 0x17,
0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1c)
content = (0, 1, 2, 3,
0, 0, 0, 0,
0x00, 0x04, 0x08, 0x0C, 0, 0, 0, 0)
dut = Hub75Sender(4, 4, content, Hub75Out())
def memtest():
for _ in range(500):
for _ in range(1000):
yield
yield


Loading…
Cancel
Save