Terasic DE0 Board


The DE0 Development and Education board is designed in a compact size with all the essential tools for novice users to gain knowledge in areas of digital logic, computer organization and FPGAs. It is equipped with Altera Cyclone III 3C16 FPGA device, which offers 15,408 LEs(Logic Elements, which are basic units used to build up more advanced behaviors). The board provides 346 user I/O pins(An Arduino usually has about 20), and is loaded with a rich set of features that makes it suitable to be used for advanced university and college courses, as well as the development of sophisticated digital systems. The DE0 combines the Altera low-power, low-cost, and high performance Cyclone III FPGA to control the various features of the DE0 Board. The DE0 Development Board includes software, reference designs, and accessories required to ensure the user simple access in evaluating their DE0 Board.

What can I do with an FPGA?

Quite a number of things, but a good sampling of what an undergraduate can achieve in a month or two on and off can be found on Cornell's ECE 576 project page, below.

https://people.ece.cornell.edu/land/courses/ece5760/FinalProjects/

Some places they may be relevant to physics is in speeding up massively parallel operations, such as simulations of fluid dynamics. https://vanhunteradams.com/DE1/Lattice_Boltzmann/Lattice_Boltzmann.html A rather standard Cyclone V chip can achieve an order of magnitude speedup compared to C code running on a Mac M1, or over three orders of magnitude faster than a Python-based simulation, despite running at a slower clock speed!

Getting Started


First steps

Once booted, plug the DE0 into the computer using the USB cable. The 7 segment readouts should begin counting from 0 to F and the LEDs should scan back and forth. If this doesn’t happen, make sure the Run/Program switch is set to Run and the red push-button switch is ON. Now start up the Quartus II software and start a new project using: FILE→ New Project Wizard

The New Project Wizard dialog will open, like so:

You can click on any of the screenshots to get a larger view

Click Next and pick directory and name for your project. It is a good idea to use a new subdirectory so that your files don’t mingle with the files of other projects.

Click Next here (creating the directory if needed), and again at the “Add Files” page.

You should now be at the Family and Device Setting dialog (page 3/5).

Once here, be sure that the Family field shows “Cyclone III”.

Select the Device named EP3C16F484C6 (this is the FPGA type installed on the DE0). You can copy and paste the name into the search box, but beware of leading or trailing spaces.

Now click Finish to complete the Project Wizard.  Your screen should now look something like this:

Hello World


Blinking an LED

Now you are going to do the hardware equivalent of a “Hello World” program – you are going to make an LED turn on. We’ll learn about how to use the Quartus II software as we go. Select File→New. Under Design Files, select Block Diagram/Schematic File and then hit OK.

You should now be in schematic entry mode, which allows you to draw devices on the screen to build up your circuits.

  • You can add circuit elements by clicking on the Symbol Tool, indicated by the gate icon.
  • You can add input or output ports by clicking on the Pin Tool, next to the symbol tool.
  • We connect circuit elements together by using the Node Tools, of which there are two:
    • The first tool (Orthogonal Node Tool) is for right-angles connections
    • The other (Diagonal Node Tool) is for direct, point-to-point connections. It will be less work to use the right angle connector, so consider using that most often.

Now - click on the Pin Tool and select an OUTPUT. A little ghostly output pin will appear next to your cursor. Drag it to the middle of the screen and left-click to drop it.

Next, click on the Symbol tool. This will bring up a dialog like so. Navigate down to Primitives | Other and select the VCC element. You can also just type the exact name into the search box.

Drag the $V_{CC}$ element over to your schematic and place it to the left of your output pin. Now select the Orthogonal Node tool and connect the $V_{CC}$ point to the output pin. Your schematic should look something like this:

At this point save your schematic file by hitting control-S. Pick a filename and click “Save”.

Now we will synthesize our schematic using the Start Analysis and Synthesis icon:

This tool does a preliminary analysis of the schematic and attempts to convert it into logic-gate level form for the final compilation. It should take a short time to run and will probably give you a few warnings. This is ok.

If you successfully synthesized, you will have a logical output pin that is defined, but not associated with any of the physical pins on the FPGA. To complete the design, you need to connect your logical pin to a physical pin using the Pin Planner Tool (under menu item Assignments, or via Control-Shift-N).  Click on the Pin Planner. A dialog will open which looks like this, showing all the 484 pins on the FPGA.

To assign your pin properly, look at the bottom half of this dialog and click in the Location field in the row corresponding to your pin (in this case pin_name1), and type in the number J1.

