bit4man
Newbie
![Newbie level 2](/styles/images/ranks/alevel2.gif)
I've created a few "how to learn" VHDL projects in Vivado, and started a quest to control a simple TM1638 that I have no problems with using a MCU, but it seemed a good project to get better at FPGA programming. For now I am using VHDL - that's what I started learning - and what I have right now is no where close to done, but my initial tests shows "something is wrong" and I'm not sure I understand why.
![Screenshot from 2021-02-13 13-30-31.png Screenshot from 2021-02-13 13-30-31.png](https://www.edaboard.com/data/attachments/97/97540-9129ec801967c4d6fd29cfca1e76c4c7.jpg)
This illustrates the error/issue I'm seeing. w_TX_STB is not showing high (and it's not sync'ed correctly) but shows X instead. I understand that this can be due to it being unintialized ; it seem to be to me, so I'm a bit lost here. Here's the relevant code (it's a very small project for now):
SER_TX:
Finally the test unit (tm1638_tb - very simple for now):
All the states that are active during the current test are setting s_tx_stb to a value.
STB (Strobe) is what the TM1638 uses to indicate where there are commands/data - sorta like an "enable" flag. It's important that it's set at 8 bit boundaries and what I thought would be my challenge (not there yet as I found this challenge instead) is that some commands have multiple bytes being sent while STB is high. This explains the rather odd structure, which of course may be very wrong.
![Screenshot from 2021-02-13 13-30-31.png Screenshot from 2021-02-13 13-30-31.png](https://www.edaboard.com/data/attachments/97/97540-9129ec801967c4d6fd29cfca1e76c4c7.jpg)
This illustrates the error/issue I'm seeing. w_TX_STB is not showing high (and it's not sync'ed correctly) but shows X instead. I understand that this can be due to it being unintialized ; it seem to be to me, so I'm a bit lost here. Here's the relevant code (it's a very small project for now):
Code:
tm1638.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity tm1638 is
PORT (
i_clock : in std_logic;
i_reset : in std_logic := '0'; -- active high
i_setled : in std_logic_vector(7 downto 0) := (others => '0');
i_enable : in std_logic := '0';
i_num1 : in std_logic_vector(10 downto 0) := (others => '0');
i_num2 : in std_logic_vector(10 downto 0) := (others => '0');
o_tx_serial : out std_logic;
o_tx_stb : out std_logic;
o_btpush : out std_logic_vector(7 downto 0)
);
end tm1638;
architecture beh of tm1638 is
constant CMD_TURNON : std_logic_vector(7 downto 0) := X"8F";
constant CMD_TURNOFF : std_logic_vector(7 downto 0) := X"87";
constant CMD_SIGNLE : std_logic_vector(7 downto 0) := X"44";
constant CMD_SEQ : std_logic_vector(7 downto 0) := X"40";
constant CMD_READB : std_logic_vector(7 downto 0) := X"42";
type comstate is (turnon, turnoff, statewait, idle, dispnum1, dispnum2, displed, readkeys);
component ser_tx is
port (
i_clk : in std_logic;
i_tx_dv : in std_logic;
i_tx_byte : in std_logic_vector(7 downto 0);
o_tx_active : out std_logic;
o_tx_serial : out std_logic;
o_tx_done : out std_logic
);
end component ser_tx;
signal r_CLOCK : std_logic := '0';
signal r_TX_DV : std_logic := '0';
signal r_TX_BYTE : std_logic_vector(7 downto 0) := (others => '0');
signal w_TX_SERIAL : std_logic;
signal w_TX_ACTIVE : std_logic;
signal w_TX_DONE : std_logic;
signal s_enabled : std_logic := '0';
signal s_oldstate : comstate := idle;
signal s_comstate : comstate := idle;
signal s_nextstate : comstate := idle;
signal s_nextcomstate : comstate := idle;
signal s_tx_stb : std_logic := '0';
begin
-- Instantiate SER transmitter
SER_TX_INST : ser_tx
port map (
i_clk => r_CLOCK,
i_tx_dv => r_TX_DV,
i_tx_byte => r_TX_BYTE,
o_tx_active => w_TX_ACTIVE,
o_tx_serial => w_TX_SERIAL,
o_tx_done => w_TX_DONE
);
r_clock <= i_clock;
o_tx_serial <= w_TX_SERIAL;
o_tx_stb <= s_tx_stb;
statesys : process(i_clock)
begin
if rising_edge(i_clock)
then
if i_reset='1'
then
r_TX_BYTE <= (others => '0');
r_TX_DV <= '0';
s_enabled <= '0';
s_comstate <= idle;
s_nextcomstate <= idle;
s_tx_stb <= '0';
else
case s_comstate is
when idle =>
if i_enable /= s_enabled
then
s_oldstate <= s_comstate; -- remember old state
s_enabled <= i_enable;
if i_enable='1' then s_comstate <= turnon; else s_comstate <= turnoff; end if;
else
if s_oldstate/=idle then s_comstate <= s_oldstate; else s_comstate <= dispnum1; end if;
s_oldstate <= idle;
end if;
s_tx_stb <= '0';
when statewait =>
if r_TX_DV = '1'
then
r_TX_DV <= '0'; -- Switch off once set
s_tx_stb <= '1';
end if;
if w_TX_DONE='1'
then
s_tx_stb <= '0';
s_comstate <= s_nextstate;
else
s_comstate <= statewait;
end if;
when turnon =>
r_TX_DV <= '1';
r_TX_BYTE <= CMD_TURNON;
s_nextstate <= idle;
s_comstate <= statewait;
when turnoff =>
r_TX_DV <= '1';
r_TX_BYTE <= CMD_TURNOFF;
s_nextstate <= idle;
s_comstate <= statewait;
when dispnum1 =>
s_nextstate <= dispnum2;
s_comstate <= statewait;
when dispnum2 =>
s_nextstate <= displed;
s_comstate <= statewait;
when displed =>
s_nextstate <= readkeys;
s_comstate <= statewait;
when readkeys =>
s_nextstate <= idle;
s_comstate <= statewait;
when others =>
s_comstate <= idle;
end case;
end if;
end if;
end process statesys;
end beh;
SER_TX:
Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;
entity SER_TX is
Port ( i_Clk : in STD_LOGIC;
i_TX_DV : in STD_LOGIC;
i_TX_Byte : in STD_LOGIC_VECTOR (7 downto 0);
o_TX_Active : out STD_LOGIC;
o_TX_Serial : out STD_LOGIC;
o_TX_Done : out STD_LOGIC);
end SER_TX;
architecture RTL of SER_TX is
type t_SM_Main is (s_Idle, s_TX_Data_Bits, s_Cleanup, s_CleanupSleep);
signal r_SM_Main : t_SM_Main := s_Idle;
constant c_cycles : integer := 5;
signal r_Bit_Index : integer range 0 to 7 := 7; -- 8 Bits Total
signal r_TX_Data : std_logic_vector(7 downto 0) := (others => '0');
signal r_TX_Done : std_logic := '0';
signal r_sleepcycles : integer range 0 to 10 := 0;
begin
p_SER_TX : process (i_Clk)
begin
if rising_edge(i_Clk) then
case r_SM_Main is
when s_Idle =>
o_TX_Serial <= '1'; -- Drive Line High for Idle
r_TX_Done <= '0';
r_Bit_Index <= 7;
if i_TX_DV = '1' then
o_TX_Active <= '1';
r_TX_Data <= i_TX_Byte;
r_SM_Main <= s_TX_Data_Bits;
else
r_SM_Main <= s_Idle;
o_TX_Active <= '0';
end if;
-- Wait g_CLKS_PER_BIT-1 clock cycles for data bits to finish
when s_TX_Data_Bits =>
o_TX_Serial <= r_TX_Data(r_Bit_Index);
-- Check if we have sent out all bits
if r_Bit_Index > 0 then
r_Bit_Index <= r_Bit_Index - 1;
r_SM_Main <= s_TX_Data_Bits;
else
r_Bit_Index <= 7;
r_SM_Main <= s_Cleanup;
end if;
-- Stay here 1 clock
when s_Cleanup =>
r_TX_Done <= '1';
if r_sleepcycles = c_cycles then
o_TX_Active <= '0';
r_SM_Main <= s_idle;
r_sleepcycles <= 0;
else
r_sleepcycles <= r_sleepcycles + 1;
r_SM_Main <= s_Cleanup;
end if;
when others =>
r_SM_Main <= s_Idle;
end case;
end if;
end process p_SER_TX;
o_TX_Done <= r_TX_Done;
end RTL;
Finally the test unit (tm1638_tb - very simple for now):
Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity tm1638_tb is
end tm1638_tb;
architecture tmbeh of tm1638_tb is
component tm1638 is
port (
i_clock : in std_logic;
i_reset : in std_logic;
i_setled : in std_logic_vector(7 downto 0) := (others => '0');
i_enable : in std_logic := '0';
i_num1 : in std_logic_vector(10 downto 0) := (others => '0');
i_num2 : in std_logic_vector(10 downto 0) := (others => '0');
o_tx_serial : out std_logic;
o_tx_stb : out std_logic;
o_btpush : out std_logic_vector(7 downto 0)
);
end component tm1638;
signal s_CLOCK : std_logic := '0';
signal s_reset : std_logic := '0';
signal s_enable : std_logic := '0';
signal s_setled : std_logic_vector(7 downto 0) := (others => '0');
signal s_num1 : std_logic_vector(10 downto 0) := (others => '0');
signal s_num2 : std_logic_vector(10 downto 0) := (others => '0');
signal w_TX_STB : std_logic;
signal w_TX_SERIAL : std_logic;
signal w_btpush : std_logic_vector(7 downto 0);
begin
TM1638_INST : tm1638
port map (
i_clock => s_clock,
i_reset => s_reset,
i_setled => s_setled,
i_enable => s_enable,
i_num1 => s_num1,
i_num2 => s_num2,
o_tx_serial=> w_TX_SERIAL,
o_tx_stb => w_TX_STB,
o_btpush => w_btpush
);
s_clock <= not s_clock after 50 ns;
process is
begin
w_TX_STB <= '0';
wait until rising_edge(s_clock);
wait until rising_edge(s_clock);
s_reset <= '1';
wait for 10ns;
wait until rising_edge(s_clock);
s_reset <= '0';
s_enable <= '1';
wait for 2us;
assert false report "Tests Complete" severity failure;
end process;
All the states that are active during the current test are setting s_tx_stb to a value.
STB (Strobe) is what the TM1638 uses to indicate where there are commands/data - sorta like an "enable" flag. It's important that it's set at 8 bit boundaries and what I thought would be my challenge (not there yet as I found this challenge instead) is that some commands have multiple bytes being sent while STB is high. This explains the rather odd structure, which of course may be very wrong.