I have tried several times to learn how to build logic circuits with FPGAs (field programmable gate arrays). I have finally had some modest success, and in this tutorial, I will try to explain how I finally got started and began working with FPGAs.
Why do I want to learn to use FPGAs? Building any digital logic circuits from ICs, soldering them together on breadboards, etc., can be very time consuming and tedious. If you are experimenting, making changes can be even more tedious. In contrast, FPGAs allow you to easily create very complex logic circuitry with relative ease, and making changes just requires tweaking code. However, you first need to learn several new systems and concepts in order to get there.
There are some barriers to learning how to program FPGAs, especially if you are a hobbyist microcontroller programmer like me. HDLs (Hardware description languages like Verilog) are used to design and implement circuits in FPGAs. They are sort of like software, but hard to get your head around, because software is sequential. When we write software, we are writing a sequence of steps our processor will follow. We are so used to thinking sequentially that using something similar to describe hardware feels strange and unfamiliar.
FPGAs (gate arrays) makes it sound like we are building logic out of NAND gates, and, in fact, you could actually do that and build anything with nothing but NAND gates. But ASIC technology (which FPGA's are part of) has been around for about 40 years now, and the software tools and HDLs have become so sophisticated that you only have to describe what you want the hardware to do, and the software designs the circuit for you. For example, I can write: dff mycounter[32]; The dff refers to a d-type flip flop. I am creating an instance of it named mycounter. But the 32 tells the software I want 32 flip flops configured as a register. Not only that, but mycounter.d loads a 32 bit number into that register, and mycounter.q is the 32 bit content of that register. We can increment our register by saying: mycounter.d = mycounter.q + 1. A d-type flip flop requires 5 gates, so this one small statement generates a register made up of 160 gates. So these HDLs are very high level, powerful languages, but it also takes some time to learn how to use them!
There are many books and many boards that attempt to be an entry point into FPGAs. Most are based on Xilinx chips made by AMD Semiconductor. Programming them requires using AMD's proprietary software tool called Vivado. Vivado is a very powerful IDE designed for professional hardware/logic designers. It is a little intimidating to start with, but, even worse, Vivado is constantly making changes to their user interface, so all books and tutorials on using it are out of date or don't match the version you are using.
On top of all this, you are trying to design logic, learn a new operating system (Vivado) and learn a new HDL language like Verilog. I was very frustrated by my early attempts to do all this using Vivado.
I finally came across an introductory board and associated development software made by Alchitry. The Alchitry Au board is manufactured and distributed by SparkFun. Alchitry has a app called Alchitry Labs that allows you to build FPGA projects and deploy them on the Alchitry Au board. It uses Vivado to program the FPGA chip, but uses it like an API. So I just have to deal with Alchitry Labs, and it takes care of interfacing with Vivado. And it doesn't particularly care which version of Vivado you choose to install.
Alchitry Labs supports two HDLs - Verilog and Lucid. Verilog is one of the original and most popular HDLs. Lucid is much less popular, but is a little simpler and easier to learn for beginners and hobbyists. Alchitry Labs basically takes Lucid inputs and converts them to Verilog which in turn is fed to Vivado.
I chose to learn Lucid. Alchitry has several good tutorials to help you get started. And I found a great resource - Getting Started with FPGA, written by Natalie Agus at Singapore University of Technology and Design. There is also a language reference that is very helpful. Between these resources I was able to learn enough basics of both Lucid and FPGA circuit design to start constructing projects on my own. I will talk about what I have accomplished at the end of this tutorial and show you them in future tutorials/projects.
Getting Set UpAs I said, the hardware is the Alchitry Au board. I actually bought the Alchitry Au FPGA Kit, which includes the Au FPGA board, the IO Element board, and the Br Prototype board. The AU board has 8 LEDs, but not much else in the way of I/O. The IO board, however, has 24 more LEDs, and a four digit 7 segment display, along with 24 dip switches and 5 push buttons. The prototype board gives you access to about 50 3.3 volt general purpose I/O pins.
Note: Don't attach the headers that come with the prototype board, at least not yet. They make it difficult, if not impossible, to use both the io board and the prototype board at the same time - something that I actual do later on in this series of tutorials.
The software is all compatible with Windows, Mac and Linux, although my experience is all with Windows. Details of the setup are available here, but the short version is you need to install Alchitry Labs (I'm using V1.27), and Alchitry Labs requires that Java Development Kit be installed. It also requires an installation of Vivado. I chose a version of Vivado from 2019 concerned that the Alchitry documentation was about 4 years old and might not know about recent changes. I don't know that was necessary, however.
I found that Alchitry Labs linked up to Java and Vivado without my having to do anything. There is a provision for telling Labs where to find Vivado, but it found it by itself. I found Labs to be very straight forward and intuitive. It checks all your syntax, and it doesn't even start Vivado until everything looks right. Vivado takes about a minute to process your code and build the circuit, but always comes back with a project file ready to download to the FPGA.
Building a Project with Alchitry LabsCreating projects for FPGAs is not quite as straight forward as writing a program for an Arduino. A typical project involves a number of files. Alchitry Labs takes care of most of them for you, but you still need to understand what's there. Project files are divided into three categories:
- Source files - As much as possible, hardware is broken into modules, each of which performs a specific function and has its own file. This helps make modules re-usable, similar to the idea of object based code. The Top module is where all the pieces come together and link to the outside resources, like switches, LEDs, and other external hardware. So any design usually has several source files
- Components - These are modules in a library that are available for your use. They create standard hardware pieces which you may need for your project. Examples would be a RAM module, a Servo control module, or a PWM module.
- Constraints - these files tell the system about the hardware you are using. For example, there is a file for the Au board itself, and another one for the IO board.
This tutorial is intended to be just an introduction. Anything worth publishing that I create for FPGAs will come in future postings. But I will publish one simple example here, that might help you get started. It blinks all 24 LEDs on the IO board, one after another.
Assuming you have completed the setup and have Labs working (again, I am using version 1.27), open a new project. It will be for the Alchitry Au, using Lucid, and in the From Example choose IO Board Base. Create a new project - I called mine "led_flash".
Now create a new file (from the File menu), make it a Lucid source file, and name it blinker. (File names and module names should match) Paste the code presented below into this file and save. You have now created a blinker hardware module.
We still need to link our blinker module to the real hardware on the IO board. So open the au_top file. This file was already created by Labs and knows about the IO board and its hardware. We need to add two things to the au_top flie:
1. Just below" reset_conditioner reset_cond;" and still within the .clk brackets, insert:
blinker myBlinker(.rst(rst)); // an instance of blinker called myBlinker
2. Just below "io_sel = 4hf; // select no digits" and still within the always brackets, insert:
io_led[myBlinker.bank][myBlinker.ledNum] = myBlinker.out; // blink LEDs
The first item creates an instance of the blinker module hardware. The second item connects the LEDs on the IO board to the outputs of the blinker module.
How Blinker WorksThe Au board has a 100 MHz clock. The blinker module has two counters. The first counts up to 10M, taking 0.1 sec, toggles the led flip flop, and resets. The second counter, which is clocked by the led flip flop, counts up to 24 for our 24 IO board LEDs. The IO board defines its LEDs as 3 banks of 8 LEDs, so the output of the second counter is split into bank and led number. The output of the led flip flop is the output that actually flashes the selected led.
What Comes Next?I worked through a number of the examples from the tutorials mentioned above. These were things like lighting an LED by pushing a button, or inputting two numbers through the dip switches, adding them together and displaying the binary result on the LEDs. At first, all I could do was set up the examples, show that they worked, and try to understand how they work. But after a few hours of working through examples, I was able to start creating simple projects on my own.
I have been able to get the seven segment display working, inputting a number in binary with the dip switches, and display it in decimal on the 7 segment display. I also succeeded in interfacing a 16 pin keypad through the prototype board, and then use it to input decimal numbers onto the 7 segment display.
I will publish all the code for my projects in a future tutorial. Doing this stuff in logic circuits is very different than programming it on a microcontroller. I haven't done anything with FPGAs yet that I couldn't have done on an Arduino in 1/10th the time, but it still feels great to be doing this stuff with logic circuits and hardware instead of computer code.
I am happy with the Lucid language so far and think it helped me get started with FPGAs. And it is deliberately similar to C+ in its syntax, which helps. However, Lucid has very limited usage. If I continue with many more FPGA projects, I will need to switch to one of the more popular HDLs - Verilog or VHDL
Comments
Please log in or sign up to comment.