new minimal cl_mini Top-Level file. Connected hub75 to pins

master
wolfgang 2 years ago
parent eeb162f537
commit 5e86ba7bed
  1. 131
      cl_min.py
  2. 40
      hub75sender.py

@ -0,0 +1,131 @@
#!/usr/bin/env python3
# This file is Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
# License: BSD
import os
import argparse
from litex.soc.cores.clock import *
from litex.soc.cores.identifier import Identifier
from litex.soc.cores.spi_flash import ECP5SPIFlash
from litex.soc.cores.gpio import GPIOOut, GPIOIn
from litex.soc.integration.soc_core import *
from litex.soc.integration.builder import *
from litex.build.lattice.trellis import trellis_args, trellis_argdict
from liteeth.phy.ecp5rgmii import LiteEthPHYRGMII
from litex.build.generic_platform import *
from litex_boards.targets import colorlight_5a_75x
from litex_boards.platforms import colorlight_5a_75b
from litex.build.generic_platform import *
from basic_system.hub75sender import Hub75Sender
from basic_system.bit_to_flash import convertBitToFlashFile
from basic_system.cl_full import load
import numpy as np
import cv2
ios = [
("led", 0, Pins("j4:1 j4: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")),
Subsignal("lat", Pins("j5:13")),
Subsignal("oen", Pins("j5:14")),
IOStandard("LVCMOS33"))
]
def getContentFromImage(file):
"""Load image and reduce colorspace to RGG332"""
img = cv2.imread(file, 1)
r = [(i >> 0) & 0xe0 for i in img[:, :, 2]]
g = [(i >> 3) & 0x1c for i in img[:, :, 1]]
b = [(i >> 6) & 0x03 for i in img[:, :, 0]]
content = [x[0] + x[1] + x[2] for x in zip(r, g, b)]
return np.array(content, dtype='uint8').flatten()
def getContentFromSyntetic():
content = np.zeros((64, 64), dtype='uint8')
content[ 0:64, 0:64] = 0xff # White Border
content[ 2:62, 2:62] = 0b00100101 # Gray inner Border
content[ 4:60, 4:60] = 0 # Black
content[ 8:16, 8:16] = 0b00000011 # Blue
content[16:24, 16:24] = 0b11100000 # Red
content[24:32, 24:32] = 0b00011100 # Green
content[32:40, 32:40] = 0b00011111 # Cyan
content[40:48, 40:48] = 0b11100011 # Pink
content[48:56, 48:56] = 0b11111100 # Yellow
return content.flatten()
class MemTest(Module, AutoCSR):
def __init__(self):
self.specials.mem = Memory(32,128, init=(1,2,3,4))
self.specials.rdport = self.mem.get_port()
class ClMini(SoCCore):
def __init__(self, with_etherbone=False, ip=None, mac=None):
platform = colorlight_5a_75b.Platform(revision="7.0")
sys_clk_freq = int(60e6)
# SoCMini ----------------------------------------------------------------------------------
SoCMini.__init__(self, platform, clk_freq=sys_clk_freq)
self.submodules.crg = colorlight_5a_75x._CRG(platform, sys_clk_freq)
self.platform.add_extension(ios)
# Etherbone --------------------------------------------------------------------------------
if with_etherbone:
self.submodules.ethphy = LiteEthPHYRGMII(
clock_pads=self.platform.request("eth_clocks"),
pads=self.platform.request("eth"))
self.add_csr("ethphy")
self.add_etherbone(phy=self.ethphy,ip_address=ip, mac_address=mac)
#self.submodules.mymem = MemTest()
#self.add_csr("mymem_mem")
content = getContentFromSyntetic()
#content = getContentFromImage("testimage.png")
self.submodules.hub = Hub75Sender(64, 64, content, platform.request("j5"))
self.add_csr("hub_mem")
self.add_csr("hub")
counter = Signal(32)
self.sync += counter.eq(counter + 1)
self.comb += platform.request("led").eq(counter[22:24])
# Led --------------------------------------------------------------------------------------
self.submodules.led = GPIOOut(platform.request("user_led_n"))
self.add_csr("led")
def main():
parser = argparse.ArgumentParser(description="LiteX SoC on Colorlight 5A-75X")
parser.add_argument("--build", action="store_true", help="build bitstream")
parser.add_argument("--load", action="store_true", help="load bitstream")
parser.add_argument("--flash", action="store_true", help="flash bitstream")
parser.add_argument("--ip-address", default="10.42.1.222", help="Ethernet IP address of the board.")
parser.add_argument("--mac-address", default="0x726b895bc2e2", help="Ethernet MAC address of the board.")
parser.set_defaults(build=True, load=True)
args = parser.parse_args()
soc = ClMini(ip=args.ip_address, mac=int(args.mac_address, 0))
builder = Builder(soc, output_dir="build", csr_csv="scripts/csr.csv")
builder.build(build_name="clmini", run=args.build)
if args.flash: # Convert Bit File to Jtag Write Flash command
name = os.path.join(builder.gateware_dir, soc.build_name)
convertBitToFlashFile(name+".bit", name+".svf.flash")
load(name + ".svf.flash")
return
if args.load: # Temporary Load into FPGA
load(os.path.join(builder.gateware_dir, soc.build_name + ".svf"))
if __name__ == "__main__":
main()

