FPGALink: Easy USB to FPGA Communication
Page created on 2011-03-26 at 0:13:02 UTC by Chris – 32 Comments
Because of its ubiquity, USB provides a good mechanism for JTAG-programming Field-Programmable Gate Arrays, but it also provides a good conduit for the host to exchange data with the FPGA, once programmed. FPGA development kits incorporating some kind of USB-capable microcontroller are common, and cheap. Unfortunately there is a confusing variety of different devkits, with different FPGAs and different USB microcontrollers, and a general lack of good software and firmware for interacting with them, and the software that is provided is often released under a restrictive license, or only available for one platform.
The FPGALink library is my attempt to provide an end-to end solution capable of JTAG-programming the FPGA on a variety of USB-based hardware platforms, and subsequently communicating with it using a straightforward API on the host side and a standard FIFO interface on the FPGA side. It works on many host and FPGA platforms. All source code is released under the GNU Lesser General Public License v3.0, meaning you are free to distribute unmodified copies of it (or binaries built from unmodified source) with your products. It has no commercial or hardware platform usage restrictions (cf. Digilent Adept may only be used on Digilent hardware), so you can prototype your design with an inexpensive devkit, and then use the same software tools on your custom-built PCBs, so you can easily distribute updated FPGA designs to your customers just as you would with firmware updates, with no special programming cables required, making your FPGA truly "field-programmable".
The source code should compile with minor changes on most modern platforms. Binaries are provided for the following platforms:
| Platform | Architectures |
|---|---|
| Linux | x86_64, i686, arm, ppc |
| MacOSX | x86_64, i386 |
| Windows | i686 |
The FPGALink library is just a C DLL, so using it from C and C++ is straightforward. Bindings are provided for Python and Excel/VBA. Simple examples are provided for all three languages. There is also a utility which provides straightforward command-line access to many of the library functions.
On the FPGA side, all HDL code is provided in separate VHDL & Verilog implementations. The VHDL code includes GHDL/GTKWave-based simulation testbenches. Xilinx and Altera target FPGAs are supported. There is firmware support for the Cypress FX2LP and the USB-capable Atmel AVR8s. There are a couple of ready-made example FPGA designs with platform support for these boards:
- KNJN Xylo-L
- Digilent Atlys
- Digilent Nexys2 (500K & 1200K editions)
- Digilent Nexys3
- Digilent S3BOARD (needs FX2 add-on board)
- EP2C5 Mini Board (needs Minimus USB AVR Board or similar)
However, there are many FPGA devkits available with basically FPGALink-compatible hardware, so if you have a board that is not listed here that you'd like to use with FPGALink, send a message to the FPGALink User Group.




