Difference between revisions of "DX TM1638 Display"

From Tech
Jump to navigationJump to search
Line 60: Line 60:
 
|}
 
|}
   
  +
=VHDL code for numeric data display=
  +
File <tt>design_top.vhdl</tt>:
  +
<nowiki>----------------------------------------------------------------------------------
  +
-- 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 : out STD_LOGIC;
  +
LED1 : out STD_LOGIC);
  +
end design_top;
  +
  +
architecture Behavioral of design_top is
  +
  +
COMPONENT dx_display
  +
PORT(
  +
clk : IN std_logic;
  +
d_strobe : OUT std_logic;
  +
d_clk : OUT std_logic;
  +
d_data : OUT std_logic;
  +
LED1 : out std_logic;
  +
digits : in bytearray(0 to 15)
  +
);
  +
END COMPONENT;
  +
  +
COMPONENT display7seg
  +
generic(
  +
endDigit: integer);
  +
PORT (digits : out bytearray(0 to endDigit);
  +
data : in integer
  +
);
  +
end COMPONENT;
  +
signal Count : integer range 0 to 32*1000*1000 :=1000*1000-1;
  +
signal digits: bytearray(0 to 15) := (others => x"00");
  +
signal data: integer range 0 to 1000000 :=0;
  +
signal decdata: integer range 0 to 1024*1024-1 :=0;
  +
begin
  +
Inst_dx_display: dx_display
  +
PORT MAP(
  +
clk => clk,
  +
d_strobe => d_strobe,
  +
d_clk => d_clk,
  +
d_data => d_data,
  +
LED1 => LED1,
  +
digits => digits
  +
);
  +
  +
  +
Inst_display7seg:display7seg
  +
generic map(
  +
endDigit=>7)
  +
PORT MAP(
  +
digits => digits(0 to 7),
  +
data => decdata);
  +
  +
Inst_display7segDec:display7seg
  +
generic map(
  +
endDigit=>5)
  +
PORT MAP(
  +
digits => digits(10 to 15),
  +
data => data);
  +
  +
reset_proc: process(clk)
  +
begin
  +
if rising_edge(clk) then
  +
if Count > 0 then
  +
Count <=Count-1;
  +
else
  +
Count<=1*1000*1000;
  +
data<=data+1;
  +
decdata<=to_integer(to_bcd(bitarray(to_unsigned(data+1,12))));
  +
if data>=4095 then
  +
data<=0;
  +
end if;
  +
end if;
  +
end if;
  +
end process;
  +
end Behavioral;</nowiki>
  +
  +
File <tt>dx_display.vhdl</tt>:
  +
<nowiki>----------------------------------------------------------------------------------
  +
-- 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
  +
PORT(
  +
clk : IN std_logic;
  +
d_strobe : OUT std_logic;
  +
d_clk : OUT std_logic;
  +
d_data : OUT std_logic;
  +
LED1 : out std_logic;
  +
digits : in bytearray(0 to 15)
  +
);
  +
end dx_display;
  +
  +
architecture Behavioral of dx_display is
  +
signal counter : std_logic_vector(4 downto 0) := (others => '0');
  +
signal nextcounter : unsigned(4 downto 0);
  +
signal byte : std_logic_vector(7 downto 0);
  +
signal endCmd : std_logic;
  +
signal newData : std_logic;
  +
signal adv : std_logic;
  +
signal reset : std_logic := '1';
  +
signal resetCount : integer range 0 to 32*1000*1000 :=1000*1000-1;
  +
COMPONENT dx_display_xmit
  +
Port ( clk : in STD_LOGIC;
  +
reset : in STD_LOGIC;
  +
byte : in STD_LOGIC_VECTOR (7 downto 0);
  +
endCmd : in STD_LOGIC;
  +
newData : in STD_LOGIC;
  +
adv : out STD_LOGIC;
  +
d_strobe : out STD_LOGIC;
  +
d_clk : out STD_LOGIC;
  +
d_data : out STD_LOGIC;
  +
LED1 : out std_logic);
  +
end component;
  +
  +
begin
  +
nextcounter <= unsigned(counter) + 1;
  +
  +
Inst_dx_display_xmit: dx_display_xmit PORT MAP(
  +
clk => clk,
  +
reset => reset,
  +
byte => byte,
  +
endCmd => endCmd,
  +
newData => newData,
  +
adv => adv,
  +
d_strobe => d_strobe,
  +
d_clk => d_clk,
  +
d_data => d_data,
  +
LED1 => LED1
  +
);
  +
  +
data_proc: process(counter)
  +
begin
  +
case counter is
  +
when "00000" => byte <= x"40"; endCmd <= '1'; newData <= '1'; -- Set address mode - auto inc
  +
when "00001" => byte <= x"88"; endCmd <= '1'; newData <= '1'; -- Turn display on, brightness 4 of 7
  +
when "00010" => byte <= x"C0"; endCmd <= '0'; newData <= '1'; -- Write at the left display
  +
  +
when others =>
  +
if unsigned(counter) <= 18 then
  +
byte<=digits(to_integer(unsigned(counter))-3);
  +
newData<='1';
  +
if unsigned(counter) < 18 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 process;
  +
  +
clk_proc: process(clk)
  +
begin
  +
if rising_edge(clk) then
  +
if reset = '1' then
  +
counter <= (others => '0');
  +
elsif adv = '1' and counter /= "11111" then
  +
counter <= std_logic_vector(nextcounter);
  +
end if;
  +
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;</nowiki>
  +
  +
File <tt>dx_display_xmit.vhdl</tt>
  +
<nowiki>
  +
library IEEE;
  +
use IEEE.STD_LOGIC_1164.ALL;
  +
use IEEE.NUMERIC_STD.ALL;
  +
  +
library work;
  +
use work.types.all;
  +
  +
entity display7seg is
  +
generic(
  +
endDigit: positive:= 15);
  +
Port (digits : out bytearray(0 to endDigit);
  +
data : in integer);
  +
end display7seg;
  +
  +
architecture Behavioral of display7seg is
  +
signal digitshapes: digitdata :=
  +
(x"3F", --0
  +
x"06", --1
  +
x"5b", --2
  +
x"4f", --3
  +
x"66", --4
  +
x"6d", --5
  +
x"7d", --6
  +
x"07", --7
  +
x"7f", --8
  +
x"6f", --9
  +
x"77", --A
  +
x"7c", --b
  +
x"39", --C
  +
x"5e", --d
  +
x"79", --E
  +
x"71" --F
  +
);
  +
signal vdata: std_logic_vector(64 downto 0);
  +
begin
  +
data_proc: process(data)
  +
begin
  +
vdata<=std_logic_vector(to_unsigned(data, 32));
  +
for i in digits'left/2 to digits'right/2 loop
  +
digits((digits'right/2-i)*2)<=
  +
digitshapes(to_integer(unsigned(vdata((i*4+3) downto i*4))));
  +
end loop;
  +
end process;
  +
end Behavioral;</nowiki>
  +
  +
And finally, the file <tt>types.vhdl</tt>, with the to_bdc function and the type declarations:
  +
<nowiki>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
  +
variable bcd : unsigned((11515*(bin'left+1))/9563-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;</nowiki>
 
=See Also=
 
=See Also=
 
* [[FPGA]]
 
* [[FPGA]]

Revision as of 00:30, 1 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 write data to display register, auto increment
010000010 read data from key scans, auto increment
010000100 write data to display register, single address
010000010 read data from key scans, single address
1100aaaa dddddddd At address aaaa write dddddddd - multiple bytes of data can be transferred
1000abbb Display control - a = active, bbb = brightness

VHDL code for numeric data 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   : out  STD_LOGIC;
			  LED1     : out  STD_LOGIC);
end design_top;

architecture Behavioral of design_top is

   COMPONENT dx_display
   PORT(
      clk     : IN std_logic;
      d_strobe : OUT std_logic;
      d_clk    : OUT std_logic;
      d_data   : OUT std_logic;
		LED1     : out std_logic;	
		digits  : in bytearray(0 to 15)
      );
   END COMPONENT;
	
   COMPONENT display7seg
	  generic(
			endDigit: integer);
	  PORT (digits  : out bytearray(0 to endDigit);
			  data    : in integer
	  );
	end COMPONENT;
   signal Count : integer range 0 to 32*1000*1000 :=1000*1000-1;
   signal digits: bytearray(0 to 15) :=   (others => x"00");		 
	signal data: integer range 0 to 1000000 :=0;
	signal decdata: integer range 0 to 1024*1024-1 :=0;
begin
   Inst_dx_display: dx_display 
	PORT MAP(
      clk     => clk,
		d_strobe  => d_strobe,
		d_clk     => d_clk,
		d_data    => d_data,
		LED1      => LED1,
		digits   => digits
   );


	Inst_display7seg:display7seg 
	generic map(
		endDigit=>7)
	PORT MAP(
		digits => digits(0 to 7),
		data   => decdata);
		
	Inst_display7segDec:display7seg 
	generic map(
		endDigit=>5)
	PORT MAP(
		digits => digits(10 to 15),
		data   => data);
				
reset_proc: process(clk)
   begin
      if rising_edge(clk) then
			if Count > 0 then
           Count <=Count-1;
			else
			  Count<=1*1000*1000;
           data<=data+1;
		     decdata<=to_integer(to_bcd(bitarray(to_unsigned(data+1,12))));
			  if data>=4095 then
			    data<=0;				 
			  end if;
         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
   PORT(
      clk     : IN std_logic;
      d_strobe : OUT std_logic;
      d_clk    : OUT std_logic;
      d_data   : OUT std_logic;
		LED1     : out std_logic;	
		digits  : in bytearray(0 to 15)
      );
end dx_display;

architecture Behavioral of dx_display is
   signal counter : std_logic_vector(4 downto 0) := (others => '0');
   signal nextcounter : unsigned(4 downto 0);
   signal byte       : std_logic_vector(7 downto 0);
   signal endCmd   : std_logic;
   signal newData  : std_logic;
   signal adv        : std_logic;
   signal reset    : std_logic := '1';
   signal resetCount : integer range 0 to 32*1000*1000 :=1000*1000-1;
   COMPONENT dx_display_xmit
    Port ( clk      : in  STD_LOGIC;
           reset    : in  STD_LOGIC;
           byte     : in  STD_LOGIC_VECTOR (7 downto 0);
           endCmd   : in  STD_LOGIC;
           newData  : in  STD_LOGIC;
           adv      : out STD_LOGIC;
           d_strobe : out STD_LOGIC;
           d_clk    : out STD_LOGIC;
           d_data   : out STD_LOGIC;
			  LED1     : out std_logic);
	end component;
 
begin
   nextcounter <= unsigned(counter) + 1;

Inst_dx_display_xmit: dx_display_xmit PORT MAP(
      clk       => clk,
      reset    => reset,
      byte       => byte,
      endCmd    => endCmd,
      newData    => newData,
      adv       => adv,
		d_strobe  => d_strobe,
		d_clk     => d_clk,
		d_data    => d_data,
		LED1      => LED1
   );
   
data_proc: process(counter)
   begin
      case counter is
         when  "00000" => byte <= x"40"; endCmd <= '1'; newData <= '1';	-- Set address mode - auto inc
         when  "00001" => byte <= x"88"; endCmd <= '1'; newData <= '1';	-- Turn display on, brightness 4 of 7
         when  "00010" => byte <= x"C0"; endCmd <= '0'; newData <= '1';	-- Write at the left display
			
			when  others => 
			  if unsigned(counter) <= 18 then
				 byte<=digits(to_integer(unsigned(counter))-3);
				 newData<='1';
				 if unsigned(counter) < 18 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 process;
   
clk_proc: process(clk)
   begin
      if rising_edge(clk) then
         if reset = '1' then 
            counter <= (others => '0');
         elsif adv = '1' and counter /= "11111" then
            counter <= std_logic_vector(nextcounter);
         end if;
      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

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

library work;
use work.types.all;

entity display7seg is
  generic(
		endDigit: positive:= 15);
  Port (digits  : out bytearray(0 to endDigit);
        data    : in integer);
end display7seg;

architecture Behavioral of display7seg is
   signal digitshapes: digitdata :=  
	   (x"3F",  --0	
		 x"06",  --1
		 x"5b",	--2
		 x"4f",  --3		 
		 x"66",  --4
		 x"6d",  --5
		 x"7d",  --6			 
		 x"07",  --7
		 x"7f",  --8
		 x"6f",  --9
		 x"77",  --A
		 x"7c",  --b
		 x"39",  --C
		 x"5e",  --d
		 x"79",  --E
		 x"71"   --F
		 );  
	signal vdata: std_logic_vector(64 downto 0);
begin   
data_proc: process(data)
  begin
    vdata<=std_logic_vector(to_unsigned(data, 32)); 
    for i in digits'left/2 to digits'right/2 loop
      digits((digits'right/2-i)*2)<=
	  	    digitshapes(to_integer(unsigned(vdata((i*4+3) downto i*4))));
    end loop;			
  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
  variable bcd : unsigned((11515*(bin'left+1))/9563-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