vhdl_workshop:lab_4

LAB 4: A Three Digit 7-Segment Display Driver

In the final version, DISP_DRV has to drive a 7-segment display with three digits. Other than that, the design needs not to be modified. The most convenient way to handle the data within the design is to define a new type, i.e. an array of three integer respective bit vector values. As user-defined types are already used it is only necessary to change the definition of T_DIGITS respective T_DISPLAY.

It is one of the main advantages of using project-specific packages in bigger projects that the interface of the different modules is easily changed by modifying the type definition. Of course, it is also necessary to change the VHDL code accordingly. The multiplex process is already almost finished as the control signals have not changed. It is just the assignment of 10 in case of an error that must be augmented to be an array of ’10’s that is assigned.

The mapping functionality itself is also correct. The decoder process, however, needs to be modified as all three integer values have to be mapped to their corresponding vector representation. The easiest solution is to place the case-statement which performs the actual decoding within a loop that processes one digit per iteration.

The basic behaviour remains unchanged.

The names of the data types of the signals remain the same. It is just the definition of the T_DIGITS and T_DISPLAY types that has to be changed to an array type.

  • Edit the P_DISPLAY package so that T_DIGITS and T_DISPLAY are arrays of type integer and std_ulogic_vector, respectively. The length of the arrays shall be 3. Do not forget to include the range specification for the array elements!
  • Adjust the two processes of the DISP_DRV architecture so that they cope with the new data types.
  • Modify the stimuli generation in the testbench to verify the correct behaviour.
  • Compile all source files and run the simulation.
  • Synthesize the design.
DISP_DRV.VHD
-- include packages
 
entity DISP_DRV is
  port(ERROR     : in std_ulogic;
       SHOW_TIME : in std_ulogic;
       NO_PICS   : in T_DIGITS;
       EXP_TIME  : in T_DIGITS;
       DISPLAY   : out T_DISPLAY);
end DISP_DRV;
 
architecture RTL of DISP_DRV is
  signal DISP_PHOTO : T_DIGITS;
begin
  DISP_MUX:process (SHOW_TIME, ERROR,
                    EXP_TIME, NO_PICS)
  begin
    if ERROR = '1' then
      DISP_PHOTO <= (10; 10; 10);
    elsif SHOW_TIME = '0' then
      -- output = picture count
    else
      -- output = exposure time
    end if;
  end process DISP_MUX;
 
  DECODE: process (DISP_PHOTO)
  begin
    -- Process all elements of the data arrays
    case DISP_PHOTO is
      when 0 => DISPLAY <= SEG_0;
      when 1 => DISPLAY <= SEG_1;
      when 2 => DISPLAY <= SEG_2;
      when 3 => DISPLAY <= SEG_3;
      when 4 => DISPLAY <= SEG_4;
      when 5 => DISPLAY <= SEG_5;
      when 6 => DISPLAY <= SEG_6;
      when 7 => DISPLAY <= SEG_7;
      when 8 => DISPLAY <= SEG_8;
      when 9 => DISPLAY <= SEG_9;
      when others => DISPLAY <= SEG_E;
    end case;
  end process DECODE;
end RTL;
TB_DISP_DRV.VHD
library ieee;
use ieee.std_logic_1164.all;
use work.P_DISPLAY.all;
 
entity TB_DISP_DRV is
end TB_DISP_DRV;
 
architecture TEST of TB_DISP_DRV is
  component DISP_DRV
    port(ERROR     : in std_ulogic;
         SHOW_TIME : in std_ulogic;
         NO_PICS   : in T_DIGITS;
         EXP_TIME  : in T_DIGITS;
         DISPLAY   : out T_DISPLAY);
    end component;
 
  signal W_ERROR : std_ulogic :='0';
  signal W_SHOW_TIME : std_ulogic :='0';
  signal W_NO_PICS : T_DIGITS;
  signal W_EXP_TIME : T_DIGITS;
  signal W_DISPLAY : T_DISPLAY;
 
