TITLE: Display Multiplexer (original version)
AUTHOR: Chuck McManis
LAST UPDATE: 20-Mar-2001

Description

This is the earlier implementation of the MUXDISP capability. My first instinct was to re-use the design I had done for looper. That arose because I was solving the ‘same’ sort of problem which is that I was turning on one of 8 digits and in the looper code I was turning on one of 7 segments.

However from an inferred hardware perspective, in terms of how many gates you are using up, it was a poor choice. My original code would infer a latch holding 8 bits, and then shift those bits around in the latch, a simple shift register. They only represented three bits of information (which digit was on) and so I could actually get away with a single 3 bit counter. Code like this:

That code infers a simple de-multiplexor and re-uses unused resources in the CLBs that are driving the digits pins, whereas in the code below where it writes:

It mirrors the selector register content into the digits pins.

Using a selector as a shift register, 8 CLBs (one register bit per) whereas using a 3 bit counter and VHDL inferred de-mux 3 CLBs. So a 63% savings in CLB usage. That stuff adds up!

The Source Code

-- MUXDISP.VHD                    Chuck McManis 19-Mar-2001
--
-- This then is some VHDL to drive 8 digits of display with only 16 lines on the
-- FPGA. Our circuit consists of 8 lines going to all 8 of the seven segment
-- displays, and then 8 lines going to a Toshiba darlington current sink that
-- "enables" each digit by grounding the common cathode pin for that digit.
-- If you turn on more than one, you get more than one digit lit. Fun yes?
-- Just don't over draw the current on the FPGA!
--
-- NB: This is the older version which was not used in the final project
--     the final version changed from using a bit string for selecting the
--     digit to one using a count.
--
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity MUXDISP is
    Port ( mux_clk : in std_logic;     -- Multiplexing clock for display
           rst : in std_logic;         -- Reset pin
           data : in std_logic_vector(31 downto 0); -- Eight 4 bit digits.
           blank : in std_logic_vector(7 downto 0); -- Eight blank inputs
           dps : in std_logic_vector(7 downto 0);
           test : in std_logic;     -- Blank and test pins
           display : out std_logic_vector(6 downto 0); -- Segment output
           dpo : out std_logic; -- decimal point output.
           digits : out std_logic_vector(7 downto 0)); -- digit selectors
end MUXDISP;

architecture behavioral of MUXDISP is

    -- I use the previously defined hex_display component as the means
    -- to drive the segment pins.
    COMPONENT hex_display
    PORT(
        test :  IN std_logic;
        blank : IN std_logic;
        data :  IN std_logic_vector(3 downto 0);
        segs :  OUT std_logic_vector(6 downto 0)
    );
    END COMPONENT;

    -- Remember the 'looper' project? Guess what, we do that again :-)
    signal selector : std_logic_vector (7 downto 0);
    signal cur_digit : std_logic_vector (3 downto 0);
    signal cur_blank : std_logic;

begin
    u1: hex_display PORT MAP( test => test, blank => cur_blank,
                              data => cur_digit, segs => display);

    -- The use of the selector bit field here wastes gates
    cur_blank <= blank(0) when selector = "10000000" else
                 blank(1) when selector = "01000000" else
                 blank(2) when selector = "00100000" else
                 blank(3) when selector = "00010000" else
                 blank(4) when selector = "00001000" else
                 blank(5) when selector = "00000100" else
                 blank(6) when selector = "00000010" else
                 blank(7);

    -- Generate what appears to be the continuous display of 8 digits
    -- by lighting each digit up in sequence. If you can get all 8
    -- digits on at least once every 100 milleseconds, then they will
    -- look continuous. Just don't pick a multiple of 60hz!
    -- On the SPARTAN2 board 'mux_clk' is 24Mhz
    gen_display: process (rst, mux_clk) is
        variable d_clk : unsigned(13 downto 0);
    begin
        if (rst = '0') then
            selector <= "10000000";
            d_clk := "00000000000000";
        elsif rising_edge(mux_clk) then
            -- each time the count "rolls over" switch to the next
            -- digit. With 14 bits that is a count of 16384 and a
            -- freq of 1.465Khz, divided by 8 means each digit is
            -- illuminated 183 times/sec. (plenty fast)
            if (d_clk = 0) then
                -- select the next digit to display
                selector <= selector(0) & selector(7 downto 1);
            end if;
            d_clk := d_clk + 1; -- now keep counting up
        end if;
    end process;

    -- At this point the selector value is rotating around like the looper
    -- did, but this time it is enabling each digit in the display in turn.
    -- We use the value of the selector to decide which bit of data to put
    -- on the cur_digit lines (which feed the hex_display decoder)
    cur_digit <= data(31 downto 28) when selector = "00000001" else
                 data(27 downto 24) when selector = "00000010" else
                 data(23 downto 20) when selector = "00000100" else
                 data(19 downto 16) when selector = "00001000" else
                 data(15 downto 12) when selector = "00010000" else
                 data(11 downto  8) when selector = "00100000" else
                 data( 7 downto  4) when selector = "01000000" else
                 data( 3 downto  0);

    dpo <= dps(7) when selector = "00000001" else
           dps(6) when selector = "00000010" else
           dps(5) when selector = "00000100" else
           dps(4) when selector = "00001000" else
           dps(3) when selector = "00010000" else
           dps(2) when selector = "00100000" else
           dps(1) when selector = "01000000" else
           dps(0);

    -- further, we need to wire the selector value to the 'digits' output.
    digits <= selector;

end behavioral;

License

Creative Commons License

This work is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported License. You are free to play around with it and modify it but you are not licensed to use it for commercial purposes. Click the link above for more details on your rights under this license.