bit4man
Newbie
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.
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.
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.