begin
  DUT : DISP_DRV
    port map(
      ERROR     => W_ERROR,
      NO_PICS   => W_NO_PICS,
      EXP_TIME  => W_EXP_TIME,
      SHOW_TIME => W_SHOW_TIME,
      DISPLAY   => W_DISPLAY);
 
  STIMULI : process
  begin
    -- DISPLAY = (0,0,0)
    wait for 30 ns;
 
    W_NO_PICS <= (0,0,0);
    W_EXP_TIME <= (5,0,0);
    -- no changes
    wait for 20 ns;
 
    for I in 1 to 10 loop
      W_NO_PICS <= (0,0,I);
      -- DISPLAY = (0,0,1)..(0,0,E)
      wait for 20 ns;
    end loop;
 
    W_SHOW_TIME <= '1';
    -- DISPLAY = (5,0,0)
    wait for 20 ns;
 
    W_EXP_TIME <= (0,6,0);
    W_NO_PICS <= (4,0,0);
    -- DISPLAY = (0,6,0)
    wait for 20 ns;
 
    W_SHOW_TIME <= '0';
    -- DISPLAY = (4,0,0)
    wait for 20 ns;
 
    W_ERROR <= '1';
    -- DISPLAY = (E,E,E)
    wait for 20 ns;
 
    W_SHOW_TIME <= '1';
    -- no changes
    wait for 20 ns;
 
    W_ERROR <= '0';
    -- DISPLAY = (0,6,0)
    wait for 20 ns;
 
    W_SHOW_TIME <= '0';
    -- DISPLAY = (4,0,0)
    wait for 20 ns;
 
    wait;
  end process STIMULI;
  DISPLAY_DIGIT(W_DISPLAY);
end TEST;
 
configuration CFG_TB_DISP_DRV of TB_DISP_DRV is
  for TEST
  end for;
end CFG_TB_DISP_DRV;

LAB 4, 5, 6, 7, 8, 9, 10, 11

P_DISPLAY.VHD
library ieee;
use ieee.std_logic_1164.all;
 
package P_DISPLAY is
  type T_DIGITS  is array (2 downto 0) of integer range 0 to 10;
  type T_DISPLAY is array (2 downto 0) of std_ulogic_vector(6 downto 0);
 
  constant SEG_0 : std_ulogic_vector(6 downto 0):= "0111111";
  constant SEG_1 : std_ulogic_vector(6 downto 0):= "0000011";
  constant SEG_2 : std_ulogic_vector(6 downto 0):= "1101101";
  constant SEG_3 : std_ulogic_vector(6 downto 0):= "1100111";
  constant SEG_4 : std_ulogic_vector(6 downto 0):= "1010011";
  constant SEG_5 : std_ulogic_vector(6 downto 0):= "1110110";
  constant SEG_6 : std_ulogic_vector(6 downto 0):= "1111110";
  constant SEG_7 : std_ulogic_vector(6 downto 0):= "0100011";
  constant SEG_8 : std_ulogic_vector(6 downto 0):= "1111111";
  constant SEG_9 : std_ulogic_vector(6 downto 0):= "1110111";
  constant SEG_E : std_ulogic_vector(6 downto 0):= "1111100";
 
  -- pragma translate_off
  procedure DISPLAY_DIGIT(signal DISPLAY:T_DISPLAY);
  -- pragma translate_on
end P_DISPLAY;
 
