Go Board Project – 7 Segment Displays

Let’s learn about these fun peripherals

The previous project taught us about debouncing a switch, and how to instantiate one module from another. Thus far, we’ve only been using Switches and LEDs to learn about FPGAs. Let’s introduce a new Go Board peripheral. The Go Board has a two digit 7-Segment display. This project will teach you how this works and how to drive it by building on the code from the previous project.

I also created a YouTube video for this project, should you prefer to follow along with that.

 

First, let’s show how a 7-Segment Display works. On the Go Board, there are two 7-Segment Displays. Each display has 7-inputs, each input drives one particular segment of the display. The segments are labeled in the figure to the right. So for example, in order to create the number 1, Segments B and C need to be illuminated. You’ve probably only ever seen displays that show the numbers 0-9. However it should be noted that it’s possible to display the hex characters A-F, as shown in the GIF to the left. This might be useful in a project coming up… hint hint. For this project, you’ll need to figure out when to drive each individual segment.

 

Project Description

Increment a Binary Counter to Drive One Digit of the 7-Segment Display Each Time a Switch is Released.

The previous project toggled the state of the LED when the switch was released. This project will keep track of the number of times (0-9) that the button was pressed in a counter. Once the counter gets up to 9, it will reset back to 0 and continue to count up. The value of the counter should be displayed on the 7-Segment Display. The image below shows the block diagram concept for how the code is designed.

Picture of Block Diagram

Project Block Diagram – Seven Segment Display

Your skills are improving. Try this project on your own. If you need any hints, you can refer to the solution below.


VHDL Solution

Most of this code should look familiar to you. Not many new concepts are introduced here. The project makes use of the Debounce_Switch module that we have designed. Additionally, there’s a new module that is Binary_To_7Segment. Take a look at the solution below, as well as the code in the Binary_To_7Segment file and make sure you understand everything.

VHDL Code – Project_7_Segment_Top.vhd:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity Project_7_Segment_Top is
  port (
    -- Main Clock (25 MHz)
    i_Clk         : in std_logic;
	
    -- Input Switch
    i_Switch_1    : in std_logic;
	
    -- Segment2 is lower digit, Segment1 is upper digit
    o_Segment2_A  : out std_logic;
    o_Segment2_B  : out std_logic;
    o_Segment2_C  : out std_logic;
    o_Segment2_D  : out std_logic;
    o_Segment2_E  : out std_logic;
    o_Segment2_F  : out std_logic;
    o_Segment2_G  : out std_logic
    );
end entity Project_7_Segment_Top;

architecture RTL of Project_7_Segment_Top is

  signal w_Switch_1 : std_logic;
  signal r_Switch_1 : std_logic := '0';
  signal r_Count    : integer range 0 to 9 := 0;

  signal w_Segment2_A : std_logic;
  signal w_Segment2_B : std_logic;
  signal w_Segment2_C : std_logic;
  signal w_Segment2_D : std_logic;
  signal w_Segment2_E : std_logic;
  signal w_Segment2_F : std_logic;
  signal w_Segment2_G : std_logic;

begin

  -- Instantiate Debounce Filter
  Debounce_Inst : entity work.Debounce_Switch
    port map (
      i_Clk    => i_Clk,
      i_Switch => i_Switch_1,
      o_Switch => w_Switch_1);
	  
  -- Purpose: When Switch is pressed, increment counter.
  -- When counter gets to 9, start it back at 0 again.
  p_Switch_Count : process (i_Clk)
  begin
    if rising_edge(i_Clk) then
      r_Switch_1 <= w_Switch_1;
	  
      -- Increment Count when switch is pushed down
      if (w_Switch_1 = '1' and r_Switch_1 = '0') then
        if (r_Count = 9) then
          r_Count <= 0;
        else 
          r_Count <= r_Count + 1;
        end if;
      end if;
    end if;
  end process p_Switch_Count;
  
  -- Instantiate Binary to 7-Segment Converter
  SevenSeg1_Inst : entity work.Binary_To_7Segment
    port map (
      i_Clk        => i_Clk,
      i_Binary_Num => std_logic_vector(to_unsigned(r_Count, 4)),
      o_Segment_A  => w_Segment2_A,
      o_Segment_B  => w_Segment2_B,
      o_Segment_C  => w_Segment2_C,
      o_Segment_D  => w_Segment2_D,
      o_Segment_E  => w_Segment2_E,
      o_Segment_F  => w_Segment2_F,
      o_Segment_G  => w_Segment2_G
      );
  
  o_Segment2_A <= not w_Segment2_A;
  o_Segment2_B <= not w_Segment2_B;
  o_Segment2_C <= not w_Segment2_C;
  o_Segment2_D <= not w_Segment2_D;
  o_Segment2_E <= not w_Segment2_E;
  o_Segment2_F <= not w_Segment2_F;
  o_Segment2_G <= not w_Segment2_G;
  
