VHDL enviando datos desde FPGA a TTL

1

Hice la misma pregunta en stackoverflow pero no obtuve ninguna buena respuesta. Soy novato en FPGAs y VHDL. Esta vez, estoy tratando de enviar datos desde FPGA a TTL. Estoy usando pines GPIO para TX y GND y los datos se pueden cambiar con el conmutador en FPGA. Mi problema es que cuando presiono el botón en FPGA, siempre veo FF en el terminal. No pude encontrar dónde está el problema.

Aquí está el código de TX:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD.ALL;

entity UART_Tx is
  port(
    CLK    : in  std_logic;
    Reset  : in  std_logic;
    Button : in  std_logic;
    Data   : in  std_logic_vector(7 downto 0);
    Out_Tx : out std_logic
  );
end entity;

Architecture Behavioral of UART_Tx is

  constant Baudrate   : integer                          := 9600;
  constant CLK_Hiz    : integer                          := 50000000;
  constant CLK_Bit    : integer                          := (CLK_Hiz / Baudrate) + 1;
  signal tx_Data_ind  : integer range 0 to 7;
  signal counter_baud : integer range 0 to (CLK_Bit - 1) := 0;
  signal shift_button : std_logic_vector (3 downto 0)    := (others => '0');
  signal button_out   : std_ulogic                       := '1';
  signal baud_pulse   : std_ulogic                       := '0';
  signal tx_enable    : std_ulogic                       := '0';
  signal tx_Data      : std_logic_vector (7 downto 0)    := (others => '0');
  signal tx_out       : std_ulogic;
  signal tx_ok        : std_ulogic                       := '0';
  signal counter_del  : std_ulogic                       := '0';

begin

  process(CLK, Reset)
  begin
    if (Reset = '0') then
      baud_pulse   <= '0';
      counter_baud <= 0;
    elsif (rising_edge(CLK)) then
      if (counter_baud < (CLK_Bit - 1)) then
        counter_baud <= counter_baud + 1;
        baud_pulse   <= '0';
      else
        counter_baud <= 0;
        baud_pulse   <= '1';
      end if;
      if (counter_del = '1') then
        counter_baud <= 0;
      end if;
    end if;
  end process;

  process(CLK, Reset)
  begin
    if (Reset = '0') then
      tx_Data     <= (others => '0');
      tx_data_ind <= 0;
      tx_enable   <= '0';
    elsif (rising_edge(CLK)) then
      tx_out                   <= '1';
      out_tx                   <= tx_out;
      shift_button(3)          <= button;
      shift_button(2 downto 0) <= shift_button(3 downto 1);
      if shift_button(3 downto 0) = "001" then
        button_out <= '0';
      end if;
      if (button_out = '0') then
        counter_del <= '1';
        tx_out    <= '0';
        if (tx_out = '0') then
          tx_enable <= '1';
        end if;
        if (tx_enable = '1') then
          counter_del <= '0';
          tx_Data     <= Data;
          if (baud_pulse = '1') then
            tx_out <= tx_Data(tx_Data_ind);
            if (tx_data_ind < 7) then
              tx_Data_ind <= tx_Data_ind + 1;
            else
              tx_ok <= '1';
            end if;
            if (tx_ok = '1') then
              tx_Data     <= (others => '0');
              tx_Data_ind <= 0;
              tx_enable   <= '0';
              button_out  <= '1';
              tx_out      <= '1';
            end if;
          end if;
        end if;
      end if;
    end if;
  end process;
end Architecture;

Aquí está el código de Testbench:

library ieee;
use ieee.std_logic_1164.all;

entity tb_UART_Tx is
end tb_UART_Tx;

architecture tb of tb_UART_Tx is

    component UART_Tx
        port (CLK    : in std_logic;
              Reset  : in std_logic;
              Button : in std_logic;
              Data   : in std_logic_vector (7 downto 0);
              Out_Tx : out std_logic);
    end component;

    signal CLK    : std_logic:='0';
    signal Reset  : std_logic:='1';
    signal Button : std_logic:='1';
    signal Data   : std_logic_vector (7 downto 0);
    signal Out_Tx : std_logic;

    constant TbPeriod : time := 20 ns; 
    signal TbSimEnded : std_logic := '0';

begin

    dut : UART_Tx
    port map (CLK    => CLK,
              Reset  => Reset,
              Button => Button,
              Data   => Data,
              Out_Tx => Out_Tx);

clk_process: process
begin

    CLK <= '0';
    wait for TbPeriod/2;
    CLK <= '1';
    wait for TbPeriod/2;
end process;

    stimuli : process
    begin

          Reset <= '0';
          wait for 20 ns;
          Button <= '1';
          Data <= "00110000";

          wait for 30 ns;
          Button <= '0';
          wait for 50 ns;
          Button <= '1';
          wait for 1000 ns;
--        Button <= '0';
--        wait for 30 ns;
--        Button <= '1';

        TbSimEnded <= '1';
        wait;
    end process;

end tb;

configuration cfg_tb_UART_Tx of tb_UART_Tx is
    for tb
    end for;
end cfg_tb_UART_Tx;

Resultados agregados de Testbench

EDITAR: Chicos, gracias a todos por su interés. Supongo que encontré la solución. El problema fue que mi botón de registro no tenía punto de partida. Entonces, cuando el código comienza, el registro comienza con 000 a 100. Así que agregué un punto de inicio de registro (111) y uso los pulsos de baudios en los lugares correctos. Ahora, el código funciona perfectamente.

Aquí está el código de trabajo:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use IEEE.NUMERIC_STD.ALL;

entity UART_Tx is
port(
            CLK:        in std_logic;
            nReset:     in std_logic;
            nButton:    in std_logic;
            Data:       in std_logic_vector (7 downto 0);
            Data_Tx:    out std_logic
            );
end UART_Tx;

architecture Behavioral of UART_Tx is


constant Baudrate:   integer:= 9600;
constant CLK_Hiz:    integer:= 50000000;
constant CLK_Bit:    integer:= (CLK_Hiz / Baudrate) + 1;
signal tx_counter:   integer range 1 to 9:= 1;
signal counter_baud: integer range 0 to (CLK_Bit - 1):= 0;
signal shift_nButton:std_logic_vector (3 downto 0):= (others => '1');
signal tx_reg:       std_logic_vector (7 downto 0):= (others => '0');
signal nButton_out:  std_ulogic:= '1';
signal baud_pulse:   std_ulogic;
signal tx_out:       std_ulogic:= '1';
signal counter_del:  std_ulogic;
signal start_bit:    std_ulogic:='0';
signal data_bit:     std_ulogic:='0';
signal stop_bit:     std_ulogic:='0';


begin
process(CLK,nReset)
    begin
        if(nReset = '0') then
            baud_pulse   <= '0';
            counter_baud <= 0;
        elsif(rising_edge(CLK)) then
            if(counter_baud < (CLK_Bit - 1)) then   
                counter_baud <= counter_baud + 1;
                baud_pulse   <= '0';        
            else    
                counter_baud <= 0;
                baud_pulse   <= '1'; 
            end if;

                if(counter_del = '1') then
                    counter_baud <= 0;
                end if; 
            end if;                 
end process;

    process(CLK, nReset)
        begin
        Data_Tx <= tx_out;

        if(nReset = '0') then
            tx_reg    <= (others => '0');
            tx_counter <= 1;
            elsif(rising_edge(CLK)) then
                    shift_nButton(3)          <=  nButton;
                    shift_nButton(2 downto 0) <= shift_nButton(3 downto 1);
                if shift_nButton(2 downto 0)  = "001" then
                    nButton_out <= '0';
                    counter_del <= '1';
                    start_bit   <= '1'; 
                end if;

                if(nButton_out = '1') then
                   tx_out      <= '1';              

                elsif(nButton_out = '0') then
                      counter_del <= '0';
                        if(start_bit = '1') then
                            tx_out      <= '0';   
                            tx_reg      <= Data;
                            if(baud_pulse = '1') then
                               start_bit  <= '0';
                               data_bit   <= '1';
                            end if;
                        end if;

                        if(data_bit = '1')then
                            if(tx_counter > 0 and tx_counter < 10) then
                                tx_out         <= tx_reg((tx_counter)-1);
                                if(baud_pulse = '1') then
                                   tx_counter  <= tx_counter + 1;
                                if(tx_counter = 9)then
                                        data_bit <= '0';
                                        stop_bit <= '1';
                                    end if;
                                end if;     
                            end if;
                        end if;

                        if(stop_bit = '1') then
                            tx_out      <= '1';
                            tx_counter      <= 1;
                            if(baud_pulse = '1') then
                            stop_bit    <= '0';
                            nButton_out <= '1';
                            tx_reg      <= (others => '0');
                            end if;
                        end if;
                end if;     
        end if;
end process;
end Behavioral;
    
pregunta Griffo

2 respuestas

0

Primero, dibujar un diagrama de flujo de estado para su diseño ayudaría a usted y a nosotros a resolver el problema.

Un par de cosas saltan hacia mí:

1. Donde escribes

  

si shift_button (3 downto 0)="001" entonces

debería ser if shift_button(2 downto 0) = "001" then

2. Al presionar el botón, lo mantendrá presionado durante muchos ciclos de reloj. Su diseño cambia un 1 a shift_button en cada ciclo de reloj, por:

elsif (rising_edge (CLK)) luego
tx_out < = '1';
out_tx < = tx_out;
shift_button (3) < = button;
...

por lo que su registro shift_button irá inmediatamente a todos los 1 s.

    
respondido por el Blair Fonville
0

Mi primera suposición es que el código de prueba está relacionado con su banco de pruebas que afirma su reinicio (que está activo-bajo en su código) y nunca lo desestima. ¿Es su problema solo en la simulación o también lo ve cuando lo implementa en hardware?

Puede haber otros problemas, pero para ser sincero, este código no es muy legible, aunque si lo escribiste es mucho mejor que lo que estaba produciendo como novato. Voy a escribir el resto de esto suponiendo que escribiste el código UART_tx. Si lo obtuvo de Internet, quien lo haya escrito no está calificado para difundir el código.

He hecho módulos UART muchas veces desde entonces y una forma mucho más legible de hacerlo es con estados explícitamente definidos. Aquí está mi referencia favorita para FSMs cada vez que olvido la sintaxis: Implementando un Máquina de estados finitos en VHDL . Esta es una buena práctica de diseño y facilitará la ayuda de otras personas (y descubrirá que también hará que su código sea menos propenso a errores).

Si el problema no es el reinicio, le recomiendo que lo use como una oportunidad para sentirse cómodo simulando y analizando las formas de onda. En ModelSim / ISE sim / lo que sea, ejecute su banco de pruebas en el visor de forma de onda. Arrastre las señales internas y observe si se están comportando como se espera. Veo algunas otras partes del código que parecen errores potenciales (sentencias if que parecen estar escritas secuencialmente aunque los procesos se simulan como paralelos): no puedo estar seguro de que lo estén, y si lo obtuvieron de Internet entonces quién sabe, pero es posible que las cosas sucedan en el ciclo del reloj incorrecto o que no ocurran en absoluto.

Como dices que eres nuevo, quiero anotar algunas otras cosas que noté:

  • Los restablecimientos son asíncronos, porque en los procesos se busca un restablecimiento fuera del bloque cronometrado. Consulte esta publicación del foro de Xilinx para obtener una explicación de por qué es malo: ¿reinicio de sincronización o reinicio asíncrono? En pocas palabras, desordena las rutas de tiempo y evita muchas optimizaciones. Lo mejor es mantener todo sincronizado con el reloj siempre que sea posible en un FPGA.

if (Reset = '0') then baud_pulse <= '0'; counter_baud <= 0; elsif (rising_edge(CLK)) then

Debería ser

if (rising_edge(CLK)) then if (Reset = '0') then baud_pulse <= '0'; counter_baud <= 0;

  • Si desea que su reinicio sea activo-bajo, es una buena práctica de codificación reflejar esto en el nombre. Llámelo nReset tal vez.

  • Estoy impresionado de que estés usando std_ulogic. Mucho más seguro que std_logic, pero nunca lo he visto en los proyectos FPGA en los que he trabajado profesionalmente.

  • Con respecto a su título. Lo que estás haciendo es enviar datos desde tu FPGA a través de un módulo UART. TTL es una clase de hardware de lógica digital (como CMOS y ECL), UART es un dispositivo de comunicaciones.

  • Soy iraní y supe cuando vi "tx_tamam" que probablemente eres de algún lugar del Medio Oriente o sus alrededores (para aquellos que no saben turco / farsi / árabe, tamam significa "terminado" "). Pensé que era divertido, pero al publicar en stackexchange valdría la pena que cambies de nombre al inglés para que la gente te ayude.

Esperemos que eso ayude. Los módulos escritos desde cero nunca funcionan la primera vez (o la segunda o la tercera o ...), mirar las formas de onda para depurar se convierte en una forma de vida después de un tiempo.

    
respondido por el jalalipop

Lea otras preguntas en las etiquetas