32 Comments
Rich says:
2011-04-24 at 17:20:20 UTCHi Chris,
I think i have succesfully built what I need using SDCC 2.9, but I now need to find the configuration settings (for xilprg.conf) for the Spartan 6 series of FPGA's.
Many thanks for the great software!
Chris says:
2011-04-24 at 18:48:15 UTCThe xilprg code bundled with NeoPurgo was written by Zoltán Csizmadia; you can find its homepage here. The only changes I made to Zoltán's code were to implement the NeroJTAG back-end and to replace the readline-based command-shell with a command-line interface. I'm not familiar with the
.bitfile programming algorithms. It might be worth asking Zoltán for some guidance on implementing Spartan-6 support.Chris says:
2011-04-26 at 12:48:01 UTCOf course, the alternative is to not use xilprg at all, but to use Xilinx impact to generate an XSVF file from your Spartan-6
.bitfile, then convert it to a CSVF file with xsvf2csvf, and then use csvfplay to load it into your FPGA. It's a bit more inconvenient, but not much slower than using xilprg.Rich says:
2011-04-28 at 23:12:39 UTCMany thanks for the advice, I will try csvfplay soon and let you know how I get on.
ben says:
2011-05-05 at 08:31:17 UTCHi Chris,
This is awesome. I'm in the process of trying to build an open source 32 channel audio interface/surround sound processor based on the Nexys2. At the moment, I've switched over completely to NeoPurgo because it's much faster than Adept and I'm trying to squeeze as much audio as I can over the USB link. I've got that mostly working now, but I'm looking for a good way to throttle the data transfer without having to stop it completely. I'm trying to modify your VHDL to add an additional state for pausing data transfer to give the audio buffers a chance to empty. I think I've got that working, but I also need to modify the host software and possibly the FX2 firmware so that it restarts the data transfer where it left off instead of dying completely. Would you have any suggestions as to where I should start looking to make modifications? I found a usb_bulk_write function, but can't seem to find its declaration. It may be enough to do several smaller calls of usb_bulk_write, but I'm trying to avoid a large message cue to keep the data rate fast.
I'm just beginning to look at this and don't know too much. I hope this makes some sense and doesn't sound completely ignorant. I'd appreciate any thoughts or suggestions you might have!
Thanks for the awesome software,
Ben
Chris says:
2011-05-05 at 12:13:26 UTCHello Ben, glad you like it!
Following feedback I've had from early adopters, I'm repackaging NeoPurgo to include an easy-to-use DLL (.so on Linux) which will make it possible for people to evaluate it without having to install all the tooling necessary to build from source. The library incorporates:
It would be good if you could try the library and let me know what you think. I'll send you an alpha version.
As far as throttling goes, I've had some success with throttling to a guaranteed-predictable rate by adding wait states into the VHDL as you mention. Unfortunately that approach will not work well for cases where the throttling is to an unpredictable rate (i.e you have no idea when data will be available, or how much). This is because the host code is inherently synchronous: you say "get some data" and it blocks until it has your data or it hits the timeout. But if the host side times out (as it can do if your data flow is unpredictable), it leaves the FX2 and FPGA in a state which I suspect will be difficult to recover from.
The alternatives are:
The latter is probably non-trivial because aynchronous USB is handled differently on the Windows and Linux versions of LibUSB.
The last point I wanted to make is about latency. NeoPurgo uses bulk USB endpoints to transfer data to and from the FPGA. Bulk endpoints are reliable in the sense that they will never silently drop or corrupt data, but without latency guarantees. USB audio I/O modules usually use isochronous endpoints, which offer guaranteed latency at the expense of data integrity.
ben says:
2011-05-05 at 16:18:44 UTCHi Chris,
That sounds good. I'd love to test the library. As far as endpoints and asynchronous transfer, it seems like I'd need to re-do a lot of bits. For now, I'm mostly concerned with sending data to the FPGA rather than getting data from it. So I guess that leaves two questions:
-- If I halt during a READ or IDLE state (while sending data to the FPGA), and go into a loop with all the handshake lines disabled (high) until a buffer is empty, will the FX2 firmware try to return to the original state (READ/IDLE) or would it want to restart from the IDLE state regardless and send a new wcount, etc...? Or would it be completely unpredictable? Is it the firmware responsible for handling those pauses or does it pass handshaking data back to the host controlling the transfer?
-- Is it possible to increase the data timeout in the host bulk sending program or is that somewhere in libusb as well?
I think I will try to write something isochronous (with native OS drivers) over the summer, but for the next couple of weeks (to debug hardware), it would be cool to see if it could work this way for multi-channel audio output by sending raw byte streams using host.
Ben
max says:
2011-06-18 at 14:27:14 UTCHi Sir,
nice work, I found your posting while searching for comments on sending files to and from FPGA, I'm using the digilent Atlys board with the usb and pic micro-controller that provides the EPP style as well as streaming mode (what digilent call DSTM), I built the Digilient Synchronous Transfer Mode logic inside the fpga, and tried to use thier software ADEPT, they have there a tab called "file I/O" that I expected it to controls that mode, I tried to send a an ascii files w/o success,
I got errors on the format and ..... I realized that I do not fully understand how to activate it. I see in your diagram on top of that post, that the interface with the fpga is the same, you just dont mention the ADEPT software that I believe you wrote your own. anyway I will appreciate some data on file format and how to activate that mode from software point of view.
Best Rgards
Max
(p.s. I manged to implement the "register I/O" (EPP) using the dpimref (you also mentioned that in your post) and i works well.)
Chris says:
2011-06-18 at 16:56:58 UTCHello Max.
FPGALink should work fine on the Atlys board since as you mention it uses the same FX2LP microcontroller with the same pin connections. You would naturally have to provide Atlys platform files for the VHDL build. When you get it working feel free to send me patches so I can include your Atlys platform files in the project on GitHub, so others may benefit from your work.
As to your questions about sending files to and from the FPGA, I'm confused. Are you asking about how to do transfers using FPGALink or with Adept? If the former, you just use the
flWriteRegister()orflReadRegister()functions (see the API docs); these functions can send and receive single bytes or whole files. If the latter, I don't know; but I'd be interested to hear the ways in which FPGALink does not meet your needs, so I can improve it.max says:
2011-12-16 at 14:40:29 UTCHi Chris,
I implemented the digilent asynchronous interface for the ATLYS board, and it works with ADEPT (out of box) w/o additional software, supporting single and burst I/O. I have some documentation and testbench as well.
you can publish it. I think its very useful for beginners.
I'am sending it to you via email, is there another way ?
Max
Third says:
2011-07-26 at 20:53:25 UTCOh my, that is wonderful! This will really help my own (current and future) designs. I'm truly grateful.
Joel says:
2011-08-05 at 02:54:18 UTCThanks, that's brilliant! I've added it to my page of Digilent Atlys resources. I spent a lot of time getting a GPL gigabit Ethernet MAC core working, but USB would be better and easier for many situations.
Chris says:
2011-08-05 at 09:14:00 UTCGreat, thanks for the link! Would you like to contribute your
platform/atlys/*files?Joel says:
2011-08-08 at 04:57:34 UTCSure, I'll let you know once I've had a chance to get it working :)
MakeStuff » New version of FPGALink says:
2011-09-06 at 09:31:33 UTC[...] FPGALink [...]
Dan Marlow says:
2011-09-06 at 19:42:39 UTCHi Chris,
I am trying to read data from the NEXYS2 as part of a course. FPGAlink looks like just what I need. I am not completely clear on how to integrate it with the rest of my FPGA design. In particular, I had expected a VHDL or Verilog module that I could incorporate into my Xilinx design, but I can't find it on your web site. Sorry if I am missing something obvious as a result of my newbie status.
--DM
Chris says:
2011-09-06 at 21:04:08 UTCHi Dan,
I consider the VHDL reference design to be source code, so it doesn't appear in the binary distribution. On GitHub you can browse the VHDL, or download the entire source tarball. Just unpack it and run "
make PLATFORM=nexys2" in thevhdldirectory. To build the VHDL you'll need Windows or Linux with a Xilinx WebPACK installation. On Windows you'll also need the 3.5MiB MakeStuff build infrastructure.If something is unclear or doesn't work for you, please let me know so I can fix it.
Chris
MakeStuff » Visualising VHDL State Machines says:
2011-09-10 at 18:11:49 UTC[...] FPGALink [...]
UMDKv2 Progressing Again... says:
2011-11-09 at 18:51:52 UTC[...] FPGALink and NeroJTAG provide a platform that finally makes feasible some of the stuff I wanted to do with version two of my USB MegaDrive DevKit. [...]
S.D. says:
2011-12-14 at 15:06:40 UTCThanks a lot! Excellent project.
Your VHDL code is much more cleaner and easier to understand comparing with the code written by Digilent developers (sometimes i have troubles understanding it).
Chris says:
2011-12-14 at 15:35:39 UTCYou're very welcome. Please subscribe to the mailing list to ensure you're notified of updates.
Ray says:
2012-01-25 at 14:07:07 UTCGood Work. I believe your code can be ported easily to support Avnet Virtex5 PCIe Development Platform which I am currently working on. The only different is that this platform uses port pc4 as TDI, pc5 as TDO, pc6 as TMS and pc7 as TCK on the FX2PL chip, as opposed to port d0,d2,d3 and d4 shown in your diagram. How easy is it to change the JTAP signal output pins on the FX2PL, and which file would I need to modify? I am only interested in configuring the FPGA at this stage, not worrying about the FIFO transfer.
Ray says:
2012-01-29 at 02:16:34 UTCI found the file which defines the 4 JTAG pin assignments. Hopefully after re-assigning the pins and recompiling the firmware, it would work with your FPGALink. Fingers crossed.
Ray says:
2012-02-02 at 05:03:15 UTCAfter a few days of work to make the source compiling on Fedora 86_64, we finally have our target programmed through USB, thanks to your FPGAlink. I will show you the modifications.
Chris says:
2012-02-02 at 09:46:29 UTCHi Ray,
Really sorry I haven't been replying, I've been away on vacation. I'm really pleased you got it working.
One thing you can do to eliminate the need for recompiling the entire library is to only recompile the firmware with your changes, and then use
flLoadCustomFirmware()orflFlashCustomFirmware(), which will load your updated firmware from a file.I quite like the idea of a way to configure the JTAG port lines from within the library itself though, thus eliminating the need for a custom firmware; I'll try to do it when I have time.
Meanwhile please join the mailing list and let me know if you run into problems; I promise to be more responsive in future!
Chris
Ardon says:
2012-02-06 at 14:19:24 UTCHi,
Though I have not any kind of hardware of an S3BOARD, an Atlys, a Nexys3 or a Nexys2, I read the TopLevel.vhd file carefully. According to the manual(EZ-USB_TRM.pdf) I think the VHDL reference design cannot work actually, the SLRD and SLWR signal have not assert to increase the FIFO pointer.(...In synchronous mode(IFCONFIG.3=0), the FIFO pointer is incremented on each rising edge of IFCLK while SLRD is asserted, In asynchronous mode(IFCONFIG.3=1), the FIFO pointer is incremented on each asserted-to-deasserted transition of SLRD....) I do not know what I said is correct. thanks
Chris says:
2012-02-06 at 17:21:40 UTCHi Ardon,
I admire your gumption for questioning the operation of my code after reading it but not trying it out. It reminds me of the Donald Knuth quote, "beware of bugs in the above code; I have only proved it correct, not tried it." Too many people assume that just because a bit of code appears to work, it must be correct!
Your interpretation of the TRM is correct. In synchronous mode,
SLOEandSLRDmust be asserted on the rising edge ofIFCLKto advance the read FIFO pointer, andSLWRmust be asserted on the rising edge ofIFCLKto advance the write FIFO pointer.In the VHDL reference design I have grouped
SLWR,SLRDandSLOEtogether into onestd_logic_vectorcalledfifoOp:Refer also to TRM section 9.2.5, where it states, "by default,
SLOEandSLRDare active-low; their polarities can be changed via theFIFOPINPOLARregister," and later on, "by default,SLWRis active-low; its polarity can be changed via theFIFOPINPOLARregister". In my firmware I have setFIFOPINPOLAR = 0x00, which according to TRM section 15.5.8 merely chooses the default polarity: active low.From
TopLevel.vhdland the state chart above, you can see thatfifoOpisFIFO_READon read states,FIFO_WRITEon write states andFIFO_NOPotherwise.I hope this clarifies things. Meanwhile I can assure you the code does actually work!
Chris
Rene Sonderegger says:
2012-02-06 at 20:54:51 UTCHallo Chris,
thanks for sharing your fine work. I was refered to here from here.
I've compiled the example in the c directroy and used "make" to generate the xsvf file as noted in your README files. It works great with my Nexys2 board :-)
I'm new to FPGAs and would like to use the ISE. When using your vhdl and ucf files in a new ISE project, the generated bit file is different from the one when running "make" from the command line.
1. What do I need to do in the ISE to get the same xsvf file as with "make"?
2. Is it possible to use FPGAlink from the ISE to connect with the board? If so, how is that done?
Thank again and kind regards from Colorado,
Rene
Chris says:
2012-02-06 at 23:31:59 UTCHi René,
You're very welcome. If you're using FPGALink, please join the mailing list.
The reason ISE generates a different-size .bit file is because the Makefile is configured to generate a compressed .bit file, whereas by default ISE is not.
-g Compressfromplatform.ut.TopLevel.vhdl, then right-clicking "Generate Programming File" and choosing "Process Properties". Check "Enable BitStream Compression".Enabling or disabling .bit file compression will not affect the functionality or performance of a design, but it will affect the size of the generated .bit file (and the corresponding .xsvf file). Confusingly enough, FPGALink implements its own compression which only comes into play if you use FPGALink standalone mode, in which the the FX2LP microcontroller reads a compressed XSVF stream from its configuration EEPROM and loads it into the FPGA on power-on. Perversely, running FPGALink compression on a Xilinx-compressed .xsvf file generates a bigger file than running FPGALink compression on a non-Xilinx-compressed .xsvf file:
So, in short, if you're using FPGALink standalone mode, it makes sense to disable Xilinx compression, because you end up needing a smaller boot EEPROM, but if you're not using FPGALink standalone mode (i.e there's always a host computer to load the FPGA), it makes sense to enable Xilinx compression. Phew.
With regard to making ISE use FPGALink to program the FPGA as part of the ISE design cycle, I don't see any easy way to do that. I may be wrong, but ISE does not appear to have any hooks to allow you to add a custom build step. You could either run the last two steps (.bit -> .xsvf and .xsvf -> FPGA) from the command-line, or just use ISE as a glorified VHDL editor, and run the entire build process from the command-line.
Chris
Chris says:
2012-03-05 at 22:13:04 UTCComments? Questions? Problems? Click here to join the mailing list!
Hardware Mode: Raspberry Pi Case & Solder Spool Stand. « Ashwith says:
2012-06-24 at 10:58:24 UTC[...] up in the comments of my previous post. Chris McClelland is the author of an application called FPGALink which can talk to various FPGA boards. What’s really interesting is that he has an ARM build [...]
Data Transfer To and Fro Digilent's Nexys-2 board says:
2012-07-23 at 12:05:13 UTC[...] Data Transfer To and Fro Digilent's Nexys-2 board Another option that works with the Nexys2 is FPGALink, which provides a library for programming and communicating with FPGAs at high speed over the [...]