I am trying to implement a simple UART transmitter, where the Nexys4 DDR board is sending ASCII characters to my PC, which I can view using Tera Term. The problem I am having is that when I press one of the buttons to send the UART data, I keep getting a lot of the same character at once, and the number is not exact (e.g. if I try to send 0x66 I get the character 'f' sometimes 102 times, sometimes 97 times, etc). I thought I needed to debounce the button so I went to find a module for it. But it seems this has no effect. I would like some help on what is wrong with the way I have done it.
Here is the code for the UART: (based from this example http://labs.domipheus.com/blog/a-uart-implementation-in-vhdl/)
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity uart_deb is
Port ( I_CLK, I_RST, I_TXSIG : in STD_LOGIC;
I_TXDATA : in STD_LOGIC_VECTOR(7 downto 0);
O_TXRDY, O_TX : out STD_LOGIC );
end uart_deb;
architecture STRUCTURE of uart_deb is
component uart_tx
Port (
I_CLK : in STD_LOGIC;
I_RST : in STD_LOGIC;
I_TXSIG : in STD_LOGIC;
I_TXDATA : in STD_LOGIC_VECTOR(7 downto 0);
O_TXRDY : out STD_LOGIC;
O_TX : out STD_LOGIC
);
end component;
component debounce
GENERIC(
counter_size : INTEGER := 19); --counter size (19 bits gives 10.5ms with 50MHz clock)
PORT(
I_CLK : IN STD_LOGIC; --input clock
button : IN STD_LOGIC; --input signal to be debounced
result : OUT STD_LOGIC); --debounced signal
END component;
signal RES : STD_LOGIC;
begin
G1: debounce port map (I_CLK, I_TXSIG, RES);
G2: uart_tx port map (I_CLK, I_RST, RES, I_TXDATA, O_TXRDY, O_TX);
end;
the uart_tx source:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx leaf cells in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity uart_tx is
Generic ( baud : integer := 9600);
Port (
I_CLK : in STD_LOGIC;
I_RST : in STD_LOGIC;
I_TXSIG : in STD_LOGIC;
I_TXDATA : in STD_LOGIC_VECTOR(7 downto 0);
O_TXRDY : out STD_LOGIC;
O_TX : out STD_LOGIC
);
end uart_tx;
architecture Behavioral of uart_tx is
signal tx_data : STD_LOGIC_VECTOR(7 downto 0) := (others => '0');
signal tx_state : integer := 0;
signal tx_rdy : STD_LOGIC := '1';
signal tx : STD_LOGIC := '1';
constant BIT_PD : integer := integer(50000000 / baud); -- 100MHz clock limit
signal tx_clk_counter : integer := BIT_PD;
signal tx_clk : STD_LOGIC := '0';
begin
clk_gen: process (I_CLK)
begin
if rising_edge(I_CLK) then
if tx_clk_counter = 0 then
tx_clk_counter <= BIT_PD;
tx_clk <= not tx_clk;
else
tx_clk_counter <= tx_clk_counter - 1;
end if;
end if;
end process;
O_TX <= tx;
O_TXRDY <= tx_rdy;
tx_proc: process (tx_clk, I_RST, I_TXSIG, tx_state)
begin
if rising_edge(tx_clk) then
if I_RST = '1' then
tx_state <= 0;
tx_data <= X"00";
tx_rdy <= '1';
tx <= '1';
else
if tx_state = 0 and I_TXSIG = '1' then
tx_state <= 1;
tx_data <= I_TXDATA;
tx_rdy <= '0';
tx <= '0';
elsif tx_state < 9 and tx_rdy = '0' then
tx <= tx_data(0);
tx_data <= '0' & tx_data(7 downto 1);
tx_state <= tx_state + 1;
elsif tx_state = 9 and tx_rdy = '0' then
tx <= '1';
tx_rdy <= '1';
tx_state <= 0;
end if;
end if;
end if;
end process;
end Behavioral;
and the debouncer source:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_unsigned.all;
ENTITY debounce IS
GENERIC(
counter_size : INTEGER := 19); --counter size (19 bits gives 10.5ms with 50MHz clock)
PORT(
I_CLK : IN STD_LOGIC; --input clock
button : IN STD_LOGIC; --input signal to be debounced
result : OUT STD_LOGIC); --debounced signal
END debounce;
ARCHITECTURE logic OF debounce IS
SIGNAL flipflops : STD_LOGIC_VECTOR(1 DOWNTO 0); --input flip flops
SIGNAL counter_set : STD_LOGIC; --sync reset to zero
SIGNAL counter_out : STD_LOGIC_VECTOR(counter_size DOWNTO 0) := (OTHERS => '0'); --counter output
BEGIN
counter_set <= flipflops(0) xor flipflops(1); --determine when to start/reset counter
PROCESS(I_CLK)
BEGIN
IF(I_CLK'EVENT and I_CLK = '1') THEN
flipflops(0) <= button;
flipflops(1) <= flipflops(0);
If(counter_set = '1') THEN --reset counter because input is changing
counter_out <= (OTHERS => '0');
ELSIF(counter_out(counter_size) = '0') THEN --stable input time is not yet met
counter_out <= counter_out + 1;
ELSE --stable input time is met
result <= flipflops(1);
END IF;
END IF;
END PROCESS;
END logic;
the constraints file:
## Clock signal
set_property -dict { PACKAGE_PIN E3 IOSTANDARD LVCMOS33 } [get_ports { I_CLK }]; #IO_L12P_T1_MRCC_35 Sch=clk100mhz
create_clock -add -name sys_clk_pin -period 20.00 -waveform {0 5} [get_ports {I_CLK}];
##Switches
set_property -dict { PACKAGE_PIN J15 IOSTANDARD LVCMOS33 } [get_ports { I_TXDATA[0] }]; #IO_L24N_T3_RS0_15 Sch=sw[0]
set_property -dict { PACKAGE_PIN L16 IOSTANDARD LVCMOS33 } [get_ports { I_TXDATA[1] }]; #IO_L3N_T0_DQS_EMCCLK_14 Sch=sw[1]
set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { I_TXDATA[2] }]; #IO_L6N_T0_D08_VREF_14 Sch=sw[2]
set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { I_TXDATA[3] }]; #IO_L13N_T2_MRCC_14 Sch=sw[3]
set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { I_TXDATA[4] }]; #IO_L12N_T1_MRCC_14 Sch=sw[4]
set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { I_TXDATA[5] }]; #IO_L7N_T1_D10_14 Sch=sw[5]
set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { I_TXDATA[6] }]; #IO_L17N_T2_A13_D29_14 Sch=sw[6]
set_property -dict { PACKAGE_PIN R13 IOSTANDARD LVCMOS33 } [get_ports { I_TXDATA[7] }]; #IO_L5N_T0_D07_14 Sch=sw[7]
## LEDs
set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { O_TXRDY }]; #IO_L18P_T2_A24_15 Sch=led[0]
##Buttons
set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { I_RST }]; #IO_L9P_T1_DQS_14 Sch=btnc
set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { I_TXSIG }]; #IO_L4N_T0_D05_14 Sch=btnu
##USB-RS232 Interface
#set_property -dict { PACKAGE_PIN C4 IOSTANDARD LVCMOS33 } [get_ports { UART_TXD_IN }]; #IO_L7P_T1_AD6P_35 Sch=uart_txd_in
set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { O_TX }]; #IO_L11N_T1_SRCC_35 Sch=uart_rxd_out
#set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { UART_CTS }]; #IO_L12N_T1_MRCC_35 Sch=uart_cts
#set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { UART_RTS }]; #IO_L5N_T0_AD13N_35 Sch=uart_rts