AUTOMATIXARON
FPGA as a box with a lot of gates
Aim of the tutorial:
In this tutorial we will design a hardware which counts the rising edges of a logic signal and displays the value on a single 7-Segment LED display.
Prerequisites:
We will use the hardware and software mentioned in the previous section. A little knowledge of digital electronics will be necessary for the hardware - gates, registers, counters, Boole algebra, and Karnaugh-maps.
Gate level implementation
We have a single 7-Segment display, on which we want to show counted edges. This means we want an encoder which creates the necessary signals for the display from a given binary coded decimal (BCD) value.
The input, in this case, is a 4bit number in the range of 0-9, while the output is a 7bit number named as A, B,.., G. as shown in the figure below.

We can create a Karnaugh map for each digit from the table above. We can then write the simplified boolean expression from the Karnaugh map, e.g. The maps of digits A and B:

The DP is the decimal point; we won't use it in this tutorial. My particular display is a TDSR5150, which is a red, common anode display as shown in the datasheet. The common anode displays need the anode tied to the supply rail, and we will connect the cathodes to the FPGA pins through 100Ω resistors. If your display is a common cathode one than the cathode needs to be tied to ground, and the output signals in this tutorial must be inverted.
First, we need to design a truth table with the digits from zero to nine, their respective binary values (these will be the inputs of our boolean functions) and the segment logic, with zero denoting a lit-up state, and one denoting a shut-down state.




We can write the expressions for the rest of the digits similarly:

Now we can create our encoder module in Verilog as:
Diamond has a built-in Simulation tool: Aldec Active-HDL. We can use this tool to simulate our SegmentLogic module.

And while we are at it, we could generate the RTL schematic of our module with the help of Synplify:

Now we have the simple logic module with a 4b input and 7b output.
Next, we need to create a counter for the button interface. We will design this counter in the top module.
The top module is equivalent to the main function in C (in a loose sense). We will connect the clk input to our button, and the segments output to the 7-Segment display.
We need a 4b counter since we want to count from zero to nine. We initialise the counter to 0 with the initial begin ... end structure.
​
Next, we create the counter routine with an always block. The sensitivity is set to the rising edge of the clk input. This routine increments the counter register and resets it after the value 9.
Finally, we create an instance of the coder logic, with the previously created counter as the input.
​
In Diamond, we need to synthesise the design (in the process window), and we need to create a map trace.
In the spreadsheet view (Tools/Spreadsheet View) we need to create the I/O constraints. Here are some important properties:
IO TYPE: here we set different voltage standards such as LVCMOS33, LVCMOS25 etc. This setting tells the synthesiser which bank must be used for the specified port.
-
Pull mode: here we can set weak pull-ups, pull-downs or keeper ports (The weak keeper circuit drives a weak 0 or 1 level to match the level it detects on the pad. When the pad is driven externally, transitions that override the weak keeper output change the state of the weak keeper's output to match. The weak keeper circuit maintains the last logic state present on the pad to prevent the pad from floating, when the pad is not driven either externally or by the logic, .)
-
PIN: here we set which pin must be used for which IO port and the synthesiser will place the design near said port if possible.
For my design, I've used pin 21 for the button input, and pins 4, 28, 10, 11, 12, 5, 9 for the segments, but we can choose other pins too. Here is the pinout of the TinyFPGA board:

After generating the JEDEC file and uploading with the programmer, we have a simple 7-Segment LED driver which counts the rising edges generated by a push button.
We can see that using a button as a clock source is not the brightest idea. Fortunately for us, we have multiple clock options available at our hand.
The simplest one is to use the internal oscillator. This oscillator can be set to a frequency of 2.08MHz to 133 MHz as shown on page 29 here.
Another counter must be used to lower the frequency to a readable 1-2Hz level.
The problem with the internal oscillator is the jitter. In the case of the Machx02, the internal oscillator has a 5% precision. We can compare the internal oscillator signal with the output of a pierce oscillator.

Here the inverter is created inside the FPGA using Verilog. The input and output pins are mapped to valid pll pins. The components I've used are: Rf = 1MΩ, Rs = 1kΩ, Ca=Cb = 20pF, with a 25MHz crystal.
​
Below we can see the differences between the internal and external oscillators (The distortion on the second image is due to my entry level oscilloscope probes). The oscilloscope is set to infinite persistence with the trigger shifted 39us to the left. The shaded regions show the clock jitter.
​


One last question would be: If the FPGA is more than just logic gates, could we create the BCD to 7Segment coder module more easily?
The answer is yes. If we treat the above mentioned truth table as a ROM, the inputs are the addresses, while the data will be the output. We can create a ROM with a switch-case structure:
Here we can see the coder logic implemented with a switch-case structure, and the synthesized module is a ROM instead of simple gates, as expected.

Here is a short video of the working example, and as always, the source code can be downloaded from here.