A list of pin numbers is included in the DE0 manual and also on the following wiki page. In the present case, the pin PIN_J1 corresponds to the 1st green LED (LED Green[0]) on the right of DE0 board. Now exit the Pin Planner (hit X button, upper right).

Always be sure to synthesize your design before trying to assign pins, as the synthesis process identifies open pins and places them in this dialog for you to assign.

Looking back at the schematic – there should now be a pin assignment tagged next to the output pin, like so:

There's one more step needed before compiling: We need to let Quartus know what file it's supposed to work with. To do this, go to the menu on the left, select the files tab, right-click on your file and click set as top-level entity

We are now ready to compile! Select the Compile button and wait with bated breath…

The compilation process can take a minute or more, depending on how complicated your design is. You will likely get 10-20 warnings during the compilation. This is ok.

If the compilation was successful, you now have a fully-defined design and you need to burn it into the FPGA. This is done using the Programmer function . Sadly, this does not produce bacon like the icon indicates.

Running the Programmer will bring up a dialog like so:

If USB-Blaster does not show up next to the Hardware Setup button, click that button and select it from the Currently Selected Hardware drop-down. If USB-Blaster is not an option, then your USB driver is not installed properly, and you may need to get help from the TA.

If no file is automatically selected, click the Add File… button, go to the output_files folder, and select the .sof file with your project name.

If all is well, then click the Start button and the FPGA will be programmed. If the progress bar doesn’t show 100% (Successful) within a few seconds, be sure that your device is in RUN mode (The switch on the bottom left should be toggled up). If all else fails, ask your TA.

After the device is programmed, you should notice that the counting and flashing on the DE0 have stopped and that the right-most green LED is lit. Congratulations! You just made your “Hello World” program and learned how to use an FPGA.

Adding Input


Using a switch

That was a little too easy, so now let’s add some user input. Go to File→Save As and save your schematic under another name. We are going to add a few components.

After doing this, go to the files tab under the Project navigator on the left-hand side of the screen, right-click the new schematic, and select Set as Top-Level Entity . Otherwise, when you go to compile things, Quartus may be stuck on the other file.

First - add another pin. This time an INPUT pin. Position it to the left of the output pin.

Next, delete the $V_{CC}$ pin and the connecting wires. To do this, click on them to make the blue selection indicators appear. Then hit the delete key.

Now, using the Symbol Tool, add a NOT gate (it is under Primitives |Logic) and connect one end to the input and one end to the output. Hit control-S to save. Now, synthesize and assign pins. You want to associate your INPUT pin to an input on the DE0 board. We will use PIN_F1, which is push-button 2 (the left-most one).

Your schematic should now look something like this:

Now save (Control-S) and Compile and Program.

The right-most green LED should now be dark, until you push button 2, when it will light up (you may have to push it hard on some of the DE0s). Congratulations! You have now performed IO with your FPGA.

The reason that we had to put the inverter in there is that the default output signal associated with the three pushbutton inputs is HI (3.3V). By pressing the button, you are actually asserting a LO state. Remember this for later when you are assigning logic to the IO pins.

Time to get Serious


Logic via programming

Last week you built a 4-bit up/down counter circuit. Now, we'll see how we can make arbitrarily large counters using Quartus.

Let’s start a new project for this circuit. Follow the instructions from the Getting Started section. Make a schematic file and then select the lpm_counter module (Symbol Tool |megafunctions |arithmetic |lpm_counter).

“LPM” stands for “Library of Parameterized Modules,” which basically means you can create a custom device (a counter in this case) with various properties you set. This can be much simpler than building what you need from scratch!

Click Next on the first dialog window to get to page 3 of 7 of the plugin manager wizard.

To start, we'll select a 4-bit counter that only counts up. To do this, change q to 4, press Finish, and then press Finish on the next screen. You should be left holding a counter, which will look like the following when placed in the block diagram:

You'll want to add an input pin and connect it to the clock input of the counter. Now, there's something new we have to deal with for the output.

The output of this counter is actually 4 separate bits. However, Quartus defaults to bundling multiple bits together in a bus connection. We'll need to assign a name to the bus, and then names to the individual bits we want to assign to be used later.

Use the orthogonal bus tool (or click and drag from the thick purple line attached to q[3..0]) to extend the connection out to the right some. Then click on the bus wire you just drew and start typing to name it. For now, use the name counter[3..0] to let Quartus know that the entire bus is named counter and that it contains 4 bits. Your schematic should look something like the following:

