Difference between revisions of "DX TM1638 Display"

From Tech
Jump to navigationJump to search
 
(4 intermediate revisions by the same user not shown)
Line 73: Line 73:
 
--
 
--
 
--
 
--
--TODO:
 
-- allow specification of d_clk frequency via generics
 
-- check rounding of compile-time divide (bcd function)
 
-- clock-division in dx_display_xmit via counter, not 64-bit register.
 
 
----------------------------------------------------------------------------------
 
----------------------------------------------------------------------------------
 
library IEEE;
 
library IEEE;
Line 94: Line 90:
   
 
COMPONENT dx_display
 
COMPONENT dx_display
  +
Generic(clkDivider: integer);
 
PORT(
 
PORT(
 
clk : IN std_logic;
 
clk : IN std_logic;
Line 114: Line 111:
 
signal digits: bytearray(0 to 7) := (others => x"00");
 
signal digits: bytearray(0 to 7) := (others => x"00");
 
signal leds: bytearray(0 to 7) := (others => x"00");
 
signal leds: bytearray(0 to 7) := (others => x"00");
signal data: integer range -2000000000 to 2000000000 :=0;
+
signal data: integer range -2000000000 to 2000000000 :=0;--20000/3;
  +
signal decdata: integer range -2000000000 to 2000000000 :=0;--20000/3;
 
signal tmp: std_logic_vector(31 downto 0);
 
signal tmp: std_logic_vector(31 downto 0);
 
signal keybyte: std_logic_vector(7 downto 0);
 
signal keybyte: std_logic_vector(7 downto 0);
  +
signal key_int:integer range 0 to 255;
 
 
begin
 
begin
 
Inst_dx_display: dx_display
 
Inst_dx_display: dx_display
  +
Generic Map(clkDivider => 16)
 
PORT MAP(
 
PORT MAP(
 
clk => clk,
 
clk => clk,
Line 132: Line 131:
 
Inst_display7seg:display7seg
 
Inst_display7seg:display7seg
 
PORT MAP(
 
PORT MAP(
digits => digits(0 to 7),
+
digits => digits(0 to 1),
data => data);
+
data => key_int);
 
 
-- Inst_display7segDec:display7seg
+
Inst_display7segDec:display7seg
-- PORT MAP(
+
PORT MAP(
-- digits => digits(6 to 7),
+
digits => digits(2 to 7),
-- data => decdata);
+
data => decdata);
 
 
 
reset_proc: process(clk)
 
reset_proc: process(clk)
Line 146: Line 145:
 
Count <=Count-1;
 
Count <=Count-1;
 
else
 
else
Count<=2*1000*1000;
+
Count<=200*1000*1;
  +
data<=data+1;
 
--for i in 0 to 3 loop
 
--for i in 0 to 3 loop
 
-- tmp(i*8 + 7 downto i*8) <= keydata(i);
 
-- tmp(i*8 + 7 downto i*8) <= keydata(i);
Line 156: Line 156:
 
--tmp(15 downto 8) <= keydata(2);
 
--tmp(15 downto 8) <= keydata(2);
 
--tmp(7 downto 0) <= keydata(3);
 
--tmp(7 downto 0) <= keydata(3);
tmp(23 downto 0)<=std_logic_vector(to_unsigned(data+1,24));
+
--tmp(23 downto 0)<=std_logic_vector(to_unsigned(data+1,24));
tmp(31 downto 24) <= keybyte;
+
--tmp(7 downto 0) <= keybyte;
  +
--tmp(15 downto 8) <= keybyte;
data<=to_integer(unsigned(tmp));
 
+
--tmp(23 downto 16) <= keybyte;
  +
--tmp(31 downto 24) <= keybyte;
 
--data<=to_integer(unsigned(tmp));
  +
decdata<=to_integer(to_bcd(bitarray(std_logic_vector(to_unsigned(data,20)))));
  +
key_int <= to_integer((unsigned(keybyte)));
 
for i in 0 to 7 loop
 
for i in 0 to 7 loop
 
leds(i)(0)<=keybyte(i);
 
leds(i)(0)<=keybyte(i);
--leds(i)(0)<='0';
 
 
leds(i)(1)<='0';
 
leds(i)(1)<='0';
 
end loop;
 
end loop;
Line 188: Line 191:
   
 
entity dx_display is
 
entity dx_display is
  +
Generic(clkDivider: integer);
 
PORT(
 
PORT(
 
clk : IN std_logic;
 
clk : IN std_logic;
Line 198: Line 202:
 
);
 
);
 
end dx_display;
 
end dx_display;
 
 
architecture Behavioral of dx_display is
 
architecture Behavioral of dx_display is
signal counter : std_logic_vector(5 downto 0) := (others => '0');
+
signal counter : integer range 0 to 31 :=0;--std_logic_vector(5 downto 0) := (others => '0');
 
signal counterPreClk:std_logic:='0';
 
signal counterPreClk:std_logic:='0';
 
signal counterClk: std_logic:='0';
 
signal counterClk: std_logic:='0';
signal nextcounter : unsigned(counter'range);
+
signal nextcounter : integer range 0 to 31; --unsigned(counter'range);
 
signal byte : std_logic_vector(7 downto 0);
 
signal byte : std_logic_vector(7 downto 0);
 
 
Line 213: Line 216:
 
signal resetCount : integer range 0 to 32*1000*1000 :=1*100-1;
 
signal resetCount : integer range 0 to 32*1000*1000 :=1*100-1;
 
signal keydataone : std_logic_vector(7 downto 0);
 
signal keydataone : std_logic_vector(7 downto 0);
constant headersize: integer := 9;
+
constant headersize: integer := 8;
 
COMPONENT dx_display_xmit
 
COMPONENT dx_display_xmit
  +
Generic(clkDivider: integer);
 
Port (
 
Port (
 
clk : in STD_LOGIC;
 
clk : in STD_LOGIC;
Line 230: Line 234:
 
 
 
begin
 
begin
nextcounter <= unsigned(counter) + 1;
+
--nextcounter <= unsigned(counter) + 1;
  +
nextcounter <= counter +1;
 
Inst_dx_display_xmit: dx_display_xmit PORT MAP(
+
Inst_dx_display_xmit: dx_display_xmit
  +
Generic Map(clkDivider => clkDivider)
  +
PORT MAP(
 
clk => clk,
 
clk => clk,
 
reset => reset,
 
reset => reset,
Line 251: Line 257:
 
newData<='1';
 
newData<='1';
 
case counter is
 
case counter is
when "000000" => byte <= x"00"; endCmd <= '1';
+
--when "000000" => byte <= x"00"; endCmd <= '1';
when "000001" => byte <= x"46"; endCmd <= '0';
+
when 0 => byte <= x"46"; endCmd <= '0';
when "000010" => byte <= x"00"; endCmd <= '0'; send<='0';
+
when 1 => byte <= x"00"; endCmd <= '0'; send<='0';
when "000011" => byte <= x"00"; endCmd <= '0'; send<='0';
+
when 2 => byte <= x"00"; endCmd <= '0'; send<='0';
 
keybyte(0)<=keydataone(0);
 
keybyte(0)<=keydataone(0);
 
keybyte(4)<=keydataone(4);
 
keybyte(4)<=keydataone(4);
when "000100" => byte <= x"00"; endCmd <= '0'; send<='0';
+
when 3 => byte <= x"00"; endCmd <= '0'; send<='0';
 
keybyte(1)<=keydataone(0);
 
keybyte(1)<=keydataone(0);
 
keybyte(5)<=keydataone(4);
 
keybyte(5)<=keydataone(4);
when "000101" => byte <= x"00"; endCmd <= '1'; send<='0';
+
when 4 => byte <= x"00"; endCmd <= '1'; send<='0';
 
keybyte(2)<=keydataone(0);
 
keybyte(2)<=keydataone(0);
 
keybyte(6)<=keydataone(4);
 
keybyte(6)<=keydataone(4);
when "000110" => byte <= x"40"; endCmd <= '1'; -- Set address mode - auto inc
+
when 5 => byte <= x"40"; endCmd <= '1'; -- Set address mode - auto inc
 
keybyte(3)<=keydataone(0);
 
keybyte(3)<=keydataone(0);
 
keybyte(7)<=keydataone(4);
 
keybyte(7)<=keydataone(4);
when "000111" => byte <= x"88"; endCmd <= '1'; -- Turn display on, lowest brightness (0)
+
when 6 => byte <= x"88"; endCmd <= '1'; -- Turn display on, lowest brightness (0)
when "001000" => byte <= x"C0"; endCmd <= '0';-- Write at the left display
+
when 7 => byte <= x"C0"; endCmd <= '0';-- Write at the left display
 
 
 
when others =>
 
when others =>
if unsigned(counter) <= 15+headersize then
+
if counter <= 15+headersize then
if counter(0)='1' then
+
if to_unsigned(counter,1)(0)='0' then
byte<=digits((to_integer(unsigned(counter))-headersize)/2);
+
byte<=digits((counter-headersize)/2);
 
else
 
else
byte<=leds((to_integer(unsigned(counter))-headersize)/2);
+
byte<=leds((counter-headersize)/2);
 
end if;
 
end if;
if unsigned(counter) < 15+headersize then
+
if counter < 15+headersize then
 
endCmd<='0';
 
endCmd<='0';
 
else
 
else
Line 293: Line 299:
 
counterPreClk<='0';
 
counterPreClk<='0';
 
if reset = '1' then
 
if reset = '1' then
counter <= "111111";
+
counter <= 31;
elsif counter ="111111" then
+
elsif counter =31 then
 
counterPreClk<='1';
 
counterPreClk<='1';
counter <= "000000";
+
counter <= 0;
elsif adv = '1' and counter /= "111111" then
+
elsif adv = '1' and counter < 31 then
 
counterPreClk<='1';
 
counterPreClk<='1';
counter <= std_logic_vector(nextcounter);
+
counter <= nextcounter;
 
end if;
 
end if;
 
end if;
 
end if;
Line 315: Line 321:
 
resetCount <=resetCount-1;
 
resetCount <=resetCount-1;
 
else
 
else
resetCount<=200*1000;
+
resetCount<=1*100*1000;
 
reset<= not reset;
 
reset<= not reset;
 
end if;
 
end if;
Line 334: Line 340:
   
 
entity dx_display_xmit is
 
entity dx_display_xmit is
  +
Generic (clkDivider: integer);
 
Port (
 
Port (
 
clk : in STD_LOGIC;
 
clk : in STD_LOGIC;
Line 345: Line 352:
 
d_strobe : out STD_LOGIC;
 
d_strobe : out STD_LOGIC;
 
d_clk : out STD_LOGIC;
 
d_clk : out STD_LOGIC;
d_data : inout STD_LOGIC
+
d_data : inout STD_LOGIC);
--LED1 : out std_logic
 
);
 
 
end dx_display_xmit;
 
end dx_display_xmit;
   
Line 354: Line 359:
 
signal bitsLeftToSend : std_logic_vector(6 downto 0) := (others => '0');
 
signal bitsLeftToSend : std_logic_vector(6 downto 0) := (others => '0');
 
signal state : std_logic_vector(3 downto 0) := (others => '0');
 
signal state : std_logic_vector(3 downto 0) := (others => '0');
--signal divider : integer range 0 downto 2048 := 0;
+
signal divider : integer range 0 to 1023 := 0;
signal divider : std_logic_vector(63 downto 0) := (63=>'1', others =>'0');
 
 
signal keydataLocal : std_logic_vector(keydata'range);
 
signal keydataLocal : std_logic_vector(keydata'range);
 
begin
 
begin
Line 361: Line 365:
 
begin
 
begin
 
if rising_edge(clk) then
 
if rising_edge(clk) then
--divider <= divider +1;
+
divider <= divider +1;
divider <= divider(0) & divider(divider'left downto 1);
 
 
adv <= '0';
 
adv <= '0';
 
if reset = '1' then
 
if reset = '1' then
 
thisByte <= (others => '0');
 
thisByte <= (others => '0');
--thisEndCmd <= endCmd;
 
 
state <= (others => '0');
 
state <= (others => '0');
 
d_strobe <= '1';
 
d_strobe <= '1';
 
d_clk <= '1';
 
d_clk <= '1';
 
d_data <= '1';
 
d_data <= '1';
--divider <= 0;
+
divider <= 0;
divider <= (divider'left=>'1', others =>'0');
+
elsif divider = (clkDivider-1) then
--elsif divider = 63 then
+
divider <= 0;
-- divider <= 0;
 
elsif divider(0) = '1' then
 
 
d_strobe <= '1';
 
d_strobe <= '1';
 
d_clk <= '1';
 
d_clk <= '1';
Line 481: Line 481:
 
 
 
--11515/9563=1.204120046010666; log(16)/log(10) = 1.2041199826559246
 
--11515/9563=1.204120046010666; log(16)/log(10) = 1.2041199826559246
variable bcd : unsigned((11515*(bin'left+1))/9563-1 downto 0) := (others => '0');
+
--(11515*i+9563*4-1)/(9563*4)*4
  +
variable bcd : unsigned(4*((11515*(bin'left+1)+9563*4-1)/(9563*4))-1 downto 0) := (others => '0');
 
variable bint : bitarray(bin'range):=bin;
 
variable bint : bitarray(bin'range):=bin;
 
variable i : integer:=0;
 
variable i : integer:=0;
Line 497: Line 498:
 
return bcd;
 
return bcd;
 
end to_bcd;
 
end to_bcd;
end package body;</nowiki>
+
end package body;
  +
</nowiki>
   
 
=See Also=
 
=See Also=

Latest revision as of 18:17, 20 May 2013

Documents

Hamsterworks code

I'm using the VHDL code from Hamster on my papilio board, and it works. Thanks Hamsterworks!

Looks like the pinning of the DX display cable as described by Hamster has changed (or was wrong). The silkscreen on my (ordered october 2011) DX display looks like this (this is the 'bottom view', the pins of the socket as seen from above are the mirror-image of this):

pin func func pin
2 Gnd Vcc 1
4 DIO CLK 3
6 STB1 STB0 5
8 STB3 STB2 7
10 STB5 STB4 9

So it looks like hamster's pinning has DIO/Data and CLK swapped, and the even Strobes were off by 2. Also, it's Strobe0 that controls this board (not Strobe1), the other strobes pass through to the 'out' connector.

I notice that after I power cycle (powered by USB cable) my papilio board (and the TM1638), I have to send the .bit file several times to the board. Strange.

  • When setting d_clock to 32MHz/8/2, it always works the first time.
  • Setting d_clock to 32MHz/4/2, it will not work at all

I'm using this constraints.ucf file for my papilio board:

# Crystal Clock - use 32MHz onboard oscillator
NET "clk" LOC = "P89" | IOSTANDARD = LVCMOS25 | PERIOD = 31.25ns ;

NET "d_data"   LOC = "P86" | IOSTANDARD=LVCMOS33; 
NET "d_clk"    LOC = "P85" | IOSTANDARD=LVCMOS33; 
NET "d_strobe" LOC = "P84" | IOSTANDARD=LVCMOS33; 

But other than that, Hamsters code works.

Commands

bits Description
010000000 setup TM1638 to write data to display register, auto increment
010000010 setup TM 1638 to read data from key scans, auto increment
010000100 setup TM 1638 to write data to display register, single address
010000010 setup TM 1638 to read data from key scans, single address
1100aaaa dddddddd At address aaaa write/read dddddddd - multiple bytes of data can be transferred
1000abbb Display control - a = active, bbb = brightness

After sending 46 the responce will be 4 bytes, key one is in bit zero (LSB) of the first byte, key two is in bit one of the second byte, etc. key 5 is in bit 4 of the first byte, key 6 in bit 4 of the second byte, etc.

VHDL code for numeric data display

The code below can read the TM1638 key status, and show hex and decimal numbers on the display.

File design_top.vhdl

---------------------------------------------------------------------------------
-- Original by: Engineer: Mike Field <hamster@snap.net.nz>
-- Modifications by: Joost Witteveen
--
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
library work;
use work.types.all;

entity design_top is
  Port ( clk      : in  STD_LOGIC;
         d_clk    : out  STD_LOGIC;
         d_strobe : out  STD_LOGIC;
         d_data   : inout  STD_LOGIC);
end design_top;

architecture Behavioral of design_top is

  COMPONENT dx_display
  Generic(clkDivider: integer);
    PORT(
      clk     : IN std_logic;
      d_strobe : OUT std_logic;
      d_clk    : OUT std_logic;
      d_data   : inOUT std_logic;
      digits   : in bytearray(0 to 7);
      leds     : in bytearray(0 to 7);
      keybyte  : out std_logic_vector(7 downto 0)
      );
  END COMPONENT;

  
  COMPONENT display7seg
    PORT (digits  : out bytearray;
          data    : in integer
	  );
  end COMPONENT;
  signal Count : integer range 0 to 34*1000*1000 :=1000*1000-1;
  signal digits: bytearray(0 to 7) := (others => x"00");
  signal leds: bytearray(0 to 7)   := (others => x"00");   
  signal data: integer range -2000000000 to 2000000000 :=0;--20000/3;
  signal decdata: integer range -2000000000 to 2000000000 :=0;--20000/3;
  signal tmp: std_logic_vector(31 downto 0);
  signal keybyte: std_logic_vector(7 downto 0);
  signal key_int:integer range 0 to 255;
begin
  Inst_dx_display: dx_display 
    Generic Map(clkDivider => 16)
    PORT MAP(
      clk      => clk,
      d_strobe => d_strobe,
      d_clk    => d_clk,
      d_data   => d_data,
      digits   => digits,
      leds     => leds,
      keybyte  => keybyte
      );

  Inst_display7seg:display7seg 
    PORT MAP(
      digits => digits(0 to 1),
      data   => key_int);
  
  Inst_display7segDec:display7seg 
    PORT MAP(
      digits => digits(2 to 7),
      data   => decdata);
  
  reset_proc: process(clk)
  begin
    if rising_edge(clk) then
      if Count > 0 then
        Count <=Count-1;
      else
        Count<=200*1000*1;
        data<=data+1;
        --for i in 0 to 3 loop
        --  tmp(i*8 + 7 downto i*8) <= keydata(i);
        --end loop;
                --decdata<=decdata+1;
        --tmp1<=std_logic_vector(to_unsigned(data,8));
        --tmp(31 downto 24) <= keydata(0);
        --tmp(23 downto 16) <= keydata(1);
        --tmp(15 downto 8) <= keydata(2);
        --tmp(7 downto 0) <= keydata(3);
        --tmp(23 downto 0)<=std_logic_vector(to_unsigned(data+1,24));
        --tmp(7 downto 0) <= keybyte;
        --tmp(15 downto 8) <= keybyte;       
        --tmp(23 downto 16) <= keybyte;
        --tmp(31 downto 24) <= keybyte;
        --data<=to_integer(unsigned(tmp));
        decdata<=to_integer(to_bcd(bitarray(std_logic_vector(to_unsigned(data,20)))));
        key_int <= to_integer((unsigned(keybyte)));
        for i in 0 to 7 loop
          leds(i)(0)<=keybyte(i);
          leds(i)(1)<='0';
        end loop;
      end if;
    end if;
  end process;
end Behavioral;

File dx_display.vhdl

----------------------------------------------------------------------------------
-- Original by: Engineer: Mike Field <hamster@snap.net.nz>
-- Modifications by: Joost Witteveen
-- 
-- Description:  Driver for the DealExteme display board, TM1638
--  8 x 7 segs
--  8 x bi-colour LED
--  8 x buttons
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
library work;
use work.types.all;

entity dx_display is
  Generic(clkDivider: integer);
  PORT(
    clk     : IN std_logic;
    d_strobe: OUT std_logic;
    d_clk   : OUT std_logic;
    d_data  : inOUT std_logic;
    digits  : in bytearray(0 to 7);
    leds    : in bytearray(0 to 7);
    keybyte : out std_logic_vector(7 downto 0)
    );
end dx_display;
architecture Behavioral of dx_display is
  signal counter : integer range 0 to 31 :=0;--std_logic_vector(5 downto 0) := (others => '0');
  signal counterPreClk:std_logic:='0';
  signal counterClk: std_logic:='0';
  signal nextcounter : integer range  0 to 31; --unsigned(counter'range);
  signal byte       : std_logic_vector(7 downto 0);
  
  signal endCmd   : std_logic;
  signal newData  : std_logic;
  signal send     : std_logic;
  signal adv      : std_logic;
  signal reset    : std_logic := '1';
  signal resetCount : integer range 0 to 32*1000*1000 :=1*100-1;
  signal keydataone : std_logic_vector(7 downto 0);
  constant headersize: integer := 8;
  COMPONENT dx_display_xmit
    Generic(clkDivider: integer);
    Port (
      clk      : in  STD_LOGIC;
      reset    : in  STD_LOGIC;
      byte     : in  STD_LOGIC_VECTOR (7 downto 0);
      keydata  : inout  STD_LOGIC_VECTOR (7 downto 0);
      endCmd   : in  STD_LOGIC;
      newData  : in  STD_LOGIC;
      send     : in  STD_LOGIC;
      adv      : out STD_LOGIC;
      d_strobe : out STD_LOGIC;
      d_clk    : out STD_LOGIC;
      d_data   : inout STD_LOGIC);
  end component;
  
begin
  --nextcounter <= unsigned(counter) + 1;
  nextcounter <= counter +1;
  Inst_dx_display_xmit: dx_display_xmit 
  Generic Map(clkDivider => clkDivider)
  PORT MAP(
    clk       => clk,
    reset     => reset,
    byte      => byte,
    keydata   => keydataone,
    endCmd    => endCmd,
    newData   => newData,
    send      => send,
    adv       => adv,
    d_strobe  => d_strobe,
    d_clk     => d_clk,
    d_data    => d_data);
  
  data_proc: process(counterClk)
  begin
    if counterClk'event and counterClk='1' then
      send<= '1';
      newData<='1';
      case counter is
        --when  "000000" => byte <= x"00"; endCmd <= '1';	
        when  0 => byte <= x"46"; endCmd <= '0';   
        when  1 => byte <= x"00"; endCmd <= '0'; send<='0'; 
        when  2 => byte <= x"00"; endCmd <= '0'; send<='0'; 
           keybyte(0)<=keydataone(0);
           keybyte(4)<=keydataone(4);
        when  3 => byte <= x"00"; endCmd <= '0'; send<='0'; 
           keybyte(1)<=keydataone(0);
           keybyte(5)<=keydataone(4);
        when  4 => byte <= x"00"; endCmd <= '1'; send<='0';
           keybyte(2)<=keydataone(0);
           keybyte(6)<=keydataone(4);
        when  5 => byte <= x"40"; endCmd <= '1'; -- Set address mode - auto inc
           keybyte(3)<=keydataone(0);
           keybyte(7)<=keydataone(4);        
        when  6 => byte <= x"88"; endCmd <= '1';	-- Turn display on, lowest brightness (0)
        when  7 => byte <= x"C0"; endCmd <= '0';-- Write at the left display
                         
        when  others => 
          if counter <= 15+headersize then
            if to_unsigned(counter,1)(0)='0' then
              byte<=digits((counter-headersize)/2);
            else
              byte<=leds((counter-headersize)/2);
            end if;
            if counter < 15+headersize then
              endCmd<='0';
            else
              endCmd<='1';
            end if;
          else
            byte <= x"FF"; endCmd <= '1'; newData <= '0';				 -- End of data / idle
          end if;
      end case;
    end if;
  end process;
  
  clk_proc: process(clk)
  begin
    if rising_edge(clk) then
      counterPreClk<='0';
      if reset = '1' then 
        counter <= 31;
      elsif counter =31 then
        counterPreClk<='1';
        counter <= 0;
      elsif adv = '1' and counter < 31 then
        counterPreClk<='1';
        counter <= nextcounter;
      end if;
    end if;
  end process;
  counterClk_proc:process(clk)
  begin
    if rising_edge(clk) then
      counterClk<=counterPreClk;
    end if;
  end process;
  reset_proc: process(clk)
  begin
    if rising_edge(clk) then
      if resetCount > 0 then
        resetCount <=resetCount-1;
      else
        resetCount<=1*100*1000;
        reset<= not reset;
      end if;
    end if;
  end process;
end Behavioral;

File dx_display_xmit.vhdl

----------------------------------------------------------------------------------
-- Engineer: Mike Field <hamster@snap.net.nz>
-- Modified by: Joost Witteveen
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity dx_display_xmit is
  Generic (clkDivider: integer);
  Port (
    clk      : in  STD_LOGIC;
    reset    : in  STD_LOGIC;
    byte     : in  STD_LOGIC_VECTOR (7 downto 0);
    keydata  : out STD_LOGIC_VECTOR (7 downto 0);
    endCmd   : in  STD_LOGIC;
    newData  : in  STD_LOGIC;
    send     : in  STD_LOGIC;
    adv      : out STD_LOGIC;
    d_strobe : out STD_LOGIC;
    d_clk    : out STD_LOGIC;
    d_data   : inout STD_LOGIC);
end dx_display_xmit;

architecture Behavioral of dx_display_xmit is
  signal thisByte       : std_logic_vector(7 downto 0)  := (others => '0');
  signal bitsLeftToSend : std_logic_vector(6 downto 0)  := (others => '0');
  signal state          : std_logic_vector(3 downto 0)  := (others => '0');
  signal divider        : integer range 0 to 1023 := 0;
  signal keydataLocal   : std_logic_vector(keydata'range);
begin
  clk_proc: process(clk)
  begin
    if rising_edge(clk) then
      divider <= divider +1;
      adv      <= '0';   
      if reset = '1'  then
        thisByte   <= (others => '0');
        state      <= (others => '0');
        d_strobe <= '1';
        d_clk    <= '1';
        d_data   <= '1';
        divider  <= 0;
      elsif divider = (clkDivider-1) then
        divider  <= 0;
        d_strobe <= '1';
        d_clk    <= '1';
        if send = '1' then
          d_data  <= '1';
        else
          d_data  <='Z';
        end if;
        case state is 
          when "0000" =>      -- Idle, without an open command
            if newData  = '1' then
              state     <= std_logic_vector(unsigned(state)+1);
              thisByte  <= byte;
              d_strobe  <= '0';
              d_clk     <= '1';
            else
              d_strobe  <= '1';
              d_clk     <= '1';
            end if;
            bitsLeftToSend <= (others => '1');
            keydatalocal<=x"55";
          when "0001" =>   -- transfer a bit					
            state    <= std_logic_vector(unsigned(state)+1);
            d_strobe <= '0';
            d_clk    <= '0';
            if send = '1' then
              d_data   <= thisByte(0);
            end if;
          when "0010" =>					
            if bitsLeftToSend(0) = '1' then -- Still got a bit to send?
              state    <= std_logic_vector(unsigned(state)-1);
            else
              if send = '0' then
               keydata <= d_data & keydatalocal(7 downto 1);                
              end if;
              adv       <= '1';
              if EndCmd = '1' then
                state    <= "0011";   -- close off command
              else
                state    <= "0100";   -- keep command open
              end if;
            end if;
            d_strobe <= '0';
            d_clk    <= '1';
            if send = '1' then            
              d_data   <= thisByte(0);
              thisByte <= '1' & thisByte(7 downto 1);
            else
              keydatalocal <= d_data & keydatalocal(7 downto 1);
            end if;
            bitsLeftToSend <= '0' & bitsLeftToSend(6 downto 1);
          when "0011" => --- ending the command by rasing d_strobe, then going back to idle state
            state    <= "0000";
            d_strobe <= '1';
            d_clk    <= '1';
            if send = '1' then                        
              d_data   <= thisByte(0);
            else
              keydata <= keydatalocal;
            end if;
          when "0100" =>      -- Waiting for data, with an open command
            d_strobe <= '0';
            d_clk    <= '1';

            if newData = '1' then
              state      <= "0001"; -- start transfering bits
              thisByte   <= byte;
              bitsLeftToSend <= (others => '1');
            end if;
          when others =>      -- performa a reset
            thisByte <= (others => '0');
            state    <= (others => '0');
            d_strobe <= '1';
            d_clk    <= '1';
        end case;
      end if;
    end if;
  end process;
end Behavioral;

And finally, the file types.vhdl, with the to_bdc function and the type declarations:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

package types is
  type digitdata is array (0 to 15) of STD_LOGIC_VECTOR(7 downto 0);
  type bytearray is array (integer range <>) of STD_LOGIC_VECTOR(7 downto 0);
  type bitarray is array (integer range <>) of STD_LOGIC;
  function to_bcd ( bin : bitarray ) return unsigned;
end package;

package body types is


  function to_bcd ( bin : bitarray ) return unsigned is
    --http://stackoverflow.com/questions/12951759/how-to-decode-an-unsigned-integer-into-bcd-use-vhdl
    --(c)2012 Enthusiasticgeek for Stack Overflow. 
    --Use at your own risk (includes commercial usage). 
    --These functions are released in the public domain and 
    --free to use as long as this copyright notice is retained.
    --adapted for variable-length inputs by joost witteveen.

    
    --11515/9563=1.204120046010666; log(16)/log(10) = 1.2041199826559246
    --(11515*i+9563*4-1)/(9563*4)*4
    variable bcd : unsigned(4*((11515*(bin'left+1)+9563*4-1)/(9563*4))-1 downto 0) := (others => '0');
    variable bint : bitarray(bin'range):=bin;
    variable i : integer:=0;
  begin 
    for i in bint'REVERSE_RANGE loop  
      bcd := bcd(bcd'left-1 downto 0) & bint(bint'left);  --shifting the bits.
      bint := bint((bint'left-1) downto 0)& '0';
      
      for ibcd in 0 to (bcd'left+1)/4-1 loop
        if(i < bin'left and bcd(ibcd*4+3 downto ibcd*4) > "0100") then --add 3 if BCD digit is greater than 4.
          bcd(ibcd*4+3 downto ibcd*4) := bcd(ibcd*4+3 downto ibcd*4) + "0011";
        end if;
      end loop;    
    end loop;
    return bcd;
  end to_bcd;
end package body;

See Also