Reading and sending multiple bytes through UART in VHDL

Status
Not open for further replies.

Feco

Newbie level 6
Joined
May 13, 2013
Messages
12
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,371
Hello.
I made a simple UART module (receive and send) in VHDL for my Spartan 6 (Nexys 3) FPGA.
That module reads multiple bytes, stores them, then sends back. If I do it with 4-8 bytes theres is no problem, BUT if I increase the byte number, it randomly keeps crushing and stops working. I have no idea why.

bigger data size --- bigger chance to crush
lower data size --- lower chance to crush (or no crush at all)

Someone could point out what is the problem?

The code:

Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity uart is
    Port ( RX  : in  STD_LOGIC;
           TX  : out  STD_LOGIC;
           CLK : in  STD_LOGIC);
end uart;

architecture Behavioral of uart is

constant max : integer := (100000000/(2*9600))-1; 
signal CLK_9600 : STD_LOGIC;
signal CLK_cnt : integer range 0 to max := 0;

type state is (start, s0, s1, s2, s3, s4, s5, s6, s7, stop);
signal current_state_rec : state;
signal next_state_rec : state;
signal current_state_snd : state;
signal next_state_snd : state;

type matrix_1 is array (0 to 19) of STD_LOGIC_VECTOR(7 downto 0);
type matrix_2 is array (0 to 19) of STD_LOGIC_VECTOR(7 downto 0);
signal memory_in : matrix_1;
signal memory_out : matrix_2;
signal akku_vector : STD_LOGIC_VECTOR(7 downto 0);

signal rec_complete_flag : STD_LOGIC;
signal snd_complete_flag : STD_LOGIC;
signal memory_full_flag : STD_LOGIC;

signal write_address : integer range 0 to 19;
signal read_address : integer range 0 to 19;

begin

memory_out <= memory_in;

process(CLK)
begin
	if rising_edge(CLK) then
		if CLK_cnt = max then
			CLK_cnt <= 0;
			CLK_9600 <= not(CLK_9600);
		else
			CLK_cnt <= CLK_cnt + 1;
		end if;
	end if;
end process;

process(CLK_9600)
begin 
	if rising_edge(CLK_9600) then
		current_state_rec <= next_state_rec;
		current_state_snd <= next_state_snd;
		akku_vector <= RX & akku_vector(7 downto 1);
	end if;
end process;

process(rec_complete_flag, CLK_9600)
begin
	if rec_complete_flag = '1' and rising_edge(CLK_9600) then
		if write_address = 19 then
			write_address <= 0;
			memory_full_flag <= '1';
			memory_in(write_address) <= akku_vector;
		else
			write_address <= write_address + 1;
			memory_full_flag <= '0';
			memory_in(write_address) <= akku_vector;
		end if;
	end if;
end process;

process(snd_complete_flag, CLK_9600)
begin
	if snd_complete_flag = '1' and rising_edge(CLK_9600) then
		if read_address = 19 then
			read_address <= 0;
		else
			read_address <= read_address + 1;
		end if;
	end if;
end process;

process(RX, current_state_rec)
begin
	case current_state_rec is
		when start =>
			if RX = '0' then
				next_state_rec <= s0;
			else
				next_state_rec <= start;
			end if;
			rec_complete_flag <= '0';
		when s0 =>
			next_state_rec <= s1;
			rec_complete_flag <= '0';
		when s1 =>
			next_state_rec <= s2;
			rec_complete_flag <= '0';
		when s2 =>
			next_state_rec <= s3;
			rec_complete_flag <= '0';
		when s3 =>
			next_state_rec <= s4;
			rec_complete_flag <= '0';
		when s4 =>
			next_state_rec <= s5;
			rec_complete_flag <= '0';
		when s5 =>
			next_state_rec <= s6;
			rec_complete_flag <= '0';
		when s6 =>
			next_state_rec <= s7;
			rec_complete_flag <= '0';
		when s7 =>
			next_state_rec <= stop;
			rec_complete_flag <= '0';
		when others =>
			next_state_rec <= start;
			rec_complete_flag <= '1';
		end case;
end process;

process(memory_full_flag, current_state_snd, read_address, memory_out)
begin
	case current_state_snd is
		when start =>
			if memory_full_flag = '1' then
				next_state_snd <= s0;
				TX <= '0';
			else
				next_state_snd <= start;
				TX <= '1';
			end if;
			snd_complete_flag <= '0';
		when s0 =>
			next_state_snd <= s1;
			TX <= memory_out(read_address)(0);
			snd_complete_flag <= '0';
		when s1 =>
			next_state_snd <= s2;
			TX <= memory_out(read_address)(1);
			snd_complete_flag <= '0';
		when s2 =>
			next_state_snd <= s3;
			TX <= memory_out(read_address)(2);
			snd_complete_flag <= '0';
		when s3 =>
			next_state_snd <= s4;
			TX <= memory_out(read_address)(3);
			snd_complete_flag <= '0';
		when s4 =>
			next_state_snd <= s5;
			TX <= memory_out(read_address)(4);
			snd_complete_flag <= '0';
		when s5 =>
			next_state_snd <= s6;
			TX <= memory_out(read_address)(5);
			snd_complete_flag <= '0';
		when s6 =>
			next_state_snd <= s7;
			TX <= memory_out(read_address)(6);
			snd_complete_flag <= '0';
		when s7 =>
			next_state_snd <= stop;
			TX <= memory_out(read_address)(7);
			snd_complete_flag <= '0';
		when others =>
			if (read_address = 19) and (memory_full_flag = '1') then
				next_state_snd <= stop;
				snd_complete_flag <= '0';
			else
				next_state_snd <= start;
				snd_complete_flag <= '1';
			end if;
			TX <= '1';
		end case;
end process;

end Behavioral;

Thanks for your help.
 

Well there are issues with the fact you have logic generated clocks and potentially gated clocks. These are poor practice in FPGAs. you should generate a clock enable and use the system clock for all registers.

You have a syntax error:
memory_out <= memory_in;

is wrong, as they are different types. If you had simulated this it would not have compiled (I dont trust ISE, its vhdl compiler is not the best).

Have you written a testbench for this? did you debug it and put in multiple data values?
 

You have a syntax error:
memory_out <= memory_in;

Oh yeah, memory_out should be matrix_1 too. I tested, if I could send back different data, but forgot to change back.

Have you written a testbench for this? did you debug it and put in multiple data values?

The simulator in ISE doesn't work under win8.1 so I cannot do it. I also tried Symphony EDA at the beginning but it just gives me a constant '1' on TX.
 

Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…