Skip to content

Commit

Permalink
Merge pull request #164 from TomKeddie/tomk_20190707_icebreaker_rgb
Browse files Browse the repository at this point in the history
platform/icebreaker: port rgb led driver from fomu
  • Loading branch information
mithro authored Jul 9, 2019
2 parents 17b548c + eddc28f commit cd662e5
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 17 deletions.
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

0 comments on commit cd662e5

Please sign in to comment.