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

ICE40 Feather support #614

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
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
53 changes: 19 additions & 34 deletions platforms/icebreaker.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,27 @@


_io = [
("user_led_n", 0, Pins("11"), IOStandard("LVCMOS33")),
("user_led_n", 1, Pins("37"), IOStandard("LVCMOS33")),
# Color-specific aliases
("user_ledr_n", 0, Pins("11"), IOStandard("LVCMOS33")),
("user_ledg_n", 0, Pins("37"), IOStandard("LVCMOS33")),
("user_btn_n", 0, Pins("10"), IOStandard("LVCMOS33")),
# HACK: Use icefeather pins
("user_led_n", 0, Pins("47"), IOStandard("LVCMOS33")),
("user_led", 0, Pins("41"), IOStandard("LVCMOS33")),
("user_led", 1, Pins("40"), IOStandard("LVCMOS33")),
("user_led", 2, Pins("39"), IOStandard("LVCMOS33")),
# RGB LED
("user_ledr_n", 0, Pins("41"), IOStandard("LVCMOS33")),
("user_ledg_n", 0, Pins("40"), IOStandard("LVCMOS33")),
("user_ledb_n", 0, Pins("39"), IOStandard("LVCMOS33")),
("user_btn_n", 0, Pins("2"), IOStandard("LVCMOS33")),

# HACK: Replace UART with icefeather pins
#("serial", 0,
# Subsignal("rx", Pins("6")),
# Subsignal("tx", Pins("9"), Misc("PULLUP")),
# IOStandard("LVCMOS33")
#),

("serial", 0,
Subsignal("rx", Pins("6")),
Subsignal("tx", Pins("9"), Misc("PULLUP")),
Subsignal("rx", Pins("23")),
Subsignal("tx", Pins("21"), Misc("PULLUP")),
IOStandard("LVCMOS33")
),

Expand All @@ -36,35 +47,9 @@
]

_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"),
("RGBLED", "39 40 41"),
]

# The attached LED/button section can be either used standalone or as a PMOD.
# Attach to platform using:
# plat.add_extension(break_off_pmod)
# pmod_btn = plat.request("user_btn")
break_off_pmod = [
("user_btn", 0, Pins("PMOD2:6"), IOStandard("LVCMOS33")),
("user_btn", 1, Pins("PMOD2:3"), IOStandard("LVCMOS33")),
("user_btn", 2, Pins("PMOD2:7"), IOStandard("LVCMOS33")),

("user_led", 0, Pins("PMOD2:4"), IOStandard("LVCMOS33")),
("user_led", 1, Pins("PMOD2:0"), IOStandard("LVCMOS33")),
("user_led", 2, Pins("PMOD2:1"), IOStandard("LVCMOS33")),
("user_led", 3, Pins("PMOD2:5"), IOStandard("LVCMOS33")),
("user_led", 4, Pins("PMOD2:2"), IOStandard("LVCMOS33")),

# Color-specific aliases
("user_ledr", 0, Pins("PMOD2:4"), IOStandard("LVCMOS33")),
("user_ledg", 0, Pins("PMOD2:0"), IOStandard("LVCMOS33")),
("user_ledg", 1, Pins("PMOD2:1"), IOStandard("LVCMOS33")),
("user_ledg", 2, Pins("PMOD2:5"), IOStandard("LVCMOS33")),
("user_ledg", 3, Pins("PMOD2:2"), IOStandard("LVCMOS33"))
]