-- pragma translate_off
use std.textio.all;
package body P_DISPLAY is
  ------------------------------
  --
  --            111111111112222
  --   123456789012345678901234
  --  1  #5##    ####    ####
  --  2 #    #  #    #  #    #
  --  3 4    0  #    #  #    #
  --  4 #    #  #    #  #    #
  --  5  #6##    ####    ####
  --  6 #    #  #    #  #    #
  --  7 3    1  #    #  #    #
  --  8 #    #  #    #  #    #
  --  9  #2##    ####    ####
  --
  ------------------------------
 
  constant ACTIVE_SEG: character := '#';
  constant EMPTY_SEG:  character := ' ';
 
  -- Width and height of a digit
  constant WIDTH:  integer := 8;
  constant HEIGHT: integer := 9;
 
  -- Datatypes to store the complete display in a matrix
  subtype T_MATRIX_ROW  is bit_vector (1 to 3*WIDTH);
  type    T_DISP_MATRIX is array (1 to HEIGHT) of T_MATRIX_ROW;
 
  -- Definition of the appearance of the 6 segments
  subtype T_DIGIT_ROW is bit_vector(1 to WIDTH);
  type    T_SEG_DEF   is array (1 to HEIGHT) of T_DIGIT_ROW;
  type    T_DIGIT_DEF is array (0 to 6) of T_SEG_DEF;
  constant DIGIT_DEF: T_DIGIT_DEF :=(("00000000", --   ....
                                      "00000010", --  .    #
                                      "00000010", --  .    0
                                      "00000010", --  .    #
                                      "00000000", --   ....
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000"),--   ....
 
                                     ("00000000", --   ....
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --   ....
                                      "00000010", --  .    #
                                      "00000010", --  .    1
                                      "00000010", --  .    #
                                      "00000000"),--   ....
 
                                     ("00000000", --   ....
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --   ....
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00111100"),--   #2##
 
                                     ("00000000", --   ....
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --   ....
                                      "01000000", --  #    .
                                      "01000000", --  3    .
                                      "01000000", --  #    .
                                      "00000000"),--   ....
 
                                     ("00000000", --   ....
                                      "01000000", --  #    .
                                      "01000000", --  4    .
                                      "01000000", --  #    .
                                      "00000000", --   ....
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000"),--   ....
 
                                     ("00111100", --   #5##
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --   ....
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000"),--   ....
 
                                     ("00000000", --   ....
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00111100", --   #6##
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000", --  .    .
                                      "00000000"));--  ....
 
  procedure DISPLAY_DIGIT(signal DISPLAY:T_DISPLAY) is
    file OUTFILE : TEXT is out "display.txt";
 
    variable L : line;
    variable DISP_TEXT: string(T_MATRIX_ROW'range);
 
    variable DISP_MATRIX: T_DISP_MATRIX;
    variable COL_L: integer;
    variable COL_R: integer;
 
  begin
    -- Clear the display
    DISP_MATRIX := (others => (others => '0'));
 
    -- Loop over all digits
    for DIGIT in T_DISPLAY'range loop
      -- Calculate the left- and rightmost columns
      COL_L := DIGIT*WIDTH + 1;
      COL_R := DIGIT*WIDTH + WIDTH;
 
      -- Loop over all segments
      for SEGMENT in 0 to 6 loop
        if DISPLAY(DIGIT)(SEGMENT) = '1' then
          -- Copy the matrix to the final display
          -- Loop over all rows of the display
          for ROW in T_SEG_DEF'range loop
            DISP_MATRIX(ROW)(COL_L to COL_R) :=
              DISP_MATRIX(ROW)(COL_L to COL_R) or
              DIGIT_DEF(SEGMENT)(ROW);
          end loop;
        end if;
      end loop;
    end loop;
 
    -- Write the matrix to a textfile
    for I in T_DISP_MATRIX'range loop
      -- Start with an empty line
      DISP_TEXT := (others => EMPTY_SEG);
 
      for J in T_MATRIX_ROW'range loop
        if DISP_MATRIX(I)(J) = '1' then
          DISP_TEXT(J) := ACTIVE_SEG;
        end if;
      end loop;
 
      -- Write the line
      write(L, DISP_TEXT);
      writeline(OUTFILE, L);
    end loop;
 
  end DISPLAY_DIGIT;
end P_DISPLAY;
-- pragma translate_on