3
\$\begingroup\$

I have been trying to multiplex a 4 digit seven segment display on my FPGA board but have been running into not being to get it fast enough so it looks solid to the human eye.

You can see an example of the speed here: http://youtu.be/geTgZcHrXTc

How do multiplex fast enough so it looks solid to the human eye?

I am using the Basys 2 board.

Right now my VHDL looks like:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity main is
    port(
        clock       : in STD_LOGIC;
        sevenseg    : out STD_LOGIC_VECTOR(6 downto 0);
        anodes  : out STD_LOGIC_VECTOR(3 downto 0);
        switches    : in STD_LOGIC_VECTOR(6 downto 0);
        dp      : in STD_LOGIC
    );
end main;

architecture Behavioral of main is
    signal counter: STD_LOGIC_VECTOR(1 downto 0) := (others => '0');
    signal r_anodes: STD_LOGIC_VECTOR(3 downto 0);
begin

    anodes <= r_anodes;

    -- Given Binary Value print it
    multiplex: process(counter, switches)
    begin
        -- Set anode correctly
        case counter(1 downto 0) is
            when "00" => r_anodes <= "1110"; -- AN 0
            when "01" => r_anodes <= "1101"; -- AN 1
            when "10" => r_anodes <= "1011"; -- AN 2
            when "11" => r_anodes <= "0111"; -- AN 3

            when others => r_anodes <= "1111"; -- nothing
        end case;

        -- Set segments correctly
        case r_anodes is
            when "1110" => 
                if switches(0) = '1' then
                    sevenseg <= "1111001"; -- 1
                else
                    sevenseg <= "1000000"; -- 0
                end if;
            when "1101" => 
                if switches(1) = '1' then
                    sevenseg <= "1111001"; -- 1
                else
                    sevenseg <= "1000000"; -- 0
                end if;
            when "1011" => 
                if switches(2) = '1' then
                    sevenseg <= "1111001"; -- 1
                else
                    sevenseg <= "1000000"; -- 0
                end if;
            when "0111" => 
                if switches(3) = '1' then
                    sevenseg <= "1111001"; -- 1
                else
                    sevenseg <= "1000000"; -- 0
                end if;

            when others => sevenseg <= "1111111"; -- nothing
        end case;

    end process;

    countClock: process(clock, counter)
    begin
        if rising_edge(clock) then
            -- Iterate
            counter <= counter + 1;
        end if;
    end process;


end Behavioral;

And my constraints file looks like:

NET "sevenseg<0>" LOC = "L14";
NET "sevenseg<1>" LOC = "H12";
NET "sevenseg<2>" LOC = "N14";
NET "sevenseg<3>" LOC = "N11";
NET "sevenseg<4>" LOC = "P12";
NET "sevenseg<5>" LOC = "L13";
NET "sevenseg<6>" LOC = "M12";
NET "dp" LOC = "N13";

NET "anodes<3>" LOC = "K14";
NET "anodes<2>" LOC = "M13";
NET "anodes<1>" LOC = "J12";
NET "anodes<0>" LOC = "F12";

NET "switches<6>" LOC = "E2";
NET "switches<5>" LOC = "F3";
NET "switches<4>" LOC = "G3";
NET "switches<3>" LOC = "B4";
NET "switches<2>" LOC = "K3";
NET "switches<1>" LOC = "L3";
NET "switches<0>" LOC = "P11";

NET "clock" TNM_NET = clock;
TIMESPEC TS_clock = PERIOD "clock" 20 ns HIGH 50%;
\$\endgroup\$
  • \$\begingroup\$ You don't seem to be setting a "LOC" for the clock input pin. Can you verify that it's connected where you think it is? \$\endgroup\$ – Dave Tweed Oct 19 '12 at 1:10
  • \$\begingroup\$ According to the manual, it should be pin B8, but this 50 MHz input will need to be divided down to maybe 500 Hz or so for scanning the display. \$\endgroup\$ – Dave Tweed Oct 19 '12 at 1:16
  • \$\begingroup\$ @DaveTweed Thanks, I have been overlooking adding the "LOC" for the clock on all my projects... Just making a time constraint. So can I divide the clock in a time constraint or do I have to use a prescaler? \$\endgroup\$ – MLM Oct 19 '12 at 1:46
3
\$\begingroup\$

Thank you Dave Tweed for finding my small mistake.

I forgot to add the "LOC" in the constraints file.

NET "clock" LOC = "B8";

I also had some pulse width issues(segments partially on) with the full 50 MHz as Dave Tweed also mentioned. So I used a prescaler to tone it back to 500 Hz.

Divide a 50 Mhz clock by 100,000 (base 10) or 11000011010100000 (binary)

Final code looks like:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity main is
    port(
        clock       : in STD_LOGIC;
        sevenseg    : out STD_LOGIC_VECTOR(6 downto 0);
        anodes  : out STD_LOGIC_VECTOR(3 downto 0);
        switches    : in STD_LOGIC_VECTOR(6 downto 0);
        dp      : in STD_LOGIC
    );
end main;

architecture Behavioral of main is
    signal prescaler: STD_LOGIC_VECTOR(16 downto 0) := "11000011010100000";
    signal prescaler_counter: STD_LOGIC_VECTOR(16 downto 0) := (others => '0');
    signal counter: STD_LOGIC_VECTOR(1 downto 0) := (others => '0');
    signal r_anodes: STD_LOGIC_VECTOR(3 downto 0);
begin

    anodes <= r_anodes;

    -- Given Binary Value print it
    multiplex: process(counter, switches)
    begin
        -- Set anode correctly
        case counter(1 downto 0) is
            when "00" => r_anodes <= "1110"; -- AN 0
            when "01" => r_anodes <= "1101"; -- AN 1
            when "10" => r_anodes <= "1011"; -- AN 2
            when "11" => r_anodes <= "0111"; -- AN 3

            when others => r_anodes <= "1111"; -- nothing
        end case;

        -- Set segments correctly
        case r_anodes is
            when "1110" => 
                if switches(0) = '1' then
                    sevenseg <= "1111001"; -- 1
                else
                    sevenseg <= "1000000"; -- 0
                end if;
            when "1101" => 
                if switches(1) = '1' then
                    sevenseg <= "1111001"; -- 1
                else
                    sevenseg <= "1000000"; -- 0
                end if;
            when "1011" => 
                if switches(2) = '1' then
                    sevenseg <= "1111001"; -- 1
                else
                    sevenseg <= "1000000"; -- 0
                end if;
            when "0111" => 
                if switches(3) = '1' then
                    sevenseg <= "1111001"; -- 1
                else
                    sevenseg <= "1000000"; -- 0
                end if;

            when others => sevenseg <= "1111111"; -- nothing
        end case;

    end process;

    countClock: process(clock, counter)
    begin
        if rising_edge(clock) then
            prescaler_counter <= prescaler_counter + 1;
            if(prescaler_counter = prescaler) then
                -- Iterate
                counter <= counter + 1;

                prescaler_counter <= (others => '0');
            end if;
        end if;
    end process;


end Behavioral;
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.