0
\$\begingroup\$

As part of my project for the Digital System Design course I have to use a component to display on the 7-segment display a INTEGER range 0 to 9999 (or a std_logic_vector(13 downto 0)). I used the double dabble algorithm to convert a 14 bit binary number into BCD and then extracted the 4 digits. I tested the component in Active-HDL and it works good, but once loaded on my Basys2 FPGA board, it displays the wrong numbers. For example, instead of "1770", I get "0064".

I am pretty sure that the problem is caused by something from the first process, where the BCD digits are generated, but I couldn't figure out what the problem is. Here is the code of the component:

library ieee;
use ieee.std_logic_1164.all; 
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

entity DISP_SOLD is
    port (EN: in std_logic;
    CLK_PLACA: in std_logic;    
    SUMA: in integer range 0 to 9999;
    -- Cathodes
    L18_CA: out std_logic;
    F18_CB: out std_logic;
    D17_CC: out std_logic;
    D16_CD: out std_logic;
    G14_CE: out std_logic;
    J17_CF: out std_logic;
    H14_CG: out std_logic;  
    -- Anodes
    AN0_F17: out std_logic;
    AN1_H17: out std_logic;
    AN2_C18: out std_logic;
    AN3_F15: out std_logic);
end DISP_SOLD;

architecture ARH of DISP_SOLD is 
-- digit_pattern_array = current_BCD_digit
signal digit_pattern_array  : std_logic_vector(6 downto 0) := "0000000";
signal current_segment   : std_logic_vector(1 downto 0) := "00";
signal cathode_select   : std_logic_vector(3 downto 0) := "0000";   
-- count use for the clock divider
signal count      : std_logic_vector(6 downto 0) := "0000000";
-- MUX_CLK is the clock resulting from the clock divider
signal MUX_CLK      : std_logic; 
signal cifra_mii: std_logic_vector(3 downto 0):="0000";    -- 1st digit
signal cifra_sute: std_logic_vector(3 downto 0):="0000";   -- 2nd digit
signal cifra_zeci: std_logic_vector(3 downto 0):="0000";   -- 3rd digit
signal cifra_unitati: std_logic_vector(3 downto 0):="0000";  -- 4th digit
begin
    process(EN, SUMA)
    variable BIN: std_logic_vector(13 downto 0);
    variable BCD: std_logic_vector(15 downto 0):=(others => '0');
    variable i: integer:=0;
    variable CONVERTED: std_logic:='0';
    begin
        if EN='1' and CONVERTED='0' then
            BIN := conv_std_logic_vector(SUMA, 14);
            -- Convert Binary to BCD (Double Dabble algorithm)
            for i in 0 to 13 loop
                bcd(15 downto 1) := bcd(14 downto 0);  --shifting the bits.
                bcd(0) := bin(13);
                bin(13 downto 1) := bin(12 downto 0);
                bin(0) :='0';

                if(i < 13 and bcd(3 downto 0) > "0100") then --add 3 if BCD digit is greater than 4.
                bcd(3 downto 0) := bcd(3 downto 0) + "0011";
                end if;
                if(i < 13 and bcd(7 downto 4) > "0100") then --add 3 if BCD digit is greater than 4.
                bcd(7 downto 4) := bcd(7 downto 4) + "0011";
                end if;
                if(i < 13 and bcd(11 downto 8) > "0100") then  --add 3 if BCD digit is greater than 4.
                bcd(11 downto 8) := bcd(11 downto 8) + "0011";
                end if; 
                if(i < 13 and bcd(15 downto 12) > "0100") then  --add 3 if BCD digit is greater than 4.
                bcd(15 downto 12) := bcd(15 downto 12) + "0011";
                end if;
            end loop; 
            if SUMA /= 0 then
                CONVERTED:='1';
            end if;
            cifra_mii <= BCD(15 downto 12); 
            cifra_sute <= BCD(11 downto 8);
            cifra_zeci <= BCD(7 downto 4);
            cifra_unitati <=BCD(3 downto 0);
        end if;
    end process;

    -- CLK_PLACA: from 50MHz to MUX_CLK (~390Hz)
    divizor_CLK: process(CLK_PLACA)
    begin 
        if rising_edge(CLK_PLACA) then
            count <= count + '1';
        end if;
        MUX_CLK <= count(6);
    end process;

    variable current_BCD_digit: std_logic_vector(3 downto 0);
    begin
        if rising_edge(MUX_CLK) then 
            current_segment <= current_segment + '1';
            case current_segment is
                when "00" =>  current_BCD_digit := cifra_mii;
                cathode_select <= "1110";         
                when "01" => current_BCD_digit := cifra_sute;
                cathode_select <= "1101"; 
                when "10" =>  current_BCD_digit := cifra_zeci;
                cathode_select <= "1011"; 
                when "11" => current_BCD_digit := cifra_unitati;
                cathode_select <= "0111"; 
                when others => null;     
            end case; 

            case current_BCD_digit is
                when "0000" => digit_pattern_array <= "0000001";
                when "0001" => digit_pattern_array <= "1001111";
                when "0010" => digit_pattern_array <= "0010010";
                when "0011" => digit_pattern_array <= "0000110";
                when "0100" => digit_pattern_array <= "1001100";
                when "0101" => digit_pattern_array <= "0100100";
                when "0110" => digit_pattern_array <= "0100000";
                when "0111" => digit_pattern_array <= "0001111";
                when "1000" => digit_pattern_array <= "0000000";
                when "1001" => digit_pattern_array <= "0001100";
                when others => null;
            end case;   
        end if;
    end process;
    L18_CA <= digit_pattern_array(6);
    F18_CB <= digit_pattern_array(5);
    D17_CC <= digit_pattern_array(4);
    D16_CD <= digit_pattern_array(3);
    G14_CE <= digit_pattern_array(2);
    J17_CF <= digit_pattern_array(1);
    H14_CG <= digit_pattern_array(0);

    AN0_F17 <= cathode_select(0) when EN='1' else '0';
    AN1_H17 <= cathode_select(1) when EN='1' else '0';
    AN2_C18 <= cathode_select(2) when EN='1' else '0';
    AN3_F15 <= cathode_select(3) when EN='1' else '0'; 
end ARH;
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

In VHDL (and HDLs in general) a for loop does not denote sequential execution like it does in a software programming language — it denotes the construction of multiple parallel instances of the hardware described in the body of the loop.

In your case, you have many assignments to the same variable BCD/bcd, and these are conflicting with each other. If you really intend to construct a system based on two shift registers (one binary, one bcd) that takes 14 clock periods to do the conversion, then you need to describe the hardware that way, and set up a state machine to control it.

On the other hand, if you really want to do it entirely combinatorially, then you need to create different intermediate variables (e.g., arrays that are indexed by the loop control variable) to hold the results at each stage.

\$\endgroup\$
2
  • \$\begingroup\$ Thank you for your answer! I do not insist to do it combinationally. The binary to BCD conversion I used was inspired from this website, with the only difference that I generated a 16-bit BCD number. It sais there that the code works, and is synthesisable. \$\endgroup\$ May 24, 2013 at 16:30
  • 1
    \$\begingroup\$ Yes, but in that example, they used a function, while you turned it into a process -- completely different in terms of the synthesis process. \$\endgroup\$
    – Dave Tweed
    May 24, 2013 at 17:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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