Getting started with FPGA development is much like getting started with any other piece of programmable silicon. First, pick the hardware to use. Next, set up the development environment. Finally, create your first “Hello World” application. In this article, I’ll take you through all three of those steps and, hopefully, get you past the most common MCU-to-FPGA gotchas.

Supporting Information

 

Previous Articles in This Series

A Microcontroller Enthusiast’s First Look at Programmable Logic

 

Choosing a Development Board

While microcontroller development boards can be had for as little as a few dollars, I haven’t seen an FPGA board for less than around $50.00 US. That said, there are still a number of good choices in the $50 to $100 range.

My experience, thus far, has been limited to the Spartan and Zynq family FPGAs from Xilinx. Of the various boards I own, the easiest to use and most flexible are the Papilio boards from Gadget Factory. In this tutorial, I’ll be using the Papilio Pro with a few accessory boards called wings.

My setup, as of this writing, costs $74.99 for the Papilio Pro FPGA board, and $7.99 for the Button/LED wing.

 

Papilio Pro development board

The Papilio Pro with wings.

 

The Spartan 6 chip used on this board has been around since 2009, so it isn’t the newest Xilinx chip. It was introduced as a low-cost, low-power FPGA for high-volume, cost-sensitive applications. Even with its age, it’s a powerful and economical choice as a starter FPGA.

The Papilio uses its own expansion system, with 48 I/O pins brought out. The board uses 3.3V I/O, so you’ll need logic-level converters if you want to communicate with 5V devices.

It has one onboard LED that’s accessible to the chip. Connection to a host PC comes through a USB mini-B connector and an FTDI chip. The FTDI chip means that drivers aren’t an issue with most newer OS versions. Configuration bit files are held in a 64Mbit SPI flash chip. Finally, it has a 64Mbit SDRAM chip on board, for use with more advanced projects than we’ll be seeing for a while.

 

The Development Environment

With your FPGA board in hand, it's time to set up the development environment. The development environment consists of two things: the Papilio loader from Gadget Factory and the ISE development environment from Xilinx.

Xilinx has a couple of different development environments. The one you’ll need for the Spartan 6 chip on the Papilio Pro is called ISE. As of this writing, it’s holding at version 14.7. The Webpack edition is free to download, so that’s what you want.

Find the ISE Design Suite on the Xilinx website / Developer Zone / Hardware Zone / ISE Design Suite / WebPACK Design Software landing page. You may need to create an account with Xilinx, but it's a free download. That's free in terms of money, but not necessarily in terms of time. It’s a pretty big download, with a file size of 6+ GB. You can, however, download it in smaller chunks, which I’d recommend if you don’t have fast or reliable internet.

The Papilio Loader is hosted on the Gadget Factory download forum. As of this writing, the current version is 2.8. The links to both pieces of software are included in the "Supporting Information" section of this article.

With the software environment downloaded and installed, it’s time to see something happen. Our FPGA “Hello World” will blink an LED, as is the convention in the hardware world. That 8-letter word, “hardware”, is very important to keep in mind. We’re writing code that looks like any old microcontroller language, but it’s not software. It’s an HDL (hardware description language) called Verilog.

From a distance, Verilog can easily be mistaken for any one of many programming languages, but what it does is very different. In C or Python, you might reduce an LED blink frequency to a visible rate with a loop that increments a variable and compares it to a set number. In Verilog, we’re going to create a register and use that register as a hardware frequency divider.

 

The Structure of an FPGA Configuration

The source code for our Hello World will end up in two text files: “HelloWorld.v”, the Verilog code, and “HelloWorld.ucf”, the user constraints file (UCF). The Verilog code wires up the internals of the FPGA to create the hardware. Verilog, like most languages, uses labels for I/O connections. The UCF is used to tell Verilog a bit about the specific chip, such as which Verilog labels connect to which chip pins, and various other parameters and constraints. The following table indicates the path that signals take from the inside to the outside.

 

Verilog code The UCF PC board Expansion header
Creates the hardware. Uses labels for I/O Translates between the Verilog I/O labels and the FPGA chip pins Connects the chip pins to the expansion header pins (and on-board LED) Connects to the outside world

 

