1
\$\begingroup\$

I asked same question in stackoverflow but didn't get any good answer. I'm newbie in FPGAs and VHDL. This time, I m trying to send Data from FPGA to TTL. I' m using GPIO pins for TX and GND and Data can be changed with switch on FPGA. My issue is whenever i press the button on FPGA, I always see FF on terminal. I couldn't find where the problem is.

Here is TX code:

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;

Here is Testbench code:

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;

Added Testbench results

EDIT: Guys thank you all for your interest. I guess I found the solution. The problem was my button register had no starting point. So when the code starts, register starts with 000 to 100. So I added a register starting point (111) and use baud pulses in right places. Now, code works perfectly.

Here is the working code:

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;
\$\endgroup\$
  • 1
    \$\begingroup\$ You've told us the issue, but you haven't asked a question. What do you want us to do, fix it for you? \$\endgroup\$ – Brian Drummond Aug 4 '17 at 12:45
  • \$\begingroup\$ @BrianDrummond Hi Brian. I just need when I press button on FPGA, I should send data from FPGA. \$\endgroup\$ – Griffo Aug 4 '17 at 12:58
  • 1
    \$\begingroup\$ The code isn't real clear. Your question would be better asked if you could include some comments on how you are trying to solve the problem (ie. what does your code do; describe the signals) - not just what the final goal is. \$\endgroup\$ – Blair Fonville Aug 4 '17 at 16:34
0
\$\begingroup\$

First, drawing a state-flow diagram for your design would help both you and us to solve the problem.

A couple of things jump out at me:

1. Where you write

if shift_button(3 downto 0) = "001" then

should be if shift_button(2 downto 0) = "001" then

2. When you press your button, you are going to be holding it for many clock cycles. Your design shifts a 1 into shift_button at evey clock cycle, per:

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

so your shift_button register will immediately go to all 1s.

\$\endgroup\$
0
\$\begingroup\$

My first guess from skimming your code is that it's related to your testbench asserting your reset (which is active-low in your code) and never de-asserting it. Is your issue only in simulation or do you also see it when implementing in hardware?

There may be other issues, but to be honest this code is not very readable, although if you wrote it it's much better than what I was producing as a newbie. I'm going to write the rest of this assuming you wrote the UART_tx code. If you got it from the internet, whoever wrote it is not qualified to disseminate code.

I've done UART modules many times since then and a much more readable way to do it is with explicitly defined states. Here's my favorite reference for FSMs every time I forget the syntax: Implementing a Finite State Machine in VHDL. This is good design practice and will make it easier for other people to help you (and you'll find it'll make your code less prone to errors as well).

If it's not the reset that is the issue, I recommend you use this as an opportunity to get comfortable simulating and analyzing waveforms. In ModelSim/ISE sim/whatever, run your test-bench in the waveform viewer. Drag in the internal signals and look to see if they're behaving as expected. I see some other parts of the code that look like potential mistakes (if-statements that seem to be written sequentially even though processes are simulated as parallel)--I can't be sure they are, and if you got it from the internet then who knows--but you might find things are happening on the wrong clock cycle or not at all.

Since you say you're new, I want to note some other things I noticed:

  • The resets are asynchronous, because in the processes you look for a reset outside of the clocked block. See this Xilinx forum post for an explanation of why that's bad: sync reset or async reset? Long story short, it messes up timing paths and prevents many optimizations. Best to keep everything synchronous to the clock whenever possible in an FPGA.

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

Should be

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

  • If you intended for your reset to be active-low, it's good coding practice to reflect this in the name. Call it nReset maybe.

  • I'm impressed you're using std_ulogic. Much safer than std_logic yet I've never seen it on the FPGA-projects I've worked on professionally.

  • With respect to your title. What you're doing is sending data from your FPGA through a UART module. TTL is a class of digital logic hardware (like CMOS and ECL), UART is a communications device.

  • I'm Iranian and I knew when I saw "tx_tamam" that you're probably from somewhere in or around the Middle East (for those that don't know Turkish/Farsi/Arabic, tamam means "finished"). I thought that was funny, but when posting on stackexchange it would be worth your time to change names to English to help people help you.

Hopefully that helps. Modules written from scratch never work the first time (or second or third or...), looking at waveforms to debug becomes a way of life after awhile.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.