Electrical – VHDL: Simple UART TX not working

fpgaquartusuartvhdl

As a first step towards learning VHDL and using FPGAs, I want to implement a simple UART transmitter which only transmits a constant bit-sequence according to the UART protocol with 9600 8N1 configuration.

I'm using a Altera Cyclone II EP2C5T144C8N board which has a 50MHz clock.

The transmitter is supposed to cycle through all the bits in the bitstring repeatedely on every rising clock of the 9600 Hz clock, which is generated by a counter beforehand.

The VHDL code is as follows:

uart_test.vhdl:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
use IEEE.std_logic_unsigned.ALL;

entity UART_TX is
    Port (clk9600: in std_logic;    -- 9600 Hz clock
            TX : out std_logic      -- TX pin
    );
end UART_TX;

architecture Behavioral of UART_TX is
-- dummy data
-- idle (1) for a 3 cycles, start bit (1 to 0 transition), 8 bits of data ('A'), stop bit (=1)
constant bits_to_transmit : std_logic_vector (0 to 12) := "1110100000101";
signal current_bit : std_logic :='1';
signal current_index: integer range 0 to 12 := 0;

begin
    process (clk9600) -- on every clock tick
    begin  
        if rising_edge(clk9600) then
            -- grab the current bit (in first iteration current_index = 0)
            current_bit <= bits_to_transmit(current_index);
            -- increment index by one (automatically overflows back to 0)
            current_index <= current_index + 1;
        end if;
    end process; 
    -- assign TX the current bit
    TX <= current_bit;
end Behavioral;

Top level entity blinky.vhdl:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;
use IEEE.std_logic_unsigned.ALL;
use WORK.all;

entity blinky is
    Port (clock50: in std_logic;        -- internal 50MHz clock
            TX_out : out std_logic;     -- transmit pin
            clock9600: out std_logic    -- 9600Hz clock out for debug
            );
end blinky;

architecture Behavioral of blinky is

-- counter for frequency dividing 50 MHz to 9600 (Clk period is 50000000 / 9600 / 2 = ~2604)
signal c : integer range 0 to 2604 := 0; 
signal internal_clk9600 : std_logic := '0';

-- component prototypes
component UART_TX is
    Port (clk9600: in std_logic;    -- 9600 Hz clock
            TX : out std_logic      -- TX pin
    );
end component;

begin
    process begin  
      wait until rising_edge(clock50);
      if (c<2604) then
          c <= c+1;
      else
          c <= 0;
          internal_clk9600 <= not internal_clk9600;
      end if; 
   end process; 

    clock9600 <= internal_clk9600;
    my_uart_tx : UART_TX port map (clk9600=>internal_clk9600, TX=>TX_out);  
end Behavioral;

The output on the TX pin is not what I expect. It transmits the 'A', then 3 garbage characters, then 'A' again. I captured the signals with a logic analyzer:

signalanalyzer

This does not correspond at all to the bit sequence I have programmed above. It seems that it inserts 0 bits after it has cycles through, which throws off the UART decoder? The 9600 clock looks however right.

Question: What is wrong with the code that causes this?

Side note: The RTL viewer shows a circuit which looks okay to me.
rtl

Best Answer

I'm not a VHDL guru, but I think your comment

-- increment index by one (automatically overflows back to 0)

is misleading, and you have to explicitly reset the index after 12.

Related Topic