Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

platform/icebreaker: port rgb led driver from fomu #164

Merged
merged 3 commits into from
Jul 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 60 additions & 6 deletions gateware/up5kspram.py → gateware/ice40.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
from migen import *
from litex.soc.interconnect import wishbone
from litex.soc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage

# ICE40 UltraPlus family-specific Wishbone interface to the Single Port RAM
# (SPRAM) primitives. Because SPRAM is much more coarse grained than Block
# RAM resources, this RAM is only minimally configurable at present (64kB or
# 128kB). Because it is single port, this module is meant to be used as the
# CPU's RAM region, leaving block RAM free for other use.

class Up5kSPRAM(Module):
class SPRAM(Module):
"""
ICE40 UltraPlus family-specific Wishbone interface to the Single Port RAM
(SPRAM) primitives. Because SPRAM is much more coarse grained than Block
RAM resources, this RAM is only minimally configurable at present (64kB or
128kB). Because it is single port, this module is meant to be used as the
CPU's RAM region, leaving block RAM free for other use.
"""

def __init__(self, width=32, size=64*1024):

# Right now, LiteX only supports 32-bit CPUs. To get a 32-bit data bus,
Expand Down Expand Up @@ -108,3 +112,53 @@ def __init__(self, width=32, size=64*1024):
self.bus.ack.eq(1)
)
]


class LED(Module, AutoCSR):
def __init__(self, pads):

rgba_pwm = Signal(3)

self.dat = CSRStorage(8)
self.addr = CSRStorage(4)
self.ctrl = CSRStorage(4)

self.specials += Instance("SB_RGBA_DRV",
i_CURREN = self.ctrl.storage[1],
i_RGBLEDEN = self.ctrl.storage[2],
i_RGB0PWM = rgba_pwm[0],
i_RGB1PWM = rgba_pwm[1],
i_RGB2PWM = rgba_pwm[2],
o_RGB0 = pads.rgb0,
o_RGB1 = pads.rgb1,
o_RGB2 = pads.rgb2,
p_CURRENT_MODE = "0b1",
p_RGB0_CURRENT = "0b000011",
p_RGB1_CURRENT = "0b000001",
p_RGB2_CURRENT = "0b000011",
)

self.specials += Instance("SB_LEDDA_IP",
i_LEDDCS = self.dat.re,
i_LEDDCLK = ClockSignal(),
i_LEDDDAT7 = self.dat.storage[7],
i_LEDDDAT6 = self.dat.storage[6],
i_LEDDDAT5 = self.dat.storage[5],
i_LEDDDAT4 = self.dat.storage[4],
i_LEDDDAT3 = self.dat.storage[3],
i_LEDDDAT2 = self.dat.storage[2],
i_LEDDDAT1 = self.dat.storage[1],
i_LEDDDAT0 = self.dat.storage[0],
i_LEDDADDR3 = self.addr.storage[3],
i_LEDDADDR2 = self.addr.storage[2],
i_LEDDADDR1 = self.addr.storage[1],
i_LEDDADDR0 = self.addr.storage[0],
i_LEDDDEN = self.dat.re,
i_LEDDEXE = self.ctrl.storage[0],
# o_LEDDON = led_is_on, # Indicates whether LED is on or not
# i_LEDDRST = ResetSignal(), # This port doesn't actually exist
o_PWMOUT0 = rgba_pwm[0],
o_PWMOUT1 = rgba_pwm[1],
o_PWMOUT2 = rgba_pwm[2],
o_LEDDON = Signal(),
)
12 changes: 11 additions & 1 deletion platforms/icebreaker.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
_connectors = [
("PMOD1A", "4 2 47 45 3 48 46 44"),
("PMOD1B", "43 38 34 31 42 36 32 28"),
("PMOD2", "27 25 21 19 26 23 20 18")
("PMOD2", "27 25 21 19 26 23 20 18"),
("RGBLED", "39 40 41"),
]

# The attached LED/button section can be either used standalone or as a PMOD.
Expand All @@ -64,6 +65,15 @@
("user_ledg", 3, Pins("PMOD2:2"), IOStandard("LVCMOS33"))
]

rgb_led = [
("rgbled", 0,
Subsignal("rgb0", Pins("RGBLED:0")),
Subsignal("rgb1", Pins("RGBLED:1")),
Subsignal("rgb2", Pins("RGBLED:2")),
IOStandard("LVCMOS33")
),
]