Look at the following photograph for a pictorial view. The PC board connects the chip pin P112 to the on-board LED, which has the reference designator LED1. The PCB connects chip pin P114 to expansion header C, pin 0. I’ve only called out two pins, but the same scheme follows for every pin used.

 

Connections on the FPGA development board

 

The UCF will allow us to attach labels to these pins. In the UCF we find the following line:

 

                    NET OnBoardLED LOC = "P112"     | IOSTANDARD=LVTTL | DRIVE=8     | SLEW=SLOW;
                  

“OnBoardLED” is the label I chose to represent the on-board component, LED1. “P112” refers to the chip pin, and is a reserved pin identifier for this specific chip.

The pin identifiers are set by the configuration settings in the ISE development environment and match the pins in the chip datasheet. If you take a look at page 31 of the "Spartan 6 Packaging and Pinout" datasheet (the link is in the Supporting Information section, above), you'll find that in the TQG144 package, as is the Spartan 6 on my development board, P112 connects to the I/O designated "IO_L66P_SCP1_0". If my board used the BGA form factor Spartan 6 chip, CPG196 (page 36), the same I/O would connect to the BGA chip at pin "D11", and I'd use "D11" instead of "P112" in this line in the UCF.

The other terms are reserved words that I’ll cover at a later time. Each section of the line is delimited with the vertical bar character "|", and the line is ended with a semicolon.

Switching to the Verilog code, “OnBoardLED” will first show up in the module port declarations section, as shown below:

 

                    module HelloWorld(
      input wire clk_in,
      output wire OnBoardLED
  );
                  

In the code above, "clk_in" and "OnBoardLED" are labels of my choosing. As is the module name "HelloWorld". In contrast, "module", "input", "output", and "wire" are all Verilog reserved words. Each port declaration is separated by a comma, except the last one. The declarations section is in parentheses and ends with a semicolon. Verilog is case-sensitive, so "onboardled" is not equal to "OnBoardLED".

So, in Verilog, I refer to it with the label “OnBoardLED”. The UCF assigns that label to chip pin P112. The printed circuit board wires pin P112 to an LED labeled “LED1”.

 

The "HelloWorld" Project

To see all of this in action, open up the ISE Design Suite. You should have an ISE icon on your desktop. If not, find it in the Windows start menu. The Xilinx start menu entry will have a lot of options. You want “Project Navigator”.

With the Project Navigator open, select “New Project”, which will bring up a dialog as shown in the following image:

 

Creating a new project

 

Fill out the name, as I have. The Location and Working Directory fields will be set up for you. I recommend adding the subfolder “work” at the end of the working directory, as I have done here. It’s not necessary, but it will put all of the intermediate files in that subfolder, leaving your source easier to find in the HelloWorld folder.

After hitting Next, down at the bottom, you’ll see the settings dialog, as shown below:

 

Checking the project settings

 

I've highlighted the most important three settings in yellow. These have to match your chip exactly. Shown are the settings for the Papilio Pro. If you’re using a different board, consult your board documentation, or look at the label on the chip. Your project won't work if any of these are not exact.

The Preferred Language field is also important. If not defaulted to Verilog, change it to Verilog. Hit Next to get to the project summary dialog, and Next one more time, and you'll be at the following screen, ready to add your source files.

 

Empty project screen

 

Adding the Source Code

From the "Project" menu, select "New Source". You'll see a list of file types. Select “Verilog Module”, and enter “HelloWorld” as the file name. Hit Next to get to the Define Module dialog. This is where you enter the labels for the module port declarations, as I covered above.

 

Specify port names

 

Enter “clk_in” as the first port name, with input as its direction. Next, enter “OnBoardLED”, with output as its direction.

If all goes well, you’ll have the following as the nearly empty framework of your Verilog file.

 

                    `timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    20:34:56 04/05/2017 
// Design Name: 
// Module Name:    HelloWorld 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module HelloWorld(
    input clk_in,
    output OnBoardLED
    );


endmodule
                  

You may note that the term "wire" that I included in the code section further up, has been left out of the auto-generated code; "wire" is implied here, so using it is optional. I like to put it there for clarity. It doesn't hurt, and at some point, we'll have other options that will make the extra clarity welcome.

To finish off the Verilog file, add the new code after the ");" at the end of the declarations section, and before the word "endmodule". When complete, your code, from beginning to end, should look like the following:

 

                    `timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    14:34:46 04/01/2017 
