0

I have written some code (or rather copied some from the internet) to drive a single 7-Segment LCD display. This can display numbers in the range; [0, 9], or if in base 16; [0, F].

I have 4 such displays and I wish to convert an integer into 4 integers, such that the expected numbers will appear on the display.

For example; the number 8765 requires conversion into the 4 integers: 8, 7, 6, 5.

If I was doing this in C or other similar programming language, then I would use divisions and truncations to complete the conversion. However I am less familiar with VHDL, and so I don't know how to proceed.

How would I go about writing VHDL code to do this?

EDIT:

Currently I have something like this:

variable number: integer; -- This is set to the 4 digit value to be displayed
variable d0: integer; -- Least significant digit (units)
variable d1: integer;
variable d2: integer;
variable d3: integer; -- Most significant digit (thousands)

All these are (should be) in base 10, not 16.

FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225
  • For decimal output (hexadecimal output is trivial), this is a duplicate of [Convert 8bit binary number to BCD in VHDL](http://stackoverflow.com/questions/23871792/convert-8bit-binary-number-to-bcd-in-vhdl), even through none of the answers were up voted. You can take a look at the [Double dabble algorithm](http://en.wikipedia.org/wiki/Double_dabble). – Morten Zilmer Aug 13 '14 at 14:12

2 Answers2

0

Hexadecimal output

Well, this is pretty easy. Presumably you have an signal x : unsigned(15 downto 0). Drive each of the 7 segment displays respectively with:

  • x(3 downto 0)
  • x(7 downto 4)
  • x(11 downto 8)
  • x(15 downto 9)

Decimal Output

Well, you need to do convert the binary input to binary coded decimal. One recommended method is to use Double Dabble, which you can read more about at the linked wikipedia article.

If you wanted something slower, you could always do a handspun division. Subtracting 10 a number of times from the whole number would certainly work, but it would be more expensive and costly than double dabble.

Either way though, you should have plenty of time to do the work. Since you only have 4 7-segment displays, the largest number is 9999. If your clock is running at 1Mhz, and you need 1000 cycles to perform your conversion, then it will still only take 1ms to produce the outcome.

Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
  • No need for division; take a look at the [Double dabble algorithm](http://en.wikipedia.org/wiki/Double_dabble). – Morten Zilmer Aug 13 '14 at 14:13
  • @MortenZilmer: You need to do some method to convert the binary to binary coded decimal. Division is one method, subtracting 10 in a loop (which I'd recommend in this case) is another, and double dabble (which I was not aware of, but is quite interesting) is another. I imagine double dabble is more efficient than my suggested algorithm though. (But I'm not sure that matters too much when the goal is printing to a seven segment display). – Bill Lynch Aug 13 '14 at 14:16
  • @user3728501: Okay. So you have an integer. So do `to_unsigned(number, 16)` and now you have a `unsigned(15 downto 0)`. – Bill Lynch Aug 13 '14 at 14:17
  • @sharth I was told that doing conversions like this is bad practice. – FreelanceConsultant Aug 13 '14 at 14:22
  • @user3728501: I disagree. – Bill Lynch Aug 13 '14 at 14:23
  • 1
    @sharth: Fair enough, your answer is a possible method. However, for a VHDL implementation (as the tags suggest), the Double dabble algorithm is more efficient and the way it is usually done (once you get aware of the algorithm ;-) – Morten Zilmer Aug 13 '14 at 14:24
  • 1
    @MortenZilmer: Yeah. I just looked at that algorithm. That will be much nicer in hardware from the smaller adders. Only 4 bits instead of my suggested 14 bit adder! And only 14 iterations! – Bill Lynch Aug 13 '14 at 14:29
  • Here's a [VHDL implementation of the Double Dabble Algorithm](http://www.nandland.com/vhdl/modules/double-dabble.html) This should help. – Russell Aug 13 '14 at 14:39
  • There's an 8 bid double dabble parallel implementation here - [ A: Convert 8bit binary number to BCD in VHDL ](http://stackoverflow.com/questions/23871792/convert-8bit-binary-number-to-bcd-in-vhdl/23899472#23899472 " A: Convert 8bit binary number to BCD in VHDL "). It's extensible. to 14 bits. The interesting part is the add3 conditional adder expressed combinatorial. And the link to some [university lecture slides](https://web.archive.org/web/20120131075956/http://edda.csie.dyu.edu.tw/course/fpga/Binary2BCD.pdf "university lecture slides"). –  Aug 13 '14 at 17:45
0

Double dabble is the way to go but implementing it on an FPGA can be a step up for a beginner. You can consider alternative approaches. If the value you are displaying is simply a counter, you can create an array of base 10 digits, similar to:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity decimal_counter is
    port (
        clk             : in  std_logic;
        overflow_in     : in  std_logic;
        arst                : in  std_logic;
        value               : out  std_logic_vector(7 downto 0);
        overflow_out    : out  std_logic
    );
end decimal_counter;

architecture rtl of decimal_counter is

    constant ASCII_0        : natural := 48;
    constant ASCII_9        : natural := 57;
    signal counter : integer range ASCII_0 to ASCII_9 := ASCII_0;

begin

    p_decimal_counter : process (clk, arst)
    begin
        if (arst = '1') then
            counter         <= ASCII_0;
        elsif (rising_edge(clk)) then
            if (overflow_in = '1') then
                if (counter = ASCII_9) then
                    counter     <= ASCII_0;
                else
                    counter     <= counter + 1;
                end if; -- (counter = ASCII_9) then
            end if; -- if (overflow_in = '1') then
        end if; -- if (rising_edge(clk)) then
    end process p_decimal_counter;

  value <= std_logic_vector(to_unsigned(counter, value'length));
  overflow_out  <= '1' when ((counter = ASCII_9) and (overflow_in = '1')) else '0';

end rtl;

and

type ascii_digit_type is array ((NUM_DIGITS - 1) downto 0) of std_logic_vector(7 downto 0); 
signal counting_digits      : ascii_digit_type  :=      (OTHERS => (OTHERS => '0'));
...
-- Generate a counter to count ticks on an input pin
gen_counter : for i in 0 to (NUM_DIGITS - 1) generate
    lowest_digits: if (i = 0) generate
        lowest_digit : decimal_counter 
        port map
        (
            clk            => EXP_I(9),
            overflow_in     => '1',
            arst                => start_tx_tick,
            value               => counting_digits(i)
            overflow_out    => digits_overflow(i)
        );
    end generate lowest_digits;
    upper_digits: if (i > 0) generate
        upper_digit : decimal_counter 
        port map
        (
            clk           => EXP_I(9),
            overflow_in     => digits_overflow(i - 1),
            arst                => start_tx_tick,
            value               => counting_digits(i)
            overflow_out    => digits_overflow(i)
        );
    end generate upper_digits;
end generate gen_counter;
KWolfe81
  • 71
  • 3