@ -6,6 +6,7 @@
import math
from migen import *
from migen.fhdl import verilog
from litex.soc.interconnect.csr import *
class ColorPWM(Module):
"""PWM dimming for RGB332 Colors"""
@ -35,17 +36,26 @@ class ColorPWM(Module):
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 += self.output.eq(Cat(r1, r2, g1, g2, b1, b2))
self.comb += self.output.eq(Cat(r1, g1, b1, r2, g2, b2))
class Hub75Out(Module):
def __init__(self):
self.rgb = Signal(6)
self.adr = Signal(5)
self.clk = Signal()
self.lat = Signal()
self.oen = Signal()
class Hub75Sender(Module):
class Hub75Sender(Module, AutoCSR):
"""Hub75 LED Matrix driver. Framebuffer Colorformat RGB332"""
def __init__(self, numCols=8, numRows=4, content=None):
def __init__(self, numCols=8, numRows=4, content=None, out=None):
addressOffset = Constant(numCols * numRows/2)
rowCountShift = math.ceil(math.log2(numCols))
memSize = numCols * numRows
#self.status = CSRStatus(32)
# Memory mapped to Wishbone - having second read port
self.specials.mem = Memory(8, numCols * numRows, init=content)
self.specials.mem = Memory(8, memSize, init=content)
ram = self.mem.get_port()
self.specials += ram
@ -57,13 +67,20 @@ class Hub75Sender(Module):
self.rowCount = Signal(max=numRows)
# Output Ports
self.outAddr = Signal(6) # abcde
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),
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)
fsm = FSM(reset_state="RESET")
self.submodules.fsm = fsm
@ -95,7 +112,7 @@ class Hub75Sender(Module):
NextValue(self.outClk, 0),
If(self.pixCount == numCols,
NextValue(self.outOe, 0),
NextValue(self.rowCount, self.rowCount + 1),
#NextValue(self.rowCount, self.rowCount + 1),
NextValue(self.pixCount, 0),
NextState("OeOff") # Finished with Row
).Else(
@ -108,11 +125,12 @@ class Hub75Sender(Module):
fsm.act("LatOff", NextValue(self.outOe, 1), NextState("OeOn"))
fsm.act("OeOn",
If(self.rowCount == Constant(numRows/2),
If(self.rowCount == Constant(numRows/2 - 1),
NextValue(self.rowCount, 0),
pwm.incrementCounter.eq(1),
NextState("Done")
).Else(
NextValue(self.rowCount, self.rowCount + 1),
NextState("AdrUp"))
)
@ -120,12 +138,10 @@ class Hub75Sender(Module):
def testbench():
content = (0x00, 0x01, 0x02, 0x03, 0x14, 0x15, 0x16, 0x17,
0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1c,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f)
0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1c)
dut = Hub75Sender(4, 4, content)
dut = Hub75Sender(4, 4, content, Hub75Out())
def memtest():
for _ in range(500):

Loading…
Cancel
Save