Electronic – 7 Segment display driver issues

displayfpgavhdl

I have this code for driving a seven segment display for hex. From my understanding its logically correct, but when I try and run it on my Nexsys 3 board I never get the correct output, it seems that the segments are almost running together when I run it, (ie. the same thing appears across all or some of them and all of the segment are always at least partially illuminated while the segments pertaining to the correct display just have a higher intensity).

below is my code

    library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    use IEEE.STD_LOGIC_unsigned.ALL;

    -- Uncomment the following library declaration if using
    -- arithmetic functions with Signed or Unsigned values
    use IEEE.NUMERIC_STD.ALL;

    -- Uncomment the following library declaration if instantiating
    -- any Xilinx primitives in this code.
    --library UNISIM;
    --use UNISIM.VComponents.all;

    entity SSD_driver is
         Port ( hex0 : in  STD_LOGIC_VECTOR (3 downto 0);
                  hex1 : in  STD_LOGIC_VECTOR (3 downto 0);
                  hex2 : in  STD_LOGIC_VECTOR (3 downto 0);
                  hex3 : in  STD_LOGIC_VECTOR (3 downto 0);
                  clock : in  STD_LOGIC;
                  reset : in  STD_LOGIC;
                  SEG : out  STD_LOGIC_VECTOR (7 downto 0);
                  AN : out  STD_LOGIC_VECTOR (3 downto 0));
    end SSD_driver;

    architecture Behavioral of SSD_driver is
    signal count : std_logic_vector(15 downto 0):=(others=>'0');
    signal mux_sel: std_logic_vector(1 downto 0):=(others=>'0');
    signal mux_out: std_logic_vector(3 downto 0):=(others=>'0');
    signal dec_out: std_logic_vector(3 downto 0):=(others=>'0');
    signal OC: std_logic_vector(3 downto 0):=(others=>'0');
    signal SS_cathode:STD_LOGIC_VECTOR(7 downto 0):=(others=>'0');

    begin
    counter:    process(clock,reset)
                    begin
                        if reset = '1' then
                            count<=(others=>'0');
                        else
                            if rising_edge(clock) then
                                count<=count+1;
                            end if;
                        end if;
                end process counter;
    mux_sel<=count(15 downto 14);

    with mux_sel select
        mux_out<=hex0 when "00",
                    hex1 when "01",
                    hex2 when "10",
                    hex3 when "11",
                    "0000" when others;

    with mux_sel select
        dec_out<="0001" when "00",
                    "0010" when "01",
                    "0100" when "10",
                    "1000" when "11",
                    "0000" when others;


    with mux_out select
        SS_cathode(7 downto 0) <=   x"C0" when "0000", -- 0
                                            x"F9" when "0001", -- 1
                                            x"A4" when "0010", -- 2
                                            x"B0" when "0011", -- 3
                                            x"99" when "0100", -- 4
                                            x"92" when "0101", -- 5
                                            x"82" when "0110", -- 6
                                            x"F8" when "0111", -- 7
                                            x"80" when "1000", -- 8
                                            x"90" when "1001", -- 9
                                            x"88" when "1010", -- a
                                            x"83" when "1011", -- b
                                            x"C6" when "1100", -- c
                                            x"A1" when "1101", -- d
                                            x"86" when "1110", -- e
                                            x"8E" when others; -- f

    SEG<=SS_cathode;
    AN<=not(dec_out);

    end Behavioral;

Any help would be appreciated, thanks in advance!

Best Answer

You obviously figured out your issue via the comments, but for those finding this question in the future, the answer lies in the Nexys datasheet. In short, yes, the 7-seg display digits are multiplexed, and as such, there is a setup and hold time when interfacing with those common anode/cathode transistors.

In this case, however, you have to switch between them slow enough for our human eyes to see the light, but fast enough so that there is no flicker. Think PWM: if you're switching between digits too quickly, the light will be dim.

The Digilent data sheet for the Nexys board answers this exact question. Check out section 9.1 which talks about interfacing with the seven-segment display. In particular...

Each digit is illuminated just one-quarter of the time, but because the eye cannot perceive the darkening of a digit before it is illuminated again, the digit appears continuously illuminated. If the update or "refresh" rate is slowed to around 45 hertz, most people will begin to see the display flicker.

In order for each of the four digits to appear bright and continuously illuminated, all four digits should be driven once every 1 to 16ms, for a refresh frequency of 1KHz to 60Hz. For example, in a 60Hz refresh scheme, the entire display would be refreshed once every 16ms, and each digit would be illuminated for ¼ of the refresh cycle, or 4ms. The controller must drive the cathodes with the correct pattern when the corresponding anode signal is driven. To illustrate the process, if AN0 is asserted while CB and CC are asserted, then a "1" will be displayed in digit position 1. Then, if AN1 is asserted while CA, CB and CC are asserted, then a "7" will be displayed in digit position 2. If AN0 and CB, CC are driven for 4ms, and then A1 and CA, CB, CC are driven for 4ms in an endless succession, the display will show "17" in the first two digits. An example timing diagram for a four-digit controller is provided.

Seven-Segment Timing Diagram. Same source, below

Source: "Nexys 3 FPGA Board Reference Manual". Digilent Incorporated. April 11, 2016. pg 19. PDF.

So there you go.