class Platform(LatticePlatform):
default_clk_name = "clk12"
Expand Down
7 changes: 4 additions & 3 deletions targets/ice40_up5k_b_evn/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
from litex.soc.integration.soc_core import *
from litex.soc.integration.builder import *

from gateware import up5kspram
from gateware import cas
from gateware import ice40
from gateware import spi_flash

from targets.utils import csr_map_update
Expand Down Expand Up @@ -105,8 +105,8 @@ def __init__(self, platform, **kwargs):

# SPRAM- UP5K has single port RAM, might as well use it as SRAM to
# free up scarce block RAM.
self.submodules.spram = up5kspram.Up5kSPRAM(size=128*1024)
self.register_mem("sram", 0x10000000, self.spram.bus, 0x20000)
self.submodules.spram = ice40.SPRAM(size=128*1024)
self.register_mem("sram", self.mem_map["sram"], self.spram.bus, 0x20000)

# We don't have a DRAM, so use the remaining SPI flash for user
# program.
Expand All @@ -121,4 +121,5 @@ def __init__(self, platform, **kwargs):
platform.toolchain.build_template[3] = "icepack -s {build_name}.txt {build_name}.bin"
platform.toolchain.nextpnr_build_template[2] = "icepack -s {build_name}.txt {build_name}.bin"


SoC = BaseSoC
12 changes: 9 additions & 3 deletions targets/icebreaker/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
from litex.build.generic_platform import Pins, Subsignal, IOStandard
from litex.soc.integration.soc_core import *
from litex.soc.integration.builder import *
from litex.soc.interconnect.csr import AutoCSR, CSRStatus, CSRStorage

from gateware import up5kspram
from gateware import ice40
from gateware import cas
from gateware import spi_flash

Expand Down Expand Up @@ -104,15 +105,20 @@ def __init__(self, platform, **kwargs):
self.register_mem("spiflash", self.mem_map["spiflash"],
self.spiflash.bus, size=platform.spiflash_total_size)

# rgb led connector
platform.add_extension(icebreaker.rgb_led)
self.submodules.rgbled = ice40.LED(platform.request("rgbled", 0))
self.add_csr("rgbled")

bios_size = 0x8000
self.add_constant("ROM_DISABLE", 1)
self.add_memory_region("rom", kwargs['cpu_reset_address'], bios_size)
self.flash_boot_address = self.mem_map["spiflash"]+platform.gateware_size+bios_size

# SPRAM- UP5K has single port RAM, might as well use it as SRAM to
# free up scarce block RAM.
self.submodules.spram = up5kspram.Up5kSPRAM(size=128*1024)
self.register_mem("sram", 0x10000000, self.spram.bus, 0x20000)
self.submodules.spram = ice40.SPRAM(size=128*1024)
self.register_mem("sram", self.mem_map["sram"], self.spram.bus, 0x20000)

# We don't have a DRAM, so use the remaining SPI flash for user
# program.
Expand Down
9 changes: 5 additions & 4 deletions targets/upduino_v1/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@
from migen.genlib.resetsync import AsyncResetSynchronizer
from migen.fhdl import verilog


from litex.build.generic_platform import Pins, Subsignal, IOStandard
from litex.soc.integration.soc_core import *
from litex.soc.integration.builder import *

from gateware import up5kspram
from gateware import cas
from gateware import ice40
from gateware import spi_flash

from targets.utils import csr_map_update
import platforms.upduino_v1 as upduino


class _CRG(Module):
def __init__(self, platform):
clk_hfosc = platform.request("sb_hfosc")
Expand Down Expand Up @@ -91,8 +91,8 @@ def __init__(self, platform, **kwargs):

# SPRAM- UP5K has single port RAM, might as well use it as SRAM to
# free up scarce block RAM.
self.submodules.spram = up5kspram.Up5kSPRAM(size=128*1024)
self.register_mem("sram", 0x10000000, self.spram.bus, 0x20000)
self.submodules.spram = ice40.SPRAM(size=128*1024)
self.register_mem("sram", self.mem_map["sram"], self.spram.bus, 0x20000)

# We don't have a DRAM, so use the remaining SPI flash for user
# program.
Expand All @@ -107,4 +107,5 @@ def __init__(self, platform, **kwargs):
platform.toolchain.build_template[3] = "icepack -s {build_name}.txt {build_name}.bin"
platform.toolchain.nextpnr_build_template[2] = "icepack -s {build_name}.txt {build_name}.bin"


SoC = BaseSoC