vhdl_workshop:lab_7

LAB 7: A State Machine for the Display

In order to control the 7-segment display a simple state machine is necessary. In addition to the buttons for the desired exposure time another special button is present on the camera panel that allows the user to switch between the current exposure time and the number of pictures that have already been taken.

If one of the exposure time buttons is pressed the display will have to show the corresponding exposure time immediately. Otherwise, the display should toggle between exposure time and number of pictures whenever the SWITCH button is pressed.

The figure below shows the module interface:

The display controller module

Valid selections of a new exposure time are signaled by KEY values other than (0, 0, 0). Illegal combinations are filtered out by the keypad decoder module. Thus, SHOW_TIME has to be set to ’1’ if KEY is not equal (0,0,0).

The SWITCH signal can not be used directly to toggle the display as the button will be pressed down for much longer than the clock period. If the signal level is used for the decision, the display will flicker as it switches between picture count and exposure time every 100 microseconds. Therefore, a register is needed that stores the last value of the SWITCH signal.

The button has just been pressed when the SWITCH signal is ’1’ and has been ’0’ during the last clock cycle. Then the SHOW_TIME signal is inverted. Due to the fact that signals declared as out can not be read by processes within the entity, an additional display state signal is also needed.

All control signals shall be of type std_ulogic, as usual. Thus, only the KEY signal has a different data type, namely T_DIGITS from the P_DISPLAY package.

  • Write a new file with the VHDL description of the exposure latch.
  • Write the corresponding testbench.
  • Compile and simulate the design.
  • Synthesize the module.
DISP_CTRL.VHD
library ieee;
use ieee.std_logic_1164.all;
use work.P_DISPLAY.all;
 
entity DISP_CTRL is
  -- system signals: CLK, RESET
  -- control signals: SWITCH, KEY
  -- output signal: SHOW_TIME
end DISP_CTRL;
 
architecture RTL of DISP_CTRL is
  -- Internal signal for SHOW_TIME output
begin
  -- Output assignment
  -- Clocked process with asynchronous reset
  process
    variable LAST_SWITCH: std_ulogic;
  begin
    if (RESET = '1') then
      -- Reset all registers
    elsif (CLK'event and CLK = '1') then
      if KEY /= (0,0,0) then
        SHOW_STATE <= '1';
      else
        if LAST_SWITCH = '0' and SWITCH = '1' then
          -- Toggle output signal
        end if;
      end if;
 
      -- Store the SWITCH value to allow a rising edge detection
      LAST_SWITCH := SWITCH;
    end if; -- end of clocked process
  end process;
end RTL;
TB_DISP_CTRL.VHD
library ieee;
use std.textio.all;
use ieee.std_logic_1164.all;
use work.P_DISPLAY.all;
 
entity TB_DISP_CTRL is
end TB_DISP_CTRL;
 
architecture TEST of TB_DISP_CTRL is
  component DISP_CTRL
    port(CLK       : in std_ulogic;
         RESET     : in std_ulogic;
         SWITCH    : in std_ulogic;
         KEY       : in T_DIGITS;
         SHOW_TIME : out std_ulogic);
  end component;
 
  signal W_CLK       : std_ulogic := '0';
  signal W_RESET     : std_ulogic;
  signal W_SWITCH    : std_ulogic;
  signal W_KEY       : T_DIGITS;
  signal W_SHOW_TIME : std_ulogic;
 
begin
  DUT : DISP_CTRL
    port map(
      CLK       => W_CLK,
      RESET     => W_RESET,
      SWITCH    => W_SWITCH,
      KEY       => W_KEY,
      SHOW_TIME => W_SHOW_TIME);
 
  W_CLK <= not W_CLK after 10 ns;
 
  STIMULI : process
  begin
    W_KEY <= (0,0,0);
    W_SWITCH <= '0';
    W_RESET <= '1';
    -- SHOW_TIME = '0'
    wait for 5 ns;
 
    W_KEY <= (1,0,0);
    -- no changes
    wait for 20 ns;
 
    W_SWITCH <= '1';
    -- no changes
    wait for 20 ns;
 
    W_SWITCH <= '0';
    -- no changes
    wait for 20 ns;
 
    W_RESET <= '0';
    -- SHOW_TIME = '1'
    wait for 60 ns;
 
    W_SWITCH <= '1';
    -- no changes
    wait for 20 ns;
 
    W_SWITCH <= '0';
    -- no changes
    wait for 20 ns;
 
    W_KEY <= (0,0,0);
    -- no changes
    wait for 20 ns;
 
    W_SWITCH <= '1';
    -- SHOW_TIME = '0'
    wait for 60 ns;
 
    W_SWITCH <= '0';
    -- no changes
    wait for 20 ns;
 
    W_SWITCH <= '1';
    -- SHOW_TIME = '1'
    wait for 20 ns;
 
    W_SWITCH <= '0';
    -- no changes
    wait for 20 ns;
 
    assert false report "End of stimuli reached"
                 severity failure;
  end process STIMULI;
 
  SAMPLE : process(W_SHOW_TIME)
    constant SPACE     : string := " ";
    variable FILE_LINE : line;
    FILE     OUT_FILE  : text IS OUT "lab_7.trace";
  begin
    write(FILE_LINE, to_bit(W_SHOW_TIME));
    writeline(OUT_FILE, FILE_LINE);
  end process SAMPLE;
end TEST;
 
configuration CFG_TB_DISP_CTRL of TB_DISP_CTRL is
  for TEST
  end for;
end CFG_TB_DISP_CTRL;

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