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".

libfpgalink-20120621.tar.gz (Linux, MacOSX & Win32)
Browse API docs
User Manual PDF (VHDL Paper Edition)
User Manual PDF (VHDL eReader Edition)
User Manual PDF (Verilog Paper Edition)
User Manual PDF (Verilog eReader Edition)
Support Mailing List
Browse source repository
RSS feed of recent commits
Open issues

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:

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

Hi 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!

The 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 .bit file programming algorithms. It might be worth asking Zoltán for some guidance on implementing Spartan-6 support.

Of course, the alternative is to not use xilprg at all, but to use Xilinx impact to generate an XSVF file from your Spartan-6 .bit file, 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.

Many thanks for the advice, I will try csvfplay soon and let you know how I get on.

Hi 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

Hello 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:

  • The pre-built firmware and code to load it into the FX2 chip
  • The code to program the FPGA from an XSVF file ("NeroJTAG")
  • The code to communicate with the FPGA, once programmed ("CommFPGA")

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:

  • Query the FPGA first to see how much data it has available, then request exactly that much data from it.
  • Switch the host side to use asynchronous APIs where you get a callback when data is available.

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.

Hi 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

Hi 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.)

Hello 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() or flReadRegister() 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.

Hi 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

Oh my, that is wonderful! This will really help my own (current and future) designs. I'm truly grateful.

Thanks, 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.

Great, thanks for the link! Would you like to contribute your platform/atlys/* files?

Sure, I'll let you know once I've had a chance to get it working :)

Hi 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

Hi 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 the vhdl directory. 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

[...] 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. [...]

Thanks 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).

You're very welcome. Please subscribe to the mailing list to ensure you're notified of updates.

Good 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.

I 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.

After 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.

Hi 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() or flFlashCustomFirmware(), 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

Hi,
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

Hi 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, SLOE and SLRD must be asserted on the rising edge of IFCLK to advance the read FIFO pointer, and SLWR must be asserted on the rising edge of IFCLK to advance the write FIFO pointer.

In the VHDL reference design I have grouped SLWR, SLRD and SLOE together into one std_logic_vector called fifoOp:

signal fifoOp       : std_logic_vector(2 downto 0);
constant FIFO_READ  : std_logic_vector(2 downto 0) := "100"; -- assert slrd_out & sloe_out
constant FIFO_WRITE : std_logic_vector(2 downto 0) := "011"; -- assert slwr_out
constant FIFO_NOP   : std_logic_vector(2 downto 0) := "111"; -- assert nothing

  :

-- Breakout fifoOp
sloe_out <= fifoOp(0);
slrd_out <= fifoOp(1);
slwr_out <= fifoOp(2);

Refer also to TRM section 9.2.5, where it states, "by default, SLOE and SLRD are active-low; their polarities can be changed via the FIFOPINPOLAR register," and later on, "by default, SLWR is active-low; its polarity can be changed via the FIFOPINPOLAR register". In my firmware I have set FIFOPINPOLAR = 0x00, which according to TRM section 15.5.8 merely chooses the default polarity: active low.

From TopLevel.vhdl and the state chart above, you can see that fifoOp is FIFO_READ on read states, FIFO_WRITE on write states and FIFO_NOP otherwise.

I hope this clarifies things. Meanwhile I can assure you the code does actually work!

Chris

Hallo 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

Hi 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.

  • You can tell the Makefile build not to generate a compressed .bit file by removing -g Compress from platform.ut.
  • You can tell ISE to generate a compressed .bit file by selecting 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:

Xilinx Compression? XSVF Size Size After FPGALink Compression
Yes 185,426 bytes 27,065 bytes
No 484,126 bytes 11,618 bytes

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

[...] 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 Another option that works with the Nexys2 is FPGALink, which provides a library for programming and communicating with FPGAs at high speed over the [...]

| Home | About |

Powered by WordPress & MakeStuff theme, with Silk icons