If you’re like me, you’ve heard a lot about FPGAs and how useful they can be in a design. Perhaps you’ve read a bit about them, learning what they are and a bit about how they work. If your background (like mine) is in microcontroller-based design, though, getting started in working with FPGAs is not necessarily intuitive. Here are some of my thoughts and experiences as I begin working with FPGA-centric design.
Although FPGAs can often be a viable alternative to a microcontroller or microprocessor in a given embedded project, they are radically different devices. Microcontrollers are CPUs with various built-in peripherals and onboard memory, whereas FPGAs are collections of various logic units that are configured to perform certain (often very complex) functions. Programming a microcontroller involves writing a program to tell it how to behave. Programming (really, configuring) an FPGA involves creating a configuration file (a “bitstream”) that sets up the configuration of the FPGA to do the intended tasks.
In short, you tell a microcontroller what to do; you tell an FPGA what to be.
The traditional “Hello, World!” project for embedded systems is typically a blinking LED. Even as simple a project as this illustrates the difference in approach when using an FPGA as opposed to a microcontroller. When writing a “blinker” program for a microcontroller, the code would generally look something like this (using PIC-like C code):
TRISB = 0xFE;
PORTB = 0x01;
PORTB = 0x00;
This code would blink an LED connected to PORTB.0 on and off at a rate of 1Hz. The microcontroller would follow each command in sequence and change the LED state appropriately.
Conversely, when implementing a blinking-LED project with an FPGA, the general approach is to implement a digital circuit (using virtual gates, flip-flops, registers, counters, multiplexers, etc) to perform the same function. One strategy is to decide how you would implement the circuit using discrete (74xx, for example) digital logic, and then implement this design in either schematic form or your HDL design language of choice. (VHDL and Verilog are the two dominant languages; the following example is in VHDL):
entity blinker is
Port (clk : in STD_LOGIC;
led : out STD_LOGIC);
architecture Behavioral of blinker is
signal count : std_logic_vector(23 downto 0);
process (clk) is
if rising_edge(clk) then
count <= count + 1;
led <= count(23);
This code describes a 24-bit counter which increments on each rising edge of the input clock. The LED is tied to the 24th bit of the counter; this divides the clock by 224 (about 16.7 million). The end result is that the LED blinks once every 224 clock cycles. With a 16MHz input clock, the LED should blink at a rate of not quite once per second.
This is a very simple example, taking up less than 1% of the resources of even small FPGA devices like the Xilinx Spartan3 series. By combining “entity” descriptions like these, though, larger, more complex designs can be implemented. As with C-style programming for CPUs, modularity makes development of larger and more complex designs possible. A top-down approach can be taken, for example, describing the inputs and outputs of the system as a whole, then breaking the internal function down into subsystems, circuits, and finally gates (Boolean expressions, etc.)
Although working with FPGAs can be unintuitive for designers used to working with procedurally-oriented devices like MCUs, there are many benefits. FPGAs can be much faster at certain tasks, since the device configuration can be optimized for specific operations. Efficient pipelines can be set up, for instance, to keep streams of data flowing. Most significantly, FPGAs are inherently massively parallel: rather than relying on a single CPU core processing a sequence of instructions one after the other, FPGAs are essentially a “sea of [logic] gates” that can work together or independently. Extending the above example, for instance, several dozen LEDs could be configured to each blink at a different rate, by duplicating the blinker design at various places in the FPGA, and modifying the count for each.
The largest drawbacks to working with FPGAs I’ve found, so far, is that they tend to be more expensive (tens of dollars for an entry-level FPGA like the Spartan3, as opposed to under $5 for a typical 8-bit MCU; really big FPGAs can be stupendously expensive), and more importantly are trickier to implement into a typical DIY project, since they tend to be available in QFN and similar packaging instead of the more hobbyist-friendly DIP format. Fortunately, modern dev boards like Digilent’s BASYS2 and Gadget Factory’s Papilio make prototyping easier.
Here are a few books that I’ve found to be useful. I’m starting out with an emphasis on VHDL and Xilinx Spartan3 parts, so the books I’m using tend to have those biases:
This is the primary book I’ve been using while getting started in FPGA projects in general and VHDL in particular. It is a step-by-step explanation of the important concepts in writing VHDL code, with a particular emphasis on Spartan3 FPGAs. Since both of the dev boards I use (Gadget Factory’s Papilio and Digilent’s BASYS2) use Spartan3 chips, this book has pretty much been a one-stop shop, thus far. If I were creating an undergraduate-level course in FPGA-based design, I would use this as the textbook, with the other two as recommended supplemental texts.
Part textbook and part “HDL cookbook” containing all kinds of HDL designs in both VHDL and Verilog. It doesn’t strike me as the best book for starting out, but looks very useful as both a reference and a good way to learn more advanced techniques. I picked up a copy on Jeri Ellsworth’s recommendation. It’s not cheap (and can be hard to find), but looks to be well worth the money.
This is a good introduction and overview of the concepts and syntax of VHDL. It is a bit more theoretical than the other two books, but does a good job of covering the language, and can be used as a language textbook and/or a VHDL desk reference.
I am working on a few FPGA-based projects, which I will post here when complete. My eventual goal is to develop standalone FPGA-based devices.