Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
9 years ago

UART issue

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.

5 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    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
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    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.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    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.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

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