Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)

UART issue

Altera_Forum
Honored Contributor II
1,560 Views

Greetings everyone, 

 

I'm working on an UART design (only the receiver), I followed an online pdf wich deals with the subject. 

I ended up with this following code : 

library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity uart_rx is generic( DBIT: integer:=8; --# data bits SB_TICK: integer:=16; --# ticks for stop bits N: integer := 7; -- size of q out corresponding to baud rate counter M: integer := 100 -- divisor for baud rate generator oversampling x16 50MHz/16*31250=100 ); port( clk, reset: in std_logic; rx: in std_logic; rx_done_tick: out std_logic; q: out std_logic_vector(N-1 downto 0); dout: out std_logic_vector(7 downto 0) ); end uart_rx ; architecture arch of uart_rx is type state_type is (idle, start, data, stop); signal state_reg, state_next: state_type; signal s_reg, s_next: unsigned(3 downto 0); signal n_reg, n_next: unsigned(2 downto 0); signal b_reg, b_next: std_logic_vector(7 downto 0); signal r_reg: unsigned(N-1 downto 0); signal r_next: unsigned(N-1 downto 0); signal max_tick : std_logic; begin -- baud generator process(clk, reset) begin if(reset = '1')then r_reg <= (others => '0'); elsif(rising_edge(clk))then r_reg <= r_next; end if; end process; -- next state logic r_next <= (others => '0') when r_reg=(M-1) else r_reg + 1; -- output logic q <= std_logic_vector(r_reg); max_tick <= '1' when r_reg=(M-1) else '0'; -- FSMD state & data registers process(clk,reset) begin if reset='1' then state_reg <= idle; s_reg <= (others=>'0'); n_reg <= (others=>'0'); b_reg <= (others=>'0'); elsif (rising_edge(clk)) then state_reg <= state_next; s_reg <= s_next; n_reg <= n_next; b_reg <= b_next; end if; end process; -- next-state logic & data path functional units/routing process(state_reg,s_reg,n_reg,b_reg,max_tick,rx) begin state_next <= state_reg; s_next <= s_reg; n_next <= n_reg; b_next <= b_reg; rx_done_tick <='0'; case state_reg is when idle => if rx='0' then state_next <= start; s_next <= (others=>'0'); end if; when start => if (max_tick = '1') then if s_reg=7 then state_next <= data; s_next <= (others=>'0'); n_next <= (others=>'0'); else s_next <= s_reg + 1; end if; end if; when data => if (max_tick = '1') then if s_reg=15 then s_next <= (others=>'0'); b_next <= rx & b_reg(7 downto 1) ; if n_reg=(DBIT-1) then state_next <= stop ; else n_next <= n_reg + 1; end if; else s_next <= s_reg + 1; end if; end if; when stop => if (max_tick = '1') then if s_reg=(SB_TICK-1) then state_next <= idle; rx_done_tick <='1'; else s_next <= s_reg + 1; end if; end if; end case; end process; dout <= b_reg; end arch;  

 

I wrote a Test Bench for it and my simulation picking me up a strange anomaly : there is a unwanted spike produced on rx_done_tick just before the wanted one. 

http://www.alteraforum.com/forum/attachment.php?attachmentid=13060&stc=1  

 

There is a spike on rx_done_tick but state_next doesnt change wich could be a lead. 

Hope someone can help me to figure this out.
0 Kudos
5 Replies
Altera_Forum
Honored Contributor II
512 Views

This will be because rx_done_tick is an asynchronous signal. There will be a signel somewhere that changes slightly before the clock edge causing a glitch. This are a characteristic of asynchronous outputs. Its difficult to tell exactly what because you didnt provide a test bench and your image is too low a resolution. 

 

The solutiuon would be to make all of the code synchronous - put it all in a synchronous process, and no glitches can be produced
0 Kudos
Altera_Forum
Honored Contributor II
512 Views

TO_BE_DONE

0 Kudos
Altera_Forum
Honored Contributor II
512 Views

You havent actually made your process synchronous. You've just put clock in the sensitivty list without creating the correct synchronous template. This will cause the simulation to appear synchronous, while the real design will not be, as sensitivity lists are ignored for synthesis. You need: 

 

process(clk) begin if rising_edge(clk) then -- code goes here end if; end process;  

 

As for your testbench, this is the most basic level of stimulation. You could tidy it up to wrap the byte writing into a procedure to make it tidier like this: 

 

stim_proc : process procedure write_byte(b : std_logic_vector) begin for i in b'range loop rx <= b(i); wait for 32 us; -- Why is this 32 us? why not some form of clock? end loop; -- write stop bit rx <= '1'; wait for 32 us; end procedure; begin wait until reset = '0'; write_byte(x"01"); write_byte(x"4C"); ....... wait; end process;  

 

I note your use of explicit time delays - usually you try and synchronise with some clock.
0 Kudos
Altera_Forum
Honored Contributor II
512 Views

The rx_done glitch reported in the original post isn't necessarily a problem. As long as the design unit interfacing with uart_rx is using the same clock (strongly suggested to do so), it doesn't "see" the glitch. It's more a matter of design topology. If you implement the uart state machine in a single synchronous process, all outputs are automatically registered. But if you prefer a two or three process state machine template, I don't see a necessity to register any internal signal, except for those send to external pins or foreign clock domains. 

 

Besides the glitch theme, which isn't an actual problem in my view, I see one different problem at first sight. 

 

You are reading rx into your state machine without synchronizing (registering) it previously to your design clock. This can cause unexpected results if an rx edge is coinciding with the clock edge, e.g. state_reg falling into an illegal and possibly unrecoverable state.´ 

 

To filter rx glitches, you may want to re-check the start bit in the middle.
0 Kudos
Altera_Forum
Honored Contributor II
512 Views

I am going to use your advice to re-work my code. Thank you both of you for your knowledge.

0 Kudos
Reply