3 votos

Rebote en el botón DDR de Nexys4

Estoy tratando de implementar un simple transmisor UART, donde la placa Nexys4 DDR está enviando caracteres ASCII a mi PC, que puedo ver usando Tera Term. El problema que estoy teniendo es que cuando presiono uno de los botones para enviar los datos UART, sigo recibiendo muchos del mismo carácter a la vez, y el número no es exacto (por ejemplo, si trato de enviar 0x66 obtengo el carácter 'f' a veces 102 veces, a veces 97 veces, etc). Pensé que tenía que desbaratar el botón, así que fui a buscar un módulo para ello. Pero parece que esto no tiene ningún efecto. Me gustaría que me ayudaran a saber qué es lo que falla en la forma en que lo he hecho.

Aquí está el código para la UART: (basado en este ejemplo 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;

la fuente uart_tx:

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;

y la fuente de desbordamiento:

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;

el archivo de restricciones:

## 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

2voto

Bernd Puntos 61

No he revisado todo el material que has presentado pero tendría que hacer una suposición de que no estás manejando correctamente la entrada del interruptor. Sí, tienes que rebotar, pero entonces tienes que detectar correctamente el borde de la transición desde la que quieres activar la transmisión UART. Eso podría ser, por supuesto, de la transición de empuje o de la transición de liberación.

Si no detecta correctamente el borde (transición) terminará detectando el interruptor pulsado una y otra vez, lo que provocará muchas transmisiones UART hasta que el interruptor se libere. El número variable que estás viendo está probablemente relacionado con el tiempo que el botón fue presionado.

1voto

GRoNGoR Puntos 81

La velocidad en baudios que ha elegido es de 9600 bps. Lo que significa que su UART tomará alrededor de \$ 1/9600 \approx 0.1 ms \$ para enviar un bit. Lo que significa que para enviar una trama completa con 8 bits, un bit de inicio y un bit de parada, la UART tardará alrededor de \$ 1 ms \$ .

Ha introducido algunos TX_DATA y ha pulsado el botón para activar la transmisión. Entonces, ¿qué sucederá si el botón permanece en estado ON durante, digamos, 100 ms? Enviará la trama de datos 100 veces, ¿verdad? Tu lógica de desbordamiento no hace nada para ayudar en este caso. Sólo comprueba si la entrada del interruptor es estable durante al menos 10 ms, y alimentar la misma lógica al pin de habilitación TXSIG de la UART.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X