// Design Name: 
// Module Name:    HelloWorld 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module HelloWorld(
	input wire clk_in,
	output wire OnBoardLED
   );

	reg  [21:0] freq_div;			// 21 bit register used as the frequency dividing counter
	assign OnBoardLED = freq_div[21];	// Connects the onboard LED to register bit 21
	
	always @(posedge clk_in) begin		// Clocked on the rising clock edge
		freq_div <= freq_div + 1'd1;	// Increment the register by 1
	end
endmodule

                  

Adding the UCF

One more file to add, and we'll be ready to give it a try and see what shakes out.

Again, go to the Project menu and select New Source. This time, you'll have a few extra options. Select "Implementation Constraints File" and give it the name "HelloWorld". Hit Next, and Finish, and you'll have an empty code window labeled HelloWorld.ucf. Copy and paste the following code into the code window. There are only two lines (and an optional comment) in this one.

Note that the pound sign "#" indicates a comment in the UCF. You can start a comment anywhere in the line. In Verilog, comments are indicated by a double slash "//" or a paired set of "/*" and "*/", as in the C language.

 

                    # UCF for our first FPGA "Hello World"
NET clk_in   	LOC = "P94" | IOSTANDARD=LVTTL | PERIOD=31.25ns;      # System clock setting
NET OnBoardLED LOC="P112"   | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=SLOW; # on board LED	

                  

Save the project and you're ready to take some action. Your ISE Project Navigator screen should look like the following:

 

Project navigator, ready to go

 

Creating the .bit File

The system has a lot to do to create the .bit file (also called the configuration or programming file), but you just need to give it one command: double-click on the line "Generate Programming File". This is the rough equivalent of compiling and linking in the microcontroller world. If all goes well, in a few minutes you'll have green check marks next to the lines "Synthesize - XST", "Implement Design", and "Generate Programming File" as shown in the image below.

 

Three green checkmarks

 

If you've got the three green check marks, you're ready to open up the Papilio Loader and put the configuration into your FPGA. The Loader is installed in your Windows start menu, under "Gadget Factory". Bring it up, and hit the Select button. Navigate to your .bit file. If you added "work" to the working directory, as I did, that's where you'll find the .bit file.

Make sure your Papilio is connected to your USB port and hit Run. When the Papilio loader reports back as Done, in its "Information" window, you should see the LED on your Papilio blinking.

 

Conclusion

If you're coming from the Arduino world, this may seem like a lot of steps to go through just to blink an LED. If you're coming from the world of the Eclipse IDE and an ARM processor, this is probably fewer steps than you went through to get that up and running. In any case, the capabilities lurking within the FPGA will make it very much worth the effort.

In subsequent articles in this series, I'll get into the detail of what these Verilog statements do, more about how an FPGA really differs from a microcontroller, and onto more complex circuit design.

 

Comments

2 Comments


  • bill S 2017-05-22

    It’s NOT :
    freq_div <= freq_div + 1’d1;

    It IS:
    freq_div <= freq_div + 1’b1;

  • Duane Benson 2017-05-23

    Both representations are correct, though 1’b1 is a more logical representation.

    For those not familiar, the first number,1 equals the number of bits used to hold the number. The ‘d or ‘b (the radix) represents the base (d, for decimal, b for binary, h for hex, o for octal. It’s not case sensitive). The final number, 1, in this case is the actual number.

    If no radix is specified, the number is assumed to be a 32 bit decimal. In my case, since the number I’m adding is 1, which takes up one bit, everything works. If the number takes up more bits, the most significant bits (MSB) are dropped off. So 1’d1 is legal and equivalent to 1’b1, but 1’d2 is not what it looks like. The format still only allocates one bit. The MSB is trimmed, so 1’d2 actually equals 0. 1’d3 equals 1. 2’d2 has enough bits, and is therefore, equal to decimal 2.

    In short, while what I used, 1’d1, is legal syntax, Bill’s recommendation of 1’b1 is probably safer and less likely to induce an error if the code is modified later. Just keep in mind, that 1’b10 would still only allocate one bit, would trim the leading digit, and is therefore equal to 0.