rgb_led = [
("rgbled", 0,
Subsignal("rgb0", Pins("RGBLED:0")),
Expand Down
74 changes: 74 additions & 0 deletions platforms/icefeather.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
from litex.build.generic_platform import *
from litex.build.lattice import LatticePlatform
from litex.build.lattice.programmer import IceStormProgrammer


_io = [
("user_led_n", 0, Pins("47"), IOStandard("LVCMOS33")),
# RGB LED
("user_ledr_n", 0, Pins("41"), IOStandard("LVCMOS33")),
("user_ledg_n", 0, Pins("40"), IOStandard("LVCMOS33")),
("user_ledb_n", 0, Pins("39"), IOStandard("LVCMOS33")),
("user_btn_n", 0, Pins("2"), IOStandard("LVCMOS33")),

("serial", 0,
Subsignal("rx", Pins("23")),
Subsignal("tx", Pins("21"), Misc("PULLUP")),
IOStandard("LVCMOS33")
),

("spiflash", 0,
Subsignal("cs_n", Pins("16"), IOStandard("LVCMOS33")),
Subsignal("clk", Pins("15"), IOStandard("LVCMOS33")),
Subsignal("miso", Pins("17"), IOStandard("LVCMOS33")),
Subsignal("mosi", Pins("14"), IOStandard("LVCMOS33")),
# TODO: Do not need these
Subsignal("wp", Pins("12"), IOStandard("LVCMOS33")),
Subsignal("hold", Pins("13"), IOStandard("LVCMOS33")),
),

("spiflash4x", 0,
Subsignal("cs_n", Pins("16"), IOStandard("LVCMOS33")),
Subsignal("clk", Pins("15"), IOStandard("LVCMOS33")),
# TODO: Find out quad-spi pins
Subsignal("dq", Pins("14 17 12 13"), IOStandard("LVCMOS33")),
),

("clk12", 0, Pins("35"), IOStandard("LVCMOS33"))
]

_connectors = [
("RGBLED", "6 4 3"),
]

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"
default_clk_period = 83.333

gateware_size = 0x20000

# FIXME: Create a "spi flash module" object in the same way we have SDRAM
spiflash_model = "n25q128"
spiflash_read_dummy_bits = 8
spiflash_clock_div = 2
spiflash_total_size = int((128/8)*1024*1024) # 128Mbit
spiflash_page_size = 256
# Winbond calls 32kb/64kb sectors "blocks".
spiflash_sector_size = 0x10000

def __init__(self):
LatticePlatform.__init__(self, "ice40-up5k-sg48", _io, _connectors,
toolchain="icestorm")

def create_programmer(self):
return IceStormProgrammer()
2 changes: 1 addition & 1 deletion scripts/download-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ if [ "$PLATFORM" = "tinyfpga_bx" ]; then
fi

# iceprog compatible platforms
if [ "$PLATFORM" = "icebreaker" -o "$PLATFORM" = "ice40_hx8k_b_evn" -o "$PLATFORM" = "ice40_up5k_b_evn" ]; then
if [ "$PLATFORM" = "icebreaker" -o "$PLATFORM" = "icefeather" -o "$PLATFORM" = "ice40_hx8k_b_evn" -o "$PLATFORM" = "ice40_up5k_b_evn" ]; then
echo
echo "Installing iceprog (tool for FTDI)"
conda install iceprog
Expand Down
2 changes: 1 addition & 1 deletion scripts/enter-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ if [ "$PLATFORM" = "tinyfpga_bx" ]; then
fi

# iceprog compatible platforms
if [ "$PLATFORM" = "icebreaker" -o "$PLATFORM" = "ice40_hx8k_b_evn" -o "$PLATFORM" = "ice40_up5k_b_evn" ]; then
if [ "$PLATFORM" = "icebreaker" -o "$PLATFORM" = "icefeather" -o "$PLATFORM" = "ice40_hx8k_b_evn" -o "$PLATFORM" = "ice40_up5k_b_evn" ]; then



Expand Down
1 change: 0 additions & 1 deletion targets/icebreaker/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ def __init__(self, platform, **kwargs):

# Assume user still has LEDs/Buttons still attached to the PCB or as
# a PMOD; pinout is identical either way.
platform.add_extension(icebreaker.break_off_pmod)
clk_freq = int(12e6)

kwargs['cpu_reset_address']=self.mem_map["spiflash"]+platform.gateware_size
Expand Down
66 changes: 66 additions & 0 deletions targets/icefeather/Makefile.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# ice40_up5k targets

ifneq ($(PLATFORM),icefeather)
$(error "Platform should be icefeather when using this file!?")
endif

# Settings
DEFAULT_TARGET = base
TARGET ?= $(DEFAULT_TARGET)
BAUD ?= 115200

# Image
image-flash-$(PLATFORM):
iceprog $(IMAGE_FILE)

# Gateware
gateware-load-$(PLATFORM):
@echo "icefeather doesn't support loading, use the flash target instead."
@echo "make gateware-flash"
@false

# As with Mimasv2, if the user asks to flash the gateware only, the BIOS must
# be sent as well (because the BIOS is too big to fit into the bitstream).
GATEWARE_BIOS_FILE = $(TARGET_BUILD_DIR)/image-gateware+bios+none.bin

gateware-flash-$(PLATFORM): $(GATEWARE_BIOS_FILE)
iceprog $(GATEWARE_BIOS_FILE)

# To avoid duplicating the mkimage.py call here, if the user has not
# already built a image-gateware+bios+none.bin, we call make recursively
# to build one here, with the FIRMWARE=none override.
#
ifneq ($(GATEWARE_BIOS_FILE),$(IMAGE_FILE))
$(GATEWARE_BIOS_FILE): $(GATEWARE_FILEBASE).bin $(BIOS_FILE) mkimage.py
FIRMWARE=none make image
endif

# Firmware
firmware-load-$(PLATFORM):
@echo "Unsupported."
@false

firmware-flash-$(PLATFORM):
@echo "icefeather doesn't support just flashing firmware, use image target instead."
@echo "make image-flash"
@false

firmware-connect-$(PLATFORM):
flterm --port=$(COMM_PORT) --speed=$(BAUD)

firmware-clear-$(PLATFORM):
@echo "FIXME: Unsupported?."
@false

# Bios
bios-flash-$(PLATFORM):
@echo "Unsupported."
@false

# Extra commands
help-$(PLATFORM):
@true

reset-$(PLATFORM):
@echo "Unsupported."
@false
118 changes: 118 additions & 0 deletions targets/icefeather/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import sys
import struct
import os.path
import argparse

from migen import *
from migen.genlib.resetsync import AsyncResetSynchronizer

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 ice40
from gateware import cas
from gateware import spi_flash

from targets.utils import define_flash_constants
from platforms import icefeather

class _CRG(Module):
def __init__(self, platform):
clk12 = platform.request("clk12")

self.clock_domains.cd_sys = ClockDomain()
self.reset = Signal()

# FIXME: Use PLL, increase system clock to 32 MHz, pending nextpnr
# fixes.
self.comb += self.cd_sys.clk.eq(clk12)

# POR reset logic- POR generated from sys clk, POR logic feeds sys clk
# reset.
reset = self.reset | ~platform.request("user_btn_n")
self.clock_domains.cd_por = ClockDomain()
reset_delay = Signal(12, reset=4095)
self.comb += [
self.cd_por.clk.eq(self.cd_sys.clk),
self.cd_sys.rst.eq(reset_delay != 0)
]
self.sync.por += \
If(reset_delay != 0,
reset_delay.eq(reset_delay - 1)
)
self.specials += AsyncResetSynchronizer(self.cd_por, reset)


class BaseSoC(SoCCore):
mem_map = {**SoCCore.mem_map, **{
"spiflash": 0xa0000000,
}}

def __init__(self, platform, **kwargs):
# disable SRAM, it'll be added later
kwargs['integrated_sram_size'] = 0x0

# disable ROM, it'll be added later
kwargs['integrated_rom_size'] = 0x0

# FIXME: Force either lite or minimal variants of CPUs; full is too big.

# Assume user still has LEDs/Buttons still attached to the PCB or as
# a PMOD; pinout is identical either way.
clk_freq = int(12e6)

kwargs['cpu_reset_address']=self.mem_map["spiflash"]+platform.gateware_size
SoCCore.__init__(self, platform, clk_freq, **kwargs)

self.submodules.crg = _CRG(platform)
self.platform.add_period_constraint(self.crg.cd_sys.clk, 1e9/clk_freq)

# Control and Status
self.submodules.cas = cas.ControlAndStatus(platform, clk_freq)
self.add_csr("cas")

# SPI flash peripheral
# TODO: Inferred tristate not currently supported by nextpnr; upgrade
# to spiflash4x when possible.
self.submodules.spiflash = spi_flash.SpiFlashSingle(
platform.request("spiflash"),
dummy=platform.spiflash_read_dummy_bits,
div=platform.spiflash_clock_div,
endianness=self.cpu.endianness)
self.add_csr("spiflash")
self.add_constant("SPIFLASH_PAGE_SIZE", platform.spiflash_page_size)
self.add_constant("SPIFLASH_SECTOR_SIZE", platform.spiflash_sector_size)
self.register_mem("spiflash", self.mem_map["spiflash"],
self.spiflash.bus, size=platform.spiflash_total_size)

# rgb led connector
platform.add_extension(icefeather.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,
type="cached+linker")
self.flash_boot_address = self.mem_map["spiflash"]+platform.gateware_size+bios_size
define_flash_constants(self)

# SPRAM- UP5K has single port RAM, might as well use it as SRAM to
# free up scarce block RAM.
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.
self.add_memory_region("user_flash",
self.flash_boot_address,
# Leave a grace area- possible one-by-off bug in add_memory_region?
# Possible fix: addr < origin + length - 1
platform.spiflash_total_size - (self.flash_boot_address - self.mem_map["spiflash"]) - 0x100,
type="cached+linker")


SoC = BaseSoC