Introduction: Stopwatch Using VHDL
As a final project for my digital design class, I have decided to program a stopwatch on my FPGA. If you are familiar at all with digital design lingo, I am using a structural approach to complete this project. If that doesnt make any sense, dont worry about it.
The very first thing you will need to do is to get yourself an FPGA circuit board. The one I am using is a Basys 3 board by Digilent.
Step 1: Get Yourself a FPGA
The very first step to programming your FPGA is to make sure you have one ! For this Instructable, I am using a Basys 3 board. However, you can use pretty much any board for this project.
Step 2: Download Xilinx Vivado (free Webpack Version)
There are plenty of tutorials on how to do this. So I will not go into it here. This project will be in VHDL and Vivado is what you want to look up.
Step 3: Understand the Circuit We Are Going to Be Making
I have included a structural design for the approach we will be taking in this Instructable. It is always important to start with pencil and paper and sketch out a design before you even think about coding. By inspecting the diagram, you can get a pretty good understanding of how the circuit functions.
The inputs are the 100 Mhz clock built into the Diligent board, an enable button which starts and pauses the circuit, and a reset button which takes the display back to zero. The outputs are the cathodes which control the seven segments and the anodes which control which of the digits is currently lit.
16 bit counter and 10 Hz clock divider
By attaching a clock divider to the input clock, we can drive the 16 bit counter at 10 Hz (ten times per second). The outputs to the clock will be a binary number from 0000-1001 (0 to 9 decimal) . If we assume the top output of the 16 bit counter is the least significant digit, when it reaches 1001 (9 decimal) it will reset to 0000 at the next clock cycle and the next significant digit higher will be increased by one.
Problem: We need a way to translate these 4 bit numbers into a 7 bit code that can be used to manipulate the cathodes into the shape of a "0" , "1", "2", etc. Thankfuly we have...
There are four encoders whose inputs are the outputs of the 16 bit counter. Since the inputs to the encoders are a binary digit from 0000-1001, we can make the encoder so that it translates the inputs into a 7 bit code that can be used to manipulate the cathodes into displaying decimal numbers. For a better understanding of how the 7 segment display works in regards to the cathodes and anodes please see this link:
MUXes, two bit counter, and 250 Hz clock divider
If you read the link that I provided about the 7 segment display, you understand that the displays are all linked by a common annode but differnt cathodes. This means that if all of the annodes are on, they will display the same number. We do not want that. Instead we need a way of cycling through the encoded values while simultaneously turning on and off the corresponding annodes. What is more, we must do this at a frequency so that the human eye percieves all four digits as being on continuously. This is where the muxes, the two bit counter, and the clock divider come in. If we drive the clock at 250 Hz and syncronize it to the encoded values and the annodes, we can achieve our goal.
Step 4: Make Your 16 Bit Counter
Perhaps the most logical place to start is to begin with your 16 bit counter. After all this is the heart of the stop watch. Since the approach is structural, I made a seperate module for the counter and then included it as a component in my final design. Here is the code I designed for the counter.
Step 5: Make Clock Dividers
These take the form of a process statement within the main module. You could make a seperate module for them or include them in your main module as I did.
frequency_divider: process (clk_in)--this is the 250hz clock divider that cycles the anodes and cathodes
if rising_edge(clk_in) then
if (counter = 200000) then
temp <= NOT(temp); counter <= 0;
else counter <= counter + 1; end if; end if;
frequency_divider2: process (clk_in)--this is the 10 hz clockdivider that drives the counter
if rising_edge(clk_in) then
if (counter2 = 5000000) then
temp2 <= NOT(temp2); counter2 <= 0;
else counter2 <= counter2 + 1; end if; end if; end process;
Step 6: Make Encoders
the next step is converting the 4 bit binary digit into a 7 bit binary number that can manipulate displays.
Step 7: Make Muxes
Step 8: Make 2 Bit Counter
If you look at the diagram for the circuit that I provided this counter will provide a means to select which signal gets displayed when connected to the muxes. since it is connected to both the annode and cathode mux, they will be synchronized and we will get the display we expect.
Step 9: Wire It Up
Now you have all the parts you need to make the circuit. The next step is coming up with the proper signaling (or wiring). In essense we are just connecting the neccessary wires to the components. Here is code for the top module stopwatch.