Now, to use those individual bits. Use the orthogonal node tool to create a new wire that starts on the bus and ends off to the right. Then click on your new wire and name it counter[0]. This splits off the lowest bit of the counter to be used by you elsewhere. It should look like the following:

Repeat the process 3 more times, changing the numbers to 1,2, and 3.

With your bits separated out, attach each one to an output pin. You may want to rename the output pins to remind you of what they're for.

Run the Analysis & Synthesis on your design, and then go to the pin planner tool. You'll want to assign the input to pin F1 again, and the outputs of the four counter bits to the four left-most LEDs. Those belong to pins B1, B2, C2, and C1 respectively.

Compile your project, and use the programmer to write it to your FPGA. The result should be a that you have a 4-bit binary counter indicated by 4 LEDs that increments when you press button 2. Remember how much wiring it took to accomplish something similar in hardware last week? This is just the start.

More output options


7-segment displays

I don't know about you, but I don't read binary numbers very naturally. Fortunately, the DE0 also has four 7-segment displays which can be used to show hexadecimal numbers. The connections on the rightmost 7-seg display are shown here:

With the appropriate conversion logic, we can use one of these to display the output of our counter. However, the process of converting binary numbers to a base 10 digit is not trivial. Here is what the gatelevel logic looks like:

(Placeholder: img)

Fortunately, there are ICs built to do the hard work for us and several of these ICs are modeled already in the Quartus software. This is one of the fabulous benefits of designing with FPGAs – the entire phase space of available logical devices is there for you to use with just a few clicks.

Go to the Symbol Tool and use the search field to locate a 7447 chip (Others |maxplus2 |7447):

Insert this into your schematic, and assign the seven OA..OG outputs to seven individual output pins. To enable the converter for your circuit, you will also need to tie the LTN and RBIN pins to $V_{CC}$ (Primitives |Other |VCC), as shown. Now hook up the 7447 inputs to your counter outputs. Your schematic should look something like this:

Why did we pull those pins high?

RBIN stands for “Reverse Blanking Input”. When low, it's used to let these modules communicate with one another to turn off segments that have leading zeros on them. We could use it if we wanted to get fancy here.

LTN stands for “Lantern”. When low, it turns on all of the lights in the display at once, suitable for testing if something's broken or not. Not very useful when counting though.

Analyze the design, and then assign the 7 output pins to the following FPGA pins, in order:

  • E11
  • F11
  • H12
  • H13
  • G12
  • F12
  • F13
Compile it and test it. How does it work? Why does it fail for counts greater than 9?

Parsing binary numbers

To make sure that we're only inputting an acceptable value to the counter, we can use a division module, lpm_divide (Megafunctions |Arithmetic | lpm_divide). Click through until you get to the plugin manager screen.

Change the numerator and denominator bits to 4 and 4, as shown above, and then click Finish. Your screen should look something like the following:

Now we need to tell the division module that we're dividing by 10. To do this, we'll need to generate a binary 10 using the lpm_constant (Megafunctions |Gates | lpm_constant) tool. Configure your constant to be 4 bits wide with a value of 10, as shown below:

We're nearly there! Now for the following:

  • Connect the counter output to the numerator input of the division function
  • Connect the constant to the denominator input of the division function
  • Connect a bus to the remainder output and give it a name
    • Don't forget to end the name with [3..0] to denote 4 bits
  • Remove the old connections to the 7447 chip
  • Break out the four bus bits as the the new four inputs for the 7447 chip

The result should look something like this. Test it.

Sure, it goes from 0 to 9 and then 0 to 5 before repeating, but it is giving us the 'ones' digit of our number successfully. We could take the numerator bits and connect them to another 7-segment display to get the tens digit of our counter, and we will in fact be doing that later.

Using the Rotary Encoder


Talking to the outside world

Last week, we introduced a rotary encoder as a sort of digital analog to a potentiometer. However, you may have noticed that it did not cleanly transition between states, there could be quite a bit of noise in the transition.

Instead of rebuilding the circuit, we've created a breakout module that will plug directly into the FPGA board, shown below:

A breakout board connected to one of the 40-pin sockets of the FPGA. The boxes denote connections to the FPGA pins or power. The cables (on the far right) have sockets on the end that connect to the pins on your rotary encoder.

With that done, we can now access the two rotary encoder values as pins V7 and AB9. Let's try this by going back to our FPGA program and re-configuring the button from pin F1 to V7. After that, compile and test your program.

What do you observe?

You probably noticed the output sporadically changing by more than one increment at a time. To address the issue, we'll build something called a debouncer. This sort of signal processing is often needed when working with mechanical inputs, as the contacts can literally vibrate between open and closed as they move. This in turn causes a quick burst of noise, that would be invisible in most analog circuits but wreaks havoc with digital devices.

Our debouncer will consist of 6 basic elements:

  1. A pair of flip-flops and a XOR gate will detect any change in state
  2. Changes in state will start a counter
  3. When the counter reaches its maximum, it will send a signal to another flip-flop to update the button state that we see on the digital side
  4. A NOT gate will make it so that we can feed a signal back from the maximum output of the counter to disable it until the input changes again.

In order to keep things clean, we'll make a sub-circuit here by creating a new block diagram file in our project. Create a new block diagram file in your project. Start out by adding a pair of inputs and one output, named input, clock and output respectively.

Save your file as debounce.bdf. Make sure you navigate to the main directory of your project; it defaults to the output_files subdirectory. Failure to do this will make it so that Quartus won't properly recognize that the block is part of your project

To start off, add in a pair of D Flip-Flops (dff) and a XOR gate (xor). Connect them together to make a change detection circuit, which will cause an output on the XOR for one clock cycle every time the input changes.

Next, we'll create a new counter with some features we haven't used yet. Go to the symbol tool and add a lpm_counter module. On the first screen, change the name to something else such as DebounceCounter

If you don't do this, you may get some very strange errors later due to Quartus finding multiple counters with the same name.

Next, click through to the configuration screen. We'll want to change the following settings:

  • Screen 1
    • set q to 12 16 bits
  • Screen 2
    • Select the Count enable and Carry-out checkboxes
  • Screen 3
    • Under the Asynchronous inputs section check the clear checkbox

Once your counter is finished, it should look something like the following:

Now, place another dff in your circuit off to the side, and make the following connections:

  • Connect the clock pin to the clock input of the counter
  • Connect the cout counter output to a not gate
    • Connect that to the cnt_en input on the counter
  • Connect the XOR output to the aclr input of the counter
  • Connect the Q output on your second original flip-flop to the D input of the new flip-flop
  • Connect the cout output on the counter to the clock > pin of the new flip-flop
  • Connect the output of the new flip-flop to the output pin you created earlier

After all of this, you should have something like the following:

Now, why did we do all of this? Well, the CountEnable (cnt_en) pin only lets the counter tick upwards when it is held high. The cout pin on the counter stands for CarryOUT, which goes high after the counter reaches its maximum value. Thus, connecting these makes the counter stop after it goes counts to $2^{16}-1 = 65535$. Since each clock cycle takes 20ns, this makes it so that our circuit takes ~1.3ms of the output being steady before it changes state.

If we were to use 12 bits, this would instead be around 80 $\mu$s, which is too quick for some of these encoders to stop being noisy. If you have a particularly angry encoder, you might need to increase the counter to 17,18, or even 19 bits. Each additional bit doubles the time that the output has to be stable for it to change in the FPGA.

The asynchronous clear aclr will reset the counter to zero. By connecting it to the XOR gate, we'll reset the counter any time the button's state changes.

The last flip-flip will only change state to match the button after the timer has reached its maximum value because the only time its clock is enabled is when cout is high.

All of this ensures that the output the code sees will only change after the input has settled down over a little bit of time.


Now to actually use our sub-circuit! Navigate the menus to File → Create/Update → Create Symbol Files for Current File

It will try to save the result in the output_files directory again (ARGH), so navigate up to the main project directory before you save the symbol file.

With that done, switch back to your main project block diagram. Click on the Symbol Tool and scroll all the way to the top of the options, where you should find your new debouncer circuit waiting for you.

With that done, its time to add it into our circuit by doing the following:

  • Disconnecting the input to our original counter (while still keeping the pin)
  • Connecting the rotary encoder pin to the input of the debouncer circuit
  • Connecting the debouncer output to the original counter
  • Adding a new pin, named something like sysclk or clk.
    • Whatever helps you recognize it as a clock.

The end result should look like the following:

After Analyzing the project, go to the pin planner and assign your sysclk input to pin G21. This connects to one of the internal 50 MHz clocks in the FPGA.

Compile and test your project.

You should now have fewer issues with your counter jumping by multiple values at once.

You should be in good shape if you finish here on day 1

Counter logic

The original plan to for this class was for you to do this last week with discrete chips, but the input noise from our encoders made that untenable. We'll go over the logic of how the counter works in an expandable segment, and jump to the final circuit for now.

To begin with, you'll want to add another input for the other pin of your rotary encoder V7 and insert another copy of your debouncing circuit to process that input.

How does this work?

Taking an exclusive OR (XOR) between an input and its previous state will detect if the state has changed within the last clock cycle only. This works because the XOR only goes high if the two inputs to it are different. By then copying this setup for the other channel and ORing the inputs together, we have a setup that will produce an output either time one of the encoder channels changes state.

Next, we compare the output of one encoder channel with the previous state of the other channel. Since the two encoder outputs are 90 degrees out of phase with one another, then one output's change will always precede the other rotating clockwise, whereas the other channel will change first when turning the other direction. The reason we compare with the previous state of one of the channels is to reduce any errors due to timing, as in some implementations of this circuit the changing state and logic operation may occur too close together and not produce a reliable output. With our debounced circuit this should no longer be an issue, but we left it in place as good practice.

Here's a brief video that may help illustrate what we're talking about in the first minute or so:

Next, you'll build the following bit of processing logic. It is designed such that it will output a pulse every time A or B changes, and such that it will output a 0 or 1 depending on which signal is leading (giving us left-right info)

Build the circuit as shown, hook the lower output (labeled change_detected in the image) up to your counter, and verify that it still counts.

If you get an error reading Logic function of type *** and instance “***” is already defined as a signal name or another logic function, then one of your symbols in has the same name as another one of the same type. Double-click on the error message to have Quartus jump to the offender and change its name.

Make sure you use underscores instead of spaces in variable names. Quartus gets cranky if you try to use spaces.

Final Project: Rotation Sensor


Now that we've got our inputs sorted out, its time to expand things out to use the entire display.

To do this, we'll need to make the following modifications:

  • Replace our 4-bit counter with a 16 bit counter up-down counter that tops out at 10,000
    • The up-down setting is on the page where you change the number of bits
    • The screen after that has a setting that lets you say you want a Modulus counter, and then has a dialog box letting you set the maximum count value
    • Remember to connect your direction logic to the new up/down input
  • Create a new division instance that will take in a 16 bit numerator
  • Cascade our display logic out to convert the counter output into ones, tens, hundreds, and thousands, displaying them on the built-in display.
    • To get the tens digit, you can create the exact same setup you have for the ones, but the input will be the quotient from the divider in the ones counter.
    • The relevant pin connections are in the table below:
Digit
Display Segment Ones Tens Hundreds Thousands
A E11 A13 D15 B18
B F11 B13 A16 F15
C H12 C13 B16 A19
D H13 A14 E15 B19
E G12 B14 A17 C19
F F12 E14 B17 D19
G F13 A15 F14 G15

If you want you can set up a custom block for the division by ten logic, or you can try to copy-paste or just build things multiple times.

Or, in general, here are some of the most relevant pins: FPGA Pins

Bonus

If you want to keep playing around with the FPGA, the following projects might make for interesting starting places.


This project is a copy of the counter you just finished with a major addition. Instead of just letting you set a number with your rotary encoder, it uses that value to create a square wave of said frequency. The square wave is output on the top right pin in the GPIO 0 bank of pins AB16; if you're not sure which then ask a TA.


This makes use of an element called an accumulator, which has an internal buffer as well as a multi-bit input. Every clock cycle, it adds the input to the buffer (accumulating a larger and larger number) until the buffer runs over and resets to zero. The overflow output is set high when this happens.

By having an 8 bit buffer and a 8 bit counter input, the overflow will take several cycles before triggering the overflow the first time. As the counter value gets larger, it will overflow more and more frequently until the counter is at 2^8-1, at which case it will overflow on that same input. The result is that the overflow output is low most of the time, but spends more and more time high as the counter gets higher. Piping this signal to an output (say, and LED) results in what looks like a smooth brightness transition. This technique is known as Pulse Density Modulation, and is a fundamental tool in Direct Digital Synthesis (DSS).

The project also has some extra logic to make the clock count down instead of up, and some flip-flops used to toggle which LED is lit. Finally, it has a cascade of comparison circuits set up to stagger a trio of clocks to be 1/3 of a period apart.