Created
January 22, 2022 12:14
-
-
Save colinoflynn/06ccb46f8e09d35ca3cb68c8178a486b to your computer and use it in GitHub Desktop.
iCE40 CRAM (Configuration) Programming via FTDI (for IceBreaker, ice40 breakout boards, etc)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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