Skip to content

Instantly share code, notes, and snippets.

@colinoflynn
Created January 22, 2022 12:14
Show Gist options
  • Save colinoflynn/06ccb46f8e09d35ca3cb68c8178a486b to your computer and use it in GitHub Desktop.
Save colinoflynn/06ccb46f8e09d35ca3cb68c8178a486b to your computer and use it in GitHub Desktop.
iCE40 CRAM (Configuration) Programming via FTDI (for IceBreaker, ice40 breakout boards, etc)
# Example of using PyFTDI to program CRAM on ICE40 FPGA. For example
# if you are using IceBreaker, you'd need to change jumpers to route
# SPI to the FPGA directly instead of the SPI flash.
import pyftdi
from pyftdi.spi import SpiController
import time
class ICE40_ftdi(object):
def __init__(self, devstr='ftdi://::/1'):
# Instantiate a SPI controller, reserve two CS pins (ADBUS*3, ADBUS*4)
spi = SpiController(2)
# Configure the first interface (IF/1) of the first FTDI device as a
# SPI master
spi.configure(devstr)
# IceBreaker - CS pin on ADBUS*4
fpga = spi.get_port(cs=1, freq=24E6, mode=0)
# Get GPIO port to manage extra pins, ADBUS*7 (0x80) as CRST, ADBUS*6 (0x40) as DONE
gpio = spi.get_gpio()
gpio.set_direction(0x80 | 0x40, 0x80)
self.gpio = gpio
self.fpgaspi = fpga
def load(self, bspath):
# Open bitstream
f = open(bspath, "rb")
data = f.read()
f.close()
fpga = self.fpgaspi
gpio = self.gpio
# Start exchange so CS goes low
fpga.exchange([0], start=True, stop=False)
time.sleep(0.05)
# Assert CRST to zero, then set back to one
gpio.write(0x00)
time.sleep(0.05)
gpio.write(0x80)
time.sleep(0.05) #If FTDI is fast this seems to be needed
# Stream out - pyftdi barfs if you send everything at once to split
# it up as needed.
si = 0
chunk = 16384
ei = si + chunk
nowdone = False
while True:
fpga.exchange(data[si:ei], start=False, stop=False)
if nowdone:
break
si = ei
ei = si + chunk
if ei > len(data):
ei = len(data)
nowdone = True
# Add extra clock cycles so program starts, otherwise only
# done pin goes high but isn't running
fpga.exchange(readlen=400, start=False, stop=True)
if gpio.read() & 0x40:
print("DONE Pin High")
else:
raise IOError("DONE pin did not go high!")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment