1
\$\begingroup\$

I'm trying to be able to configure my FPGA by loading the configuration into the flash memory. I am able to write to the SPI flash through an ethernet interface, so I think it would be possible to write the bitstream to the flash over ethernet, and that way I could program the FPGA over the network without using a JTAG cable. Is this possible? How should I generate the bitstream in Vivado? What address in the flash should I use?

I am using a Kintex-7 FPGA and and a Spansion S25FL256S SPI flash chip.

Thanks!!

\$\endgroup\$
  • \$\begingroup\$ You really should read the Xilinx literature on this. Some of their FPGAs can act as an SPI master to autonomously read out data from some types of SPI flashes. Failing that, any little micro should be able to read the flash and push the data in via whatever Xilinx calls their "send it clock and data" bitstream interface. \$\endgroup\$ – Chris Stratton Aug 14 '16 at 20:00
  • \$\begingroup\$ @ChrisStratton Thanks for your comment. I tried looking at the Xilinx documentation and could really only find information on programming the flash memory with the bitstream using JTAG. Can you point me to some useful documentation? Also, I'm not sure what you mean by "send it clock and data." \$\endgroup\$ – Ethan Aug 14 '16 at 20:18
  • \$\begingroup\$ They call it slave serial: xilinx.com/support/documentation/application_notes/xapp502.pdf Again, this is distinct from the master mode they have which supports some flashes, take time to look at all your options before deciding, though if you already have an MCU in the system letting that do it via slave serial can make a lot of sense, especially as that may be your path for changing the flash contents or want to use part of the flash for something else. \$\endgroup\$ – Chris Stratton Aug 14 '16 at 20:23
1
\$\begingroup\$

This is definitely possible. I imagine you're going to need to write a little loader program that will read in the bit file and send it to the FPGA via ethernet. In this case, you don't need to do anything special when generating the bit file, just generate it normally as you would if you were going to program the FPGA directly via JTAG. The bit file contains a little bit of header information in a relatively easy to decode binary format. Your loader script should read in the bit file, strip the header, and then send the rest of the bit file on to the FPGA for writing into the flash chip. After verifying that the data has been written correctly, you can have the FPGA reset itself via the ICAP interface to load the new configuration. I have actually implemented something similar, but instead of writing to Flash memory it writes the bitstream directly to a different FPGA with a wide parallel bus (slave SelectMAP). Actually, you can probably get away with loading the entire bit file verbatim without stripping off the header - the data section of the bit file contains synchronization information, and the FPGA will ignore anything before the synchronization data, including the header.

As for where to burn the config data to flash...it depends on precisely what you want to implement. It is possible to store multiple configurations in flash and trigger the FPGA to reset and load a different configuration. The idea is that you can have a 'golden' configuration that loads first, and then an additional configuration that can be upgraded. I think you may need to set it up so that the FPGA always boots into the 'golden' configuration, then the 'golden' configuration will attempt to reset the FPGA and load the other one via writes to the ICAP primitive. If the configuration fails, the FPGA will reload the 'golden' configuration again. You'll have to perform ICAP accesses with a small state machine to check the configuration status when the 'golden' configuration starts up. The 'golden' configuration should at least implement a way to access the Flash memory so you can update the firmware. It is also possible to implement power on board initialization and board testing in the 'golden' bitstream. Another option is to edit the bit file to set up the write to WBSTAR and trigger a reset with IPROG to skip loading the golden configuration and immediately try loading the main configuration. If the second configuration cannot be loaded, then the FPGA will fall back on the golden configuration. Take a look at the configuration user guide for details; this isn't something that I have experimented with before.

See UG470 and XAPP1247 for more information. XAPP1247 also contains what you need to put in the XDC files to adjust the bit files to automatically boot the 'main' image and automatically fall back on the 'golden' image without having to perform ICAP operations in the design itself.

Here is some python code to parse the header on a bit file:

import struct
import sys

bit_name = 'some_bit_file.bit'

print("Reading bit file %s" % bit_name)

try:
    bit_file = open(bit_name, 'rb')
except Exception as ex:
    print("Error opening \"%s\": %s" %(bit_name, ex.strerror), file=sys.stderr)
    exit(1)

# parse bit file header

# Field 1
# Unknown header
l = struct.unpack(">H", bit_file.read(2))[0]
hdr = bit_file.read(l)

# Field 2
# Unknown header
l = struct.unpack(">H", bit_file.read(2))[0]
hdr = bit_file.read(l)

# Field 3
# Design name
l = struct.unpack(">H", bit_file.read(2))[0]
design_name = bit_file.read(l).decode("utf-8")
print("Design name: %s" % design_name)

# Field 4
# Part name
k = bit_file.read(1)
l = struct.unpack(">H", bit_file.read(2))[0]
part_name = bit_file.read(l).decode("utf-8")
print("Part name: %s" % part_name)

# Field 5
# date
k = bit_file.read(1)
l = struct.unpack(">H", bit_file.read(2))[0]
date = bit_file.read(l).decode("utf-8")
print("Date: %s" % date)

# Field 6
# time
k = bit_file.read(1)
l = struct.unpack(">H", bit_file.read(2))[0]
t = bit_file.read(l).decode("utf-8")
print("Time: %s" % t)

# Field 7
# data
k = bit_file.read(1)
l = struct.unpack(">L", bit_file.read(4))[0]
config_data = bit_file.read(l)

print("Bitfile contains %d bytes" % len(config_data))
\$\endgroup\$
  • \$\begingroup\$ Thanks so much! Great answer! In the end I was planning on having two configurations as you described, but for now, I am interested in having just one as a test that its possible. If I'm doing just one, should programming the bit file to address zero of the flash? Also, thanks for the script, but I learned that Vivado can generate a .bin file that doesnt have the headers. \$\endgroup\$ – Ethan Aug 14 '16 at 22:57
  • \$\begingroup\$ Yeah, just write it at address zero. That's where the FPGA will look first until informed otherwise via internal startup configuration registers. \$\endgroup\$ – alex.forencich Aug 14 '16 at 23:06
  • \$\begingroup\$ Also, the nice thing about parsing the bit file header is you can do some sanity checking (I.e. make sure the part field is correct) \$\endgroup\$ – alex.forencich Aug 14 '16 at 23:07
  • \$\begingroup\$ I also recommend looking at XAPP1247; it has some more information on how to generate the bit files to make use of some of the FPGA configuration features to skip the 'golden' bitstream and then automatically fall back on failure without having to implement at in the logic with ICAP writes. \$\endgroup\$ – alex.forencich Aug 15 '16 at 2:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.