end architecture RTL;

Verilog Solution

Most of this code should look familiar to you. Not many new concepts are introduced here. The project makes use of the Debounce_Switch module that we have designed. Additionally, there’s a new module that is Binary_To_7Segment. Take a look at the solution below, as well as the code in the Binary_To_7Segment file and make sure you understand everything.

Verilog Code – Project_7_Segment_Top.v:

module Project_7_Segment_Top
  (input  i_Clk,      // Main Clock (25 MHz)
   input  i_Switch_1, 
   output o_Segment2_A,
   output o_Segment2_B,
   output o_Segment2_C,
   output o_Segment2_D,
   output o_Segment2_E,
   output o_Segment2_F,
   output o_Segment2_G
   );

  wire w_Switch_1;
  reg  r_Switch_1 = 1'b0;
  reg [3:0] r_Count = 4'b0000;

  wire w_Segment2_A;
  wire w_Segment2_B;
  wire w_Segment2_C;
  wire w_Segment2_D;
  wire w_Segment2_E;
  wire w_Segment2_F;
  wire w_Segment2_G;

  // Instantiate Debounce Filter
  Debounce_Switch Debounce_Switch_Inst
    (.i_Clk(i_Clk),
     .i_Switch(i_Switch_1),
     .o_Switch(w_Switch_1));
	  
  // Purpose: When Switch is pressed, increment counter.
  // When counter gets to 9, start it back at 0 again.
  always @(posedge i_Clk)
  begin
    r_Switch_1 <= w_Switch_1;
	  
      // Increment Count when switch is pushed down
      if (w_Switch_1 == 1'b1 && r_Switch_1 == 1'b0)
      begin
        if (r_Count == 9)
          r_Count <= 0;
        else 
          r_Count <= r_Count + 1;
      end
  end
  
  // Instantiate Binary to 7-Segment Converter
  Binary_To_7Segment Inst
    (.i_Clk(i_Clk),
     .i_Binary_Num(r_Count),
     .o_Segment_A(w_Segment2_A),
     .o_Segment_B(w_Segment2_B),
     .o_Segment_C(w_Segment2_C),
     .o_Segment_D(w_Segment2_D),
     .o_Segment_E(w_Segment2_E),
     .o_Segment_F(w_Segment2_F),
     .o_Segment_G(w_Segment2_G)
     );
  
  assign o_Segment2_A = ~w_Segment2_A;
  assign o_Segment2_B = ~w_Segment2_B;
  assign o_Segment2_C = ~w_Segment2_C;
  assign o_Segment2_D = ~w_Segment2_D;
  assign o_Segment2_E = ~w_Segment2_E;
  assign o_Segment2_F = ~w_Segment2_F;
  assign o_Segment2_G = ~w_Segment2_G;
  
endmodule

For both the VHDL and the Verilog solutions above, we instantiated two modules: Debounce_Switch and Binary_To_7Segment. Are you starting to see how more complicated pieces of code get created? When you design some block of code that has a useful purpose, it’s worth considering if it should be in its own module or entity. It makes reuse much easier if you can instantiate one module, rather than copy and pasting the same code in multiple designs.

One thing to keep in mind is there is a sweet-spot for the minimum and maximum amount of code that should be in a single file. For example, you wouldn’t want to wrap up a single AND Gate in a file AND_Gate.vhd, there’s not enough code in there to make it worth while. You’ll get a feel for deciding when to wrap up code in its own file as you do more designs. There’s nothing functionally wrong with putting everything inside one file, but you’ll find it gets unwieldy quickly.

Synthesis Report (selection)

Resource Usage Report for Project_7_Segment_Top 

I/O ports: 9

I/O Register bits:                  0
Register bits not including I/Os:   31 (2%)
Total load per clock:
   Project_7_Segment_Top|i_Clk: 1

Mapping Summary:
Total  LUTs: 52 (4%)

The synthesis report above shows that we are starting to figure out how to use some of our resources, though we still only used two percent of Registers and four percent of LUTs, so we have lots of room in the FPGA for more stuff.

 

Gif of results

Pressing Switch 1 Increments 7-Segment

Great! We have successfully driven the 7-Segment display! Not too bad right? There’s lots of fun projects that are available to you with a couple 7-Segment displays. I’ll leave it to you to get the second one running. Here’s a thought, how will you convert a binary number to a base-10 number that can be displayed on two 7-Segment displays? I’ll give a hint for one possible solution: The Double Dabbler. Now let’s move on to our next project. This one is going to introduce simulation and test benches.

Simulating an LED Blink Module