Merge pull request #67 from mubes/ecp5_usb
Addition of USB ACM for ECP5
This commit is contained in:
commit
4b4f2f9eb8
|
@ -172,6 +172,13 @@ _io_v7_0 = [ # Documented by @miek
|
|||
Subsignal("tx_data", Pins("T14 R12 R13 R14")),
|
||||
IOStandard("LVCMOS33")
|
||||
),
|
||||
|
||||
("usb", 0,
|
||||
Subsignal("d_p", Pins("M8")),
|
||||
Subsignal("d_n", Pins("R2")),
|
||||
Subsignal("pullup", Pins("P4")),
|
||||
IOStandard("LVCMOS33")
|
||||
),
|
||||
]
|
||||
|
||||
# from https://github.com/miek/chubby75/blob/5a-75b-v7_pinout/5a-75b/hardware_V6.1.md
|
||||
|
|
|
@ -84,6 +84,13 @@ _io = [
|
|||
Subsignal("n", Pins("C10")),
|
||||
IOStandard("LVCMOS33")
|
||||
),
|
||||
|
||||
("usb", 0,
|
||||
Subsignal("d_p", Pins("D15")),
|
||||
Subsignal("d_n", Pins("E15")),
|
||||
Subsignal("pullup", Pins("B12 C12")),
|
||||
IOStandard("LVCMOS33")
|
||||
),
|
||||
]
|
||||
|
||||
# Platform -----------------------------------------------------------------------------------------
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
USB
|
||||
===
|
||||
USB support has been integrated for the V7.0 this board. Supporting other
|
||||
versions should be trivial and just need pinning changes. To build with
|
||||
usb support just do;
|
||||
|
||||
./colourlight_5a_75b.py --uart-name=usb_cdc
|
||||
|
||||
To install onto the board;
|
||||
|
||||
./colourlight_5a_75b.py --load
|
||||
|
||||
The USB Serial connection will appear as /dev/ttyACMx, or equivalent on your OS.
|
||||
|
||||
Pinning for V7.0;
|
||||
|
||||
* Replace U23 with a SN74CBT3245APWR, or remove U23 and place jumper wires.
|
||||
(You're basically making the ports Bi-directional).
|
||||
|
||||
* Place a 15K resistor between J4 pin 2 and J4 pin 4.
|
||||
|
||||
* Place a 15K resistor between J4 pin 3 and J4 pin 4.
|
||||
|
||||
* Place a 1.5K resistor between J4 pin 1 and J4 pin 3.
|
||||
|
||||
* Connect USB DP (Green) to J4 pin 3, USB DN (White) to J4 pin 2.
|
|
@ -0,0 +1,11 @@
|
|||
USB
|
||||
===
|
||||
USB support has been integrated and tested for V3.0.3 this board. Revisions
|
||||
higher than this should be supported. The USB connection is on US2.
|
||||
|
||||
To build with usb support just do;
|
||||
|
||||
./ulx3s.py --uart-name=usb_cdc
|
||||
|
||||
The USB Serial connection will appear as /dev/ttyACMx, or equivalent on your OS.
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
# Very basic bitstream to SVF converter, tested with the ULX3S WiFi interface
|
||||
|
||||
flash_page_size = 256
|
||||
erase_block_size = 64*1024
|
||||
|
||||
|
||||
def bitreverse(x):
|
||||
y = 0
|
||||
for i in range(8):
|
||||
if (x >> (7 - i)) & 1 == 1:
|
||||
y |= (1 << i)
|
||||
return y
|
||||
|
||||
with open(sys.argv[1], 'rb') as bitf:
|
||||
bs = bitf.read()
|
||||
# Autodetect IDCODE from bitstream
|
||||
idcode_cmd = bytes([0xE2, 0x00, 0x00, 0x00])
|
||||
idcode = None
|
||||
for i in range(len(bs) - 4):
|
||||
if bs[i:i+4] == idcode_cmd:
|
||||
idcode = bs[i+4] << 24
|
||||
idcode |= bs[i+5] << 16
|
||||
idcode |= bs[i+6] << 8
|
||||
idcode |= bs[i+7]
|
||||
break
|
||||
if idcode is None:
|
||||
print("Failed to find IDCODE in bitstream, check bitstream is valid")
|
||||
sys.exit(1)
|
||||
bitf.seek(0)
|
||||
|
||||
address = 0
|
||||
last_page = -1
|
||||
|
||||
with open(sys.argv[2], 'w') as svf:
|
||||
print("""
|
||||
STATE RESET;
|
||||
HDR 0;
|
||||
HIR 0;
|
||||
TDR 0;
|
||||
TIR 0;
|
||||
ENDDR DRPAUSE;
|
||||
ENDIR IRPAUSE;
|
||||
STATE IDLE;
|
||||
""", file=svf)
|
||||
print("""
|
||||
SIR 8 TDI (E0);
|
||||
SDR 32 TDI (00000000)
|
||||
TDO ({:08X})
|
||||
MASK (FFFFFFFF);
|
||||
""".format(idcode), file=svf)
|
||||
print("""
|
||||
SIR 8 TDI (1C);
|
||||
SDR 510 TDI (3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
||||
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
|
||||
|
||||
// Enter Programming mode
|
||||
SIR 8 TDI (C6);
|
||||
SDR 8 TDI (00);
|
||||
RUNTEST IDLE 2 TCK 1.00E-02 SEC;
|
||||
|
||||
// Erase
|
||||
SIR 8 TDI (0E);
|
||||
SDR 8 TDI (01);
|
||||
RUNTEST IDLE 2 TCK 2.0E-1 SEC;
|
||||
|
||||
// Read STATUS
|
||||
SIR 8 TDI (3C);
|
||||
SDR 32 TDI (00000000)
|
||||
TDO (00000000)
|
||||
MASK (0000B000);
|
||||
|
||||
// Exit Programming mode
|
||||
SIR 8 TDI (26);
|
||||
RUNTEST IDLE 2 TCK 1.00E-02 SEC;
|
||||
|
||||
// BYPASS
|
||||
SIR 8 TDI (FF);
|
||||
STATE IDLE;
|
||||
RUNTEST 32 TCK;
|
||||
RUNTEST 2.00E-2 SEC;
|
||||
|
||||
// Enter SPI mode
|
||||
|
||||
SIR 8 TDI (3A);
|
||||
SDR 16 TDI (68FE);
|
||||
STATE IDLE;
|
||||
RUNTEST 32 TCK;
|
||||
RUNTEST 2.00E-2 SEC;
|
||||
|
||||
// SPI IO
|
||||
SDR 8 TDI (D5);
|
||||
|
||||
RUNTEST 2.00E-0 SEC;
|
||||
|
||||
// CONFIRM FLASH ID
|
||||
SDR 32 TDI (000000F9)
|
||||
TDO (68FFFFFF)
|
||||
MASK (FF000000);
|
||||
|
||||
SDR 8 TDI(60);
|
||||
SDR 16 TDI(0080);
|
||||
RUNTEST 1.00E-0 SEC;
|
||||
|
||||
|
||||
""", file=svf)
|
||||
while True:
|
||||
if((address // 0x10000) != last_page):
|
||||
last_page = (address // 0x10000)
|
||||
print("""SDR 8 TDI (60);
|
||||
""", file=svf)
|
||||
address_flipped = [bitreverse(x) for x in [0xd8,int(address // 0x10000),0x00,0x00]]
|
||||
hex_address= ["{:02X}".format(x) for x in reversed(address_flipped)]
|
||||
print("\n".join(textwrap.wrap("SDR {} TDI ({});".format(8*len(hex_address), "".join(hex_address)), 100)), file=svf)
|
||||
print("""RUNTEST 3.00 SEC;
|
||||
""", file=svf)
|
||||
|
||||
chunk = bitf.read(flash_page_size)
|
||||
if not chunk:
|
||||
break
|
||||
# Convert chunk to bit-reversed hex
|
||||
br_chunk = [bitreverse(x) for x in bytes([0x02, int(address / 0x10000 % 0x100),int(address / 0x100 % 0x100),int(address % 0x100)]) + chunk]
|
||||
address += len(chunk)
|
||||
hex_chunk = ["{:02X}".format(x) for x in reversed(br_chunk)]
|
||||
print("""
|
||||
SDR 8 TDI (60);
|
||||
""", file=svf)
|
||||
print("\n".join(textwrap.wrap("SDR {} TDI ({});".format(8*len(br_chunk), "".join(hex_chunk)), 100)), file=svf)
|
||||
print("""
|
||||
RUNTEST 2.50E-2 SEC;
|
||||
""", file=svf)
|
||||
|
||||
print("""
|
||||
// BYPASS
|
||||
SIR 8 TDI (FF);
|
||||
|
||||
//REFRESH
|
||||
SIR 8 TDI(79);
|
||||
SDR 24 TDI(000000);
|
||||
|
||||
STATE IDLE;
|
||||
RUNTEST 32 TCK;
|
||||
RUNTEST 2.00E-2 SEC;
|
||||
STATE RESET;
|
||||
""", file=svf)
|
|
@ -48,7 +48,7 @@ from liteeth.phy.ecp5rgmii import LiteEthPHYRGMII
|
|||
# CRG ----------------------------------------------------------------------------------------------
|
||||
|
||||
class _CRG(Module):
|
||||
def __init__(self, platform, sys_clk_freq, with_rst=True):
|
||||
def __init__(self, platform, sys_clk_freq, with_usb_pll=False, with_rst=True):
|
||||
self.clock_domains.cd_sys = ClockDomain()
|
||||
self.clock_domains.cd_sys_ps = ClockDomain()
|
||||
|
||||
|
@ -67,22 +67,34 @@ class _CRG(Module):
|
|||
pll.create_clkout(self.cd_sys_ps, sys_clk_freq, phase=180) # Idealy 90° but needs to be increased.
|
||||
self.specials += AsyncResetSynchronizer(self.cd_sys, ~pll.locked | ~rst_n)
|
||||
|
||||
# USB PLL
|
||||
if with_usb_pll:
|
||||
self.submodules.usb_pll = usb_pll = ECP5PLL()
|
||||
usb_pll.register_clkin(clk25, 25e6)
|
||||
self.clock_domains.cd_usb_12 = ClockDomain()
|
||||
self.clock_domains.cd_usb_48 = ClockDomain()
|
||||
usb_pll.create_clkout(self.cd_usb_12, 12e6, margin=0)
|
||||
usb_pll.create_clkout(self.cd_usb_48, 48e6, margin=0)
|
||||
#self.comb += self.cd_usb_48.clk.eq(self.cd_sys.clk)
|
||||
|
||||
# SDRAM clock
|
||||
self.specials += DDROutput(1, 0, platform.request("sdram_clock"), ClockSignal("sys_ps"))
|
||||
|
||||
# BaseSoC ------------------------------------------------------------------------------------------
|
||||
|
||||
class BaseSoC(SoCCore):
|
||||
def __init__(self, revision, with_ethernet=False, with_etherbone=False, **kwargs):
|
||||
def __init__(self, revision, with_ethernet=False, with_etherbone=False, sys_clk_freq=60e6, **kwargs):
|
||||
platform = colorlight_5a_75b.Platform(revision=revision)
|
||||
sys_clk_freq = int(125e6) if with_etherbone else int(60e6)
|
||||
if (with_etherbone):
|
||||
sys_clk_freq = int(125e6)
|
||||
|
||||
# SoCCore ----------------------------------------------------------------------------------
|
||||
SoCCore.__init__(self, platform, clk_freq=sys_clk_freq, **kwargs)
|
||||
|
||||
# CRG --------------------------------------------------------------------------------------
|
||||
with_rst = kwargs["uart_name"] not in ["serial", "bridge"] # serial_rx shared with user_btn_n.
|
||||
self.submodules.crg = _CRG(platform, sys_clk_freq, with_rst=with_rst)
|
||||
with_usb_pll = kwargs.get("uart_name", None) == "usb_cdc"
|
||||
self.submodules.crg = _CRG(platform, sys_clk_freq, with_usb_pll=with_usb_pll,with_rst=with_rst)
|
||||
|
||||
# SDR SDRAM --------------------------------------------------------------------------------
|
||||
if not self.integrated_main_ram_size:
|
||||
|
@ -115,23 +127,44 @@ class BaseSoC(SoCCore):
|
|||
|
||||
# Load ---------------------------------------------------------------------------------------------
|
||||
|
||||
def load():
|
||||
def openocd_run_svf(filename, iface="ftdi"):
|
||||
import os
|
||||
f = open("openocd.cfg", "w")
|
||||
f.write(
|
||||
"""
|
||||
interface ftdi
|
||||
if (iface == "ftdi"):
|
||||
f.write(
|
||||
"""adapter driver ftdi
|
||||
ftdi_vid_pid 0x0403 0x6011
|
||||
ftdi_channel 0
|
||||
ftdi_layout_init 0x0098 0x008b
|
||||
reset_config none
|
||||
adapter_khz 25000
|
||||
adapter speed 25000
|
||||
jtag newtap ecp5 tap -irlen 8 -expected-id 0x41111043
|
||||
""")
|
||||
elif (iface=="jlink"):
|
||||
f.write("""adapter driver jlink
|
||||
transport select jtag
|
||||
reset_config none
|
||||
telnet_port 4444
|
||||
adapter speed 10000
|
||||
jtag newtap lfe5u25 tap -irlen 8 -irmask 0xFF -ircapture 0x5 -expected-id 0x41111043
|
||||
""")
|
||||
else:
|
||||
print("Unrecognised jtag interface")
|
||||
exit()
|
||||
|
||||
f.close()
|
||||
os.system("openocd -f openocd.cfg -c \"transport select jtag; init; svf soc_basesoc_colorlight_5a_75b/gateware/top.svf; exit\"")
|
||||
os.system("openocd -d0 -f openocd.cfg -c \"transport select jtag; init; svf -tap lfe5u25.tap {} -quiet -progress; exit\"".format(filename))
|
||||
os.system("rm openocd.cfg")
|
||||
exit()
|
||||
|
||||
def load(iface="ftdi"):
|
||||
openocd_run_svf("soc_basesoc_colorlight_5a_75b/gateware/top.svf",iface=iface)
|
||||
|
||||
def flash(iface="ftdi"):
|
||||
import os
|
||||
os.system("./bit_to_flash.py soc_basesoc_colorlight_5a_75b/gateware/top.bit soc_basesoc_colorlight_5a_75b/gateware/top.svf.flash")
|
||||
openocd_run_svf("soc_basesoc_colorlight_5a_75b/gateware/top.svf.flash",iface=iface)
|
||||
|
||||
# Build --------------------------------------------------------------------------------------------
|
||||
|
||||
def main():
|
||||
|
@ -144,15 +177,24 @@ def main():
|
|||
parser.add_argument("--with-etherbone", action="store_true", help="enable Etherbone support")
|
||||
parser.add_argument("--eth-phy", default=0, type=int, help="Ethernet PHY 0 or 1 (default=0)")
|
||||
parser.add_argument("--load", action="store_true", help="load bitstream")
|
||||
parser.add_argument("--flash", action="store_true", help="flash bitstream")
|
||||
parser.add_argument("--iface", default="ftdi", help="loading jtag interface")
|
||||
parser.add_argument("--sys-clk-freq", default=60e6,
|
||||
help="system clock frequency (default=60MHz)")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.load:
|
||||
load()
|
||||
load(iface=args.iface)
|
||||
|
||||
if args.flash:
|
||||
flash(iface=args.iface)
|
||||
|
||||
assert not (args.with_ethernet and args.with_etherbone)
|
||||
soc = BaseSoC(revision=args.revision,
|
||||
with_ethernet = args.with_ethernet,
|
||||
with_etherbone = args.with_etherbone,
|
||||
sys_clk_freq = args.sys_clk_freq,
|
||||
**soc_core_argdict(args))
|
||||
builder = Builder(soc, **builder_argdict(args))
|
||||
builder.build(**trellis_argdict(args))
|
||||
|
|
|
@ -27,7 +27,7 @@ from litedram.phy import GENSDRPHY
|
|||
# CRG ----------------------------------------------------------------------------------------------
|
||||
|
||||
class _CRG(Module):
|
||||
def __init__(self, platform, sys_clk_freq):
|
||||
def __init__(self, platform, sys_clk_freq, with_usb_pll=False):
|
||||
self.clock_domains.cd_sys = ClockDomain()
|
||||
self.clock_domains.cd_sys_ps = ClockDomain(reset_less=True)
|
||||
|
||||
|
@ -42,10 +42,17 @@ class _CRG(Module):
|
|||
self.submodules.pll = pll = ECP5PLL()
|
||||
self.comb += pll.reset.eq(rst)
|
||||
pll.register_clkin(clk25, 25e6)
|
||||
pll.create_clkout(self.cd_sys, sys_clk_freq)
|
||||
pll.create_clkout(self.cd_sys, sys_clk_freq, margin=0)
|
||||
pll.create_clkout(self.cd_sys_ps, sys_clk_freq, phase=90)
|
||||
self.specials += AsyncResetSynchronizer(self.cd_sys, ~pll.locked | rst)
|
||||
|
||||
# USB PLL
|
||||
if with_usb_pll:
|
||||
self.clock_domains.cd_usb_12 = ClockDomain()
|
||||
self.clock_domains.cd_usb_48 = ClockDomain()
|
||||
pll.create_clkout(self.cd_usb_12, 12e6, margin=0)
|
||||
self.comb += self.cd_usb_48.clk.eq(self.cd_sys.clk)
|
||||
|
||||
# SDRAM clock
|
||||
self.specials += DDROutput(1, 0, platform.request("sdram_clock"), ClockSignal("sys_ps"))
|
||||
|
||||
|
@ -64,7 +71,8 @@ class BaseSoC(SoCCore):
|
|||
SoCCore.__init__(self, platform, clk_freq=sys_clk_freq, **kwargs)
|
||||
|
||||
# CRG --------------------------------------------------------------------------------------
|
||||
self.submodules.crg = _CRG(platform, sys_clk_freq)
|
||||
with_usb_pll = kwargs.get("uart_name", None) == "usb_cdc"
|
||||
self.submodules.crg = _CRG(platform, sys_clk_freq, with_usb_pll)
|
||||
|
||||
# SDR SDRAM --------------------------------------------------------------------------------
|
||||
if not self.integrated_main_ram_size:
|
||||
|
@ -87,8 +95,8 @@ def main():
|
|||
help="gateware toolchain to use, trellis (default) or diamond")
|
||||
parser.add_argument("--device", dest="device", default="LFE5U-45F",
|
||||
help="FPGA device, ULX3S can be populated with LFE5U-45F (default) or LFE5U-85F")
|
||||
parser.add_argument("--sys-clk-freq", default=50e6,
|
||||
help="system clock frequency (default=50MHz)")
|
||||
parser.add_argument("--sys-clk-freq", default=48e6,
|
||||
help="system clock frequency (default=48MHz)")
|
||||
parser.add_argument("--sdram-module", default="MT48LC16M16",
|
||||
help="SDRAM module: MT48LC16M16, AS4C32M16 or AS4C16M16 (default=MT48LC16M16)")
|
||||
builder_args(parser)
|
||||
|
|
Loading…
Reference in New Issue