Difference between revisions of "DX TM1638 Display"
| Line 64: | Line 64: | ||
=VHDL code for numeric data display= |
=VHDL code for numeric data display= |
||
| − | File <tt>design_top.vhdl</tt> |
+ | ==File <tt>design_top.vhdl</tt>== |
<nowiki>--------------------------------------------------------------------------------- |
<nowiki>--------------------------------------------------------------------------------- |
||
-- Original by: Engineer: Mike Field <hamster@snap.net.nz> |
-- Original by: Engineer: Mike Field <hamster@snap.net.nz> |
||
-- Modifications by: Joost Witteveen |
-- Modifications by: Joost Witteveen |
||
| + | -- |
||
| + | -- |
||
| + | --TODO: |
||
| + | -- allow specification of d_clk frequency via generics |
||
| + | -- remove compiler warnings |
||
| + | -- 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 79: | Line 86: | ||
d_clk : out STD_LOGIC; |
d_clk : out STD_LOGIC; |
||
d_strobe : out STD_LOGIC; |
d_strobe : out STD_LOGIC; |
||
| − | d_data : |
+ | d_data : inout STD_LOGIC); |
| − | LED1 : out STD_LOGIC); |
||
end design_top; |
end design_top; |
||
| Line 90: | Line 96: | ||
d_strobe : OUT std_logic; |
d_strobe : OUT std_logic; |
||
d_clk : OUT std_logic; |
d_clk : OUT std_logic; |
||
| − | d_data : |
+ | 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; |
END COMPONENT; |
||
| + | |||
COMPONENT display7seg |
COMPONENT display7seg |
||
| + | PORT (digits : out bytearray; |
||
| − | generic( |
||
| − | endDigit: integer); |
||
| − | PORT (digits : out bytearray(0 to endDigit); |
||
data : in integer |
data : in integer |
||
); |
); |
||
end COMPONENT; |
end COMPONENT; |
||
| − | signal Count : integer range 0 to |
+ | signal Count : integer range 0 to 34*1000*1000 :=1000*1000-1; |
| − | signal digits: bytearray(0 to |
+ | signal digits: bytearray(0 to 7) := (others => x"00"); |
| − | signal |
+ | signal leds: bytearray(0 to 7) := (others => x"00"); |
| − | signal |
+ | signal data: integer range -2000000000 to 2000000000 :=0; |
| + | signal tmp: std_logic_vector(31 downto 0); |
||
| + | signal keybyte: std_logic_vector(7 downto 0); |
||
| + | |||
begin |
begin |
||
Inst_dx_display: dx_display |
Inst_dx_display: dx_display |
||
PORT MAP( |
PORT MAP( |
||
| − | clk => clk, |
+ | clk => clk, |
| − | d_strobe |
+ | d_strobe => d_strobe, |
| − | d_clk |
+ | d_clk => d_clk, |
| − | d_data |
+ | d_data => d_data, |
| − | + | digits => digits, |
|
| − | + | leds => leds, |
|
| + | keybyte => keybyte |
||
); |
); |
||
| − | |||
Inst_display7seg:display7seg |
Inst_display7seg:display7seg |
||
| − | generic map( |
||
| − | endDigit=>7) |
||
PORT MAP( |
PORT MAP( |
||
digits => digits(0 to 7), |
digits => digits(0 to 7), |
||
| − | data => |
+ | data => data); |
| − | + | -- Inst_display7segDec:display7seg |
|
| − | + | -- PORT MAP( |
|
| − | + | -- digits => digits(6 to 7), |
|
| + | -- data => decdata); |
||
| − | PORT MAP( |
||
| − | digits => digits(10 to 15), |
||
| − | data => data); |
||
reset_proc: process(clk) |
reset_proc: process(clk) |
||
| Line 139: | Line 144: | ||
Count <=Count-1; |
Count <=Count-1; |
||
else |
else |
||
| − | Count<= |
+ | Count<=2*1000*1000; |
| − | + | --for i in 0 to 3 loop |
|
| + | -- tmp(i*8 + 7 downto i*8) <= keydata(i); |
||
| − | decdata<=to_integer(to_bcd(bitarray(to_unsigned(data+1,12)))); |
||
| − | + | --end loop; |
|
| − | + | --decdata<=decdata+1; |
|
| + | --tmp1<=std_logic_vector(to_unsigned(data,8)); |
||
| − | end if; |
||
| + | --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(31 downto 24) <= keybyte; |
||
| + | data<=to_integer(unsigned(tmp)); |
||
| + | |||
| + | for i in 0 to 7 loop |
||
| + | leds(i)(0)<=keybyte(i); |
||
| + | --leds(i)(0)<='0'; |
||
| + | leds(i)(1)<='0'; |
||
| + | end loop; |
||
end if; |
end if; |
||
end if; |
end if; |
||
end process; |
end process; |
||
| − | end Behavioral; |
+ | end Behavioral; |
| + | </nowiki> |
||
| − | File <tt>dx_display.vhdl</tt> |
+ | ==File <tt>dx_display.vhdl</tt>== |
<nowiki>---------------------------------------------------------------------------------- |
<nowiki>---------------------------------------------------------------------------------- |
||
-- Original by: Engineer: Mike Field <hamster@snap.net.nz> |
-- Original by: Engineer: Mike Field <hamster@snap.net.nz> |
||
| Line 169: | Line 188: | ||
PORT( |
PORT( |
||
clk : IN std_logic; |
clk : IN std_logic; |
||
| − | d_strobe |
+ | d_strobe: OUT std_logic; |
| − | d_clk |
+ | d_clk : OUT std_logic; |
| − | d_data |
+ | 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; |
end dx_display; |
||
architecture Behavioral of dx_display is |
architecture Behavioral of dx_display is |
||
| − | signal counter : std_logic_vector( |
+ | signal counter : std_logic_vector(5 downto 0) := (others => '0'); |
| − | signal |
+ | signal counterPreClk:std_logic:='0'; |
| + | signal counterClk: std_logic:='0'; |
||
| + | signal nextcounter : unsigned(counter'range); |
||
signal byte : std_logic_vector(7 downto 0); |
signal byte : std_logic_vector(7 downto 0); |
||
| + | |||
signal endCmd : std_logic; |
signal endCmd : std_logic; |
||
signal newData : std_logic; |
signal newData : std_logic; |
||
| − | signal |
+ | signal send : std_logic; |
| + | signal adv : std_logic; |
||
signal reset : std_logic := '1'; |
signal reset : std_logic := '1'; |
||
| − | signal resetCount : integer range 0 to 32*1000*1000 := |
+ | signal resetCount : integer range 0 to 32*1000*1000 :=1*100-1; |
| + | signal keydataone : std_logic_vector(7 downto 0); |
||
| + | constant headersize: integer := 9; |
||
COMPONENT dx_display_xmit |
COMPONENT dx_display_xmit |
||
| − | Port ( |
+ | 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; |
end component; |
||
| Line 204: | Line 232: | ||
Inst_dx_display_xmit: dx_display_xmit PORT MAP( |
Inst_dx_display_xmit: dx_display_xmit PORT MAP( |
||
clk => clk, |
clk => clk, |
||
| − | reset => reset, |
+ | reset => reset, |
| − | byte |
+ | byte => byte, |
| + | keydata => keydataone, |
||
endCmd => endCmd, |
endCmd => endCmd, |
||
| − | newData |
+ | newData => newData, |
| + | send => send, |
||
adv => adv, |
adv => adv, |
||
d_strobe => d_strobe, |
d_strobe => d_strobe, |
||
d_clk => d_clk, |
d_clk => d_clk, |
||
| − | d_data => d_data |
+ | d_data => d_data); |
| − | LED1 => LED1 |
||
| − | ); |
||
| − | data_proc: process( |
+ | data_proc: process(counterClk) |
begin |
begin |
||
| + | if counterClk'event and counterClk='1' then |
||
| − | case counter is |
||
| + | send<= '1'; |
||
| − | when "00000" => byte <= x"40"; endCmd <= '1'; newData <= '1'; -- Set address mode - auto inc |
||
| + | newData<='1'; |
||
| − | when "00001" => byte <= x"88"; endCmd <= '1'; newData <= '1'; -- Turn display on, brightness 4 of 7 |
||
| + | case counter is |
||
| − | when "00010" => byte <= x"C0"; endCmd <= '0'; newData <= '1'; -- Write at the left display |
||
| − | + | when "000000" => byte <= x"00"; endCmd <= '1'; |
|
| − | when |
+ | when "000001" => byte <= x"46"; endCmd <= '0'; |
| + | when "000010" => byte <= x"00"; endCmd <= '0'; send<='0'; |
||
| − | if unsigned(counter) <= 18 then |
||
| + | when "000011" => byte <= x"00"; endCmd <= '0'; send<='0'; |
||
| − | byte<=digits(to_integer(unsigned(counter))-3); |
||
| − | + | keybyte(0)<=keydataone(0); |
|
| − | + | keybyte(4)<=keydataone(4); |
|
| − | endCmd<='0'; |
+ | when "000100" => byte <= x"00"; endCmd <= '0'; send<='0'; |
| + | keybyte(1)<=keydataone(0); |
||
| + | keybyte(5)<=keydataone(4); |
||
| + | when "000101" => byte <= x"00"; endCmd <= '1'; send<='0'; |
||
| + | keybyte(2)<=keydataone(0); |
||
| + | keybyte(6)<=keydataone(4); |
||
| + | when "000110" => byte <= x"40"; endCmd <= '1'; -- Set address mode - auto inc |
||
| + | keybyte(3)<=keydataone(0); |
||
| + | keybyte(7)<=keydataone(4); |
||
| + | when "000111" => byte <= x"88"; endCmd <= '1'; -- Turn display on, lowest brightness (0) |
||
| + | when "001000" => byte <= x"C0"; endCmd <= '0';-- Write at the left display |
||
| + | |||
| + | when others => |
||
| + | if unsigned(counter) <= 15+headersize then |
||
| + | if counter(0)='1' then |
||
| + | byte<=digits((to_integer(unsigned(counter))-headersize)/2); |
||
| + | else |
||
| + | byte<=leds((to_integer(unsigned(counter))-headersize)/2); |
||
| + | end if; |
||
| + | if unsigned(counter) < 15+headersize then |
||
| + | endCmd<='0'; |
||
| + | else |
||
| + | endCmd<='1'; |
||
| + | end if; |
||
else |
else |
||
| − | endCmd<='1'; |
+ | byte <= x"FF"; endCmd <= '1'; newData <= '0'; -- End of data / idle |
end if; |
end if; |
||
| − | + | end case; |
|
| + | end if; |
||
| − | byte <= x"FF"; endCmd <= '1'; newData <= '0'; -- End of data / idle |
||
| − | end if; |
||
| − | end case; |
||
end process; |
end process; |
||
| Line 240: | Line 289: | ||
begin |
begin |
||
if rising_edge(clk) then |
if rising_edge(clk) then |
||
| + | counterPreClk<='0'; |
||
if reset = '1' then |
if reset = '1' then |
||
| − | counter <= |
+ | counter <= "111111"; |
| − | elsif |
+ | elsif counter ="111111" then |
| + | counterPreClk<='1'; |
||
| + | counter <= "000000"; |
||
| + | elsif adv = '1' and counter /= "111111" then |
||
| + | counterPreClk<='1'; |
||
counter <= std_logic_vector(nextcounter); |
counter <= std_logic_vector(nextcounter); |
||
end if; |
end if; |
||
| + | end if; |
||
| + | end process; |
||
| + | counterClk_proc:process(clk) |
||
| + | begin |
||
| + | if rising_edge(clk) then |
||
| + | counterClk<=counterPreClk; |
||
end if; |
end if; |
||
end process; |
end process; |
||
| Line 253: | Line 313: | ||
resetCount <=resetCount-1; |
resetCount <=resetCount-1; |
||
else |
else |
||
| − | resetCount<= |
+ | resetCount<=200*1000; |
reset<= not reset; |
reset<= not reset; |
||
end if; |
end if; |
||
end if; |
end if; |
||
end process; |
end process; |
||
| − | end Behavioral; |
+ | end Behavioral; |
| + | </nowiki> |
||
| − | File <tt>dx_display_xmit.vhdl</tt> |
+ | ==File <tt>dx_display_xmit.vhdl</tt>== |
<nowiki>---------------------------------------------------------------------------------- |
<nowiki>---------------------------------------------------------------------------------- |
||
-- Engineer: Mike Field <hamster@snap.net.nz> |
-- Engineer: Mike Field <hamster@snap.net.nz> |
||
| + | -- Modified by: Joost Witteveen |
||
| − | -- |
||
| − | -- Module Name: dx_display_xmit - Behavioral |
||
| − | -- Description: Drive the serial bus for the display |
||
| − | -- |
||
| − | -- Revision: |
||
| − | -- Revision 0.01 - File Created |
||
| − | -- Additional Comments: |
||
-- |
-- |
||
---------------------------------------------------------------------------------- |
---------------------------------------------------------------------------------- |
||
| Line 277: | Line 332: | ||
entity dx_display_xmit is |
entity dx_display_xmit is |
||
| − | Port ( |
+ | 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); |
||
| − | newData : in STD_LOGIC; |
||
| − | + | 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 |
||
| + | --LED1 : out std_logic |
||
| + | ); |
||
end dx_display_xmit; |
end dx_display_xmit; |
||
architecture Behavioral of dx_display_xmit is |
architecture Behavioral of dx_display_xmit is |
||
| − | signal thisEndCmd : std_logic; |
||
signal thisByte : std_logic_vector(7 downto 0) := (others => '0'); |
signal thisByte : std_logic_vector(7 downto 0) := (others => '0'); |
||
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( |
+ | signal state : std_logic_vector(3 downto 0) := (others => '0'); |
--signal divider : integer range 0 downto 2048 := 0; |
--signal divider : integer range 0 downto 2048 := 0; |
||
| − | signal divider : std_logic_vector( |
+ | signal divider : std_logic_vector(63 downto 0) := (63=>'1', others =>'0'); |
| + | signal keydataLocal : std_logic_vector(keydata'range); |
||
begin |
begin |
||
| − | |||
clk_proc: process(clk) |
clk_proc: process(clk) |
||
begin |
begin |
||
| Line 303: | Line 361: | ||
--divider <= divider +1; |
--divider <= divider +1; |
||
divider <= divider(0) & divider(divider'left downto 1); |
divider <= divider(0) & divider(divider'left downto 1); |
||
| − | adv <= '0'; |
+ | adv <= '0'; |
| − | |||
if reset = '1' then |
if reset = '1' then |
||
| − | LED1<='0'; |
||
| − | |||
thisByte <= (others => '0'); |
thisByte <= (others => '0'); |
||
| − | thisEndCmd <= endCmd; |
+ | --thisEndCmd <= endCmd; |
state <= (others => '0'); |
state <= (others => '0'); |
||
d_strobe <= '1'; |
d_strobe <= '1'; |
||
| Line 319: | Line 374: | ||
-- divider <= 0; |
-- divider <= 0; |
||
elsif divider(0) = '1' then |
elsif divider(0) = '1' then |
||
| − | LED1<='0'; |
||
d_strobe <= '1'; |
d_strobe <= '1'; |
||
d_clk <= '1'; |
d_clk <= '1'; |
||
| − | + | if send = '1' then |
|
| + | d_data <= '1'; |
||
| + | else |
||
| + | d_data <='Z'; |
||
| + | end if; |
||
case state is |
case state is |
||
| − | when " |
+ | 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'; |
|
| − | adv <= '1'; |
||
| − | d_strobe <= '0'; |
||
| − | d_clk <= '1'; |
||
| − | d_data <= '1'; |
||
else |
else |
||
| − | d_strobe <= '1'; |
+ | d_strobe <= '1'; |
| − | d_clk <= '1'; |
+ | d_clk <= '1'; |
| − | d_data <= '1'; |
||
end if; |
end if; |
||
bitsLeftToSend <= (others => '1'); |
bitsLeftToSend <= (others => '1'); |
||
| − | + | keydatalocal<=x"55"; |
|
| − | when " |
+ | when "0001" => -- transfer a bit |
| − | LED1<='1'; |
||
state <= std_logic_vector(unsigned(state)+1); |
state <= std_logic_vector(unsigned(state)+1); |
||
d_strobe <= '0'; |
d_strobe <= '0'; |
||
d_clk <= '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? |
if bitsLeftToSend(0) = '1' then -- Still got a bit to send? |
||
state <= std_logic_vector(unsigned(state)-1); |
state <= std_logic_vector(unsigned(state)-1); |
||
| − | elsif thisEndCmd = '1' then |
||
| − | state <= "011"; -- close off command |
||
else |
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; |
end if; |
||
d_strobe <= '0'; |
d_strobe <= '0'; |
||
d_clk <= '1'; |
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); |
bitsLeftToSend <= '0' & bitsLeftToSend(6 downto 1); |
||
| + | when "0011" => --- ending the command by rasing d_strobe, then going back to idle state |
||
| − | |||
| + | state <= "0000"; |
||
| − | when "011" => --- ending the command by rasing d_strobe, then going back to idle state |
||
| − | state <= "000"; |
||
d_strobe <= '1'; |
d_strobe <= '1'; |
||
d_clk <= '1'; |
d_clk <= '1'; |
||
| − | + | if send = '1' then |
|
| − | + | d_data <= thisByte(0); |
|
| + | else |
||
| − | when "100" => -- Waiting for data, withan open command |
||
| + | keydata <= keydatalocal; |
||
| + | end if; |
||
| + | when "0100" => -- Waiting for data, with an open command |
||
d_strobe <= '0'; |
d_strobe <= '0'; |
||
d_clk <= '1'; |
d_clk <= '1'; |
||
| + | |||
| − | d_data <= '1'; |
||
if newData = '1' then |
if newData = '1' then |
||
| − | state <= " |
+ | state <= "0001"; -- start transfering bits |
thisByte <= byte; |
thisByte <= byte; |
||
| − | thisEndCmd <= endCmd; |
||
| − | adv <= '1'; |
||
bitsLeftToSend <= (others => '1'); |
bitsLeftToSend <= (others => '1'); |
||
end if; |
end if; |
||
| − | |||
when others => -- performa a reset |
when others => -- performa a reset |
||
thisByte <= (others => '0'); |
thisByte <= (others => '0'); |
||
| Line 385: | Line 447: | ||
d_strobe <= '1'; |
d_strobe <= '1'; |
||
d_clk <= '1'; |
d_clk <= '1'; |
||
| − | d_data <= '1'; |
||
end case; |
end case; |
||
end if; |
end if; |
||
Revision as of 21:33, 19 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 C0, the response will be 00 if the left-most key is not pressed, and 02 if the left-most key is pressed. Same after sending 46 C1 (??)
VHDL code for numeric data display
File design_top.vhdl
---------------------------------------------------------------------------------
-- Original by: Engineer: Mike Field <hamster@snap.net.nz>
-- Modifications by: Joost Witteveen
--
--
--TODO:
-- allow specification of d_clk frequency via generics
-- remove compiler warnings
-- check rounding of compile-time divide (bcd function)
-- clock-division in dx_display_xmit via counter, not 64-bit register.
----------------------------------------------------------------------------------
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
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;
signal tmp: std_logic_vector(31 downto 0);
signal keybyte: std_logic_vector(7 downto 0);
begin
Inst_dx_display: dx_display
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 7),
data => data);
-- Inst_display7segDec:display7seg
-- PORT MAP(
-- digits => digits(6 to 7),
-- data => decdata);
reset_proc: process(clk)
begin
if rising_edge(clk) then
if Count > 0 then
Count <=Count-1;
else
Count<=2*1000*1000;
--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(31 downto 24) <= keybyte;
data<=to_integer(unsigned(tmp));
for i in 0 to 7 loop
leds(i)(0)<=keybyte(i);
--leds(i)(0)<='0';
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
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 : std_logic_vector(5 downto 0) := (others => '0');
signal counterPreClk:std_logic:='0';
signal counterClk: std_logic:='0';
signal nextcounter : 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 := 9;
COMPONENT dx_display_xmit
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;
Inst_dx_display_xmit: dx_display_xmit 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 "000001" => byte <= x"46"; endCmd <= '0';
when "000010" => byte <= x"00"; endCmd <= '0'; send<='0';
when "000011" => byte <= x"00"; endCmd <= '0'; send<='0';
keybyte(0)<=keydataone(0);
keybyte(4)<=keydataone(4);
when "000100" => byte <= x"00"; endCmd <= '0'; send<='0';
keybyte(1)<=keydataone(0);
keybyte(5)<=keydataone(4);
when "000101" => byte <= x"00"; endCmd <= '1'; send<='0';
keybyte(2)<=keydataone(0);
keybyte(6)<=keydataone(4);
when "000110" => byte <= x"40"; endCmd <= '1'; -- Set address mode - auto inc
keybyte(3)<=keydataone(0);
keybyte(7)<=keydataone(4);
when "000111" => byte <= x"88"; endCmd <= '1'; -- Turn display on, lowest brightness (0)
when "001000" => byte <= x"C0"; endCmd <= '0';-- Write at the left display
when others =>
if unsigned(counter) <= 15+headersize then
if counter(0)='1' then
byte<=digits((to_integer(unsigned(counter))-headersize)/2);
else
byte<=leds((to_integer(unsigned(counter))-headersize)/2);
end if;
if unsigned(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 <= "111111";
elsif counter ="111111" then
counterPreClk<='1';
counter <= "000000";
elsif adv = '1' and counter /= "111111" then
counterPreClk<='1';
counter <= std_logic_vector(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<=200*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
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
--LED1 : out 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 downto 2048 := 0;
signal divider : std_logic_vector(63 downto 0) := (63=>'1', others =>'0');
signal keydataLocal : std_logic_vector(keydata'range);
begin
clk_proc: process(clk)
begin
if rising_edge(clk) then
--divider <= divider +1;
divider <= divider(0) & divider(divider'left downto 1);
adv <= '0';
if reset = '1' then
thisByte <= (others => '0');
--thisEndCmd <= endCmd;
state <= (others => '0');
d_strobe <= '1';
d_clk <= '1';
d_data <= '1';
--divider <= 0;
divider <= (divider'left=>'1', others =>'0');
--elsif divider = 63 then
-- divider <= 0;
elsif divider(0) = '1' then
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
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;