Results 1 to 6 of 6

Thread: UART issue

  1. #1
    Join Date
    Dec 2016
    Posts
    12
    Rep Power
    1

    Default 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 :
    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.


    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.
    Attached Images Attached Images

  2. #2
    Tricky is offline Moderator **Forum Master**
    Join Date
    Oct 2008
    Posts
    5,303
    Rep Power
    1

    Default Re: UART issue

    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

  3. #3
    Join Date
    Dec 2016
    Posts
    12
    Rep Power
    1

    Default Re: UART issue

    Sorry for the image, I don't understand why the quality is so poor.
    However, thank you for your help, i followed your advice and it seems to have solved my issue.
    Let me put again my code and my test bench maybe you could detect some other beginner mistakes.
    If you have any advice to simplify my test bench, particularly the byte sending, is there a way to factorise this ?

    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)
       process(clk)
       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 max_tick='1' then
                if rx='0' then
                   state_next <= start;
                   s_next <= (others=>'0');
                end if;
    	    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;
    Code:
    --TB
    
    LIBRARY ieee;
    USE ieee.std_logic_1164.ALL;
    USE ieee.std_logic_unsigned.all;
    
    -- entity declaration for your testbench.Dont declare any ports here
    ENTITY test_tb IS
    END test_tb;
    
    ARCHITECTURE behavior OF test_tb IS
       -- Component Declaration for the Unit Under Test (UUT)
        COMPONENT uart_rx  --'test' is the name of the module needed to be tested.
    --just copy and paste the input and output ports of your module as such.
       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 COMPONENT;
       --declare inputs and initialize them
       signal clk, reset,rx : std_logic := '0';
       
       --declare outputs and initialize them
            signal rx_done_tick : std_logic :='0';
    	signal q : std_logic_vector(7-1 downto 0);
    	signal dout : std_logic_vector(7 downto 0);
       
       -- Clock period definitions
       constant clk_period : time := 20 ns;
    
        BEGIN
           -- Instantiate the Unit Under Test (UUT)
           uut: uart_rx
    
           port map(clk=>clk, reset=>reset, rx=>rx,rx_done_tick=>rx_done_tick,q=>q,dout=>dout);     
    
       -- Clock process definitions( clock with 50% duty cycle is generated here.
       clk_process :process
       begin
            clk <= '0';
            wait for clk_period/2;  --for 0.5 ns signal is '0'.
            clk <= '1';
            wait for clk_period/2;  --for next 0.5 ns signal is '1'.
       end process;
       
      -- Stimulus process
      stim_proc: process
       begin        
    		  rx <= '1';		--default state
            wait for 50 ns;
            reset <='1';		        --reset the system
            wait for 100 ns;
            reset <='0';
    		  wait for 69 ns;
    		  
    		  --BYTE 1 MIDI 0x90 (note ON channel 1)
    		  
    		  rx <= '0';     --start bit
    		  wait for 32 us;
    		  rx <= '0';	  --D0
    		  wait for 32 us;
    		  rx <= '0';     --D1
    		  wait for 32 us;
    		  rx <= '0';     --D2
    		  wait for 32 us;
    		  rx <= '0';     --D3
    		  wait for 32 us;		
                      rx <= '1';     --D4
    		  wait for 32 us;
    		  rx <= '0';     --D5
    		  wait for 32 us;
    		  rx <= '0';     --D6
    		  wait for 32 us;
    		  rx <= '1';     --D7
    		  wait for 32 us;
    		  rx <= '1';     --stop bit 
    		
    		  wait for 32 us;
    		
    		  --BYTE 2 NOTE NUMBER 0xXX (don't care for this TB)
    		
    		  rx <= '0';     --start bit
    		  wait for 32 us;
    		  rx <= '1';	  --D0
    		  wait for 32 us;
    		  rx <= '0';     --D1
    		  wait for 32 us;
    		  rx <= '0';     --D2
    		  wait for 32 us;
    		  rx <= '1';     --D3
    		  wait for 32 us;		
                      rx <= '1';     --D4
    		  wait for 32 us;
    		  rx <= '1';     --D5
    		  wait for 32 us;
    		  rx <= '0';     --D6
    		  wait for 32 us;
    		  rx <= '0';     --D7
    		  wait for 32 us;
    		  rx <= '1';     --stop bit 
    
    		  wait for 32 us;
    		 
    		  --BYTE 3 VELOCITY 0xXX (don't care for this TB)
    		  
    		  rx <= '0';     --start bit
    		  wait for 32 us;
    		  rx <= '1';	  --D0
    		  wait for 32 us;
    		  rx <= '0';     --D1
    		  wait for 32 us;
    		  rx <= '0';     --D2
    		  wait for 32 us;
    		  rx <= '1';     --D3
    		  wait for 32 us;		
                      rx <= '1';     --D4
    		  wait for 32 us;
    		  rx <= '1';     --D5
    		  wait for 32 us;
    		  rx <= '0';     --D6
    		  wait for 32 us;
    		  rx <= '0';     --D7
    		  wait for 32 us;
    		  rx <= '1';     --stop bit 
    		
    		
    		  --OCTET 1 MIDI 0x80 (note OFF channel 1)
    		  
    		  rx <= '0';     --start bit
    		  wait for 32 us;
    		  rx <= '0';	  --D0
    		  wait for 32 us;
    		  rx <= '0';     --D1
    		  wait for 32 us;
    		  rx <= '0';     --D2
    		  wait for 32 us;
    		  rx <= '0';     --D3
    		  wait for 32 us;		
                      rx <= '0';     --D4
    		  wait for 32 us;
    		  rx <= '0';     --D5
    		  wait for 32 us;
    		  rx <= '0';     --D6
    		  wait for 32 us;
    		  rx <= '1';     --D7
    		  wait for 32 us;
    		  rx <= '1';     --stop bit 
    		
    		  wait for 32 us;
    		
    		  --BYTE 2 NOTE NUMBER 0xXX (don't care for this TB)
    		
    		  rx <= '0';     --start bit
    		  wait for 32 us;
    		  rx <= '1';	  --D0
    		  wait for 32 us;
    		  rx <= '0';     --D1
    		  wait for 32 us;
    		  rx <= '0';     --D2
    		  wait for 32 us;
    		  rx <= '1';     --D3
    		  wait for 32 us;		
                      rx <= '1';     --D4
    		  wait for 32 us;
    		  rx <= '1';     --D5
    		  wait for 32 us;
    		  rx <= '0';     --D6
    		  wait for 32 us;
    		  rx <= '0';     --D7
    		  wait for 32 us;
    		  rx <= '1';     --stop bit 
    
    		  wait for 32 us;
    		 
    		  --BYTE 3 VELOCITY 0xXX (don't care for this TB)
    		  
    		  rx <= '0';     --start bit
    		  wait for 32 us;
    		  rx <= '1';	  --D0
    		  wait for 32 us;
    		  rx <= '0';     --D1
    		  wait for 32 us;
    		  rx <= '0';     --D2
    		  wait for 32 us;
    		  rx <= '1';     --D3
    		  wait for 32 us;		
                      rx <= '1';     --D4
    		  wait for 32 us;
    		  rx <= '1';     --D5
    		  wait for 32 us;
    		  rx <= '0';     --D6
    		  wait for 32 us;
    		  rx <= '0';     --D7
    		  wait for 32 us;
    		  rx <= '1';     --stop bit 
    		
    		
    		
    		  wait;
      end process;
    
    END;

  4. #4
    Tricky is offline Moderator **Forum Master**
    Join Date
    Oct 2008
    Posts
    5,303
    Rep Power
    1

    Default Re: UART issue

    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:

    Code:
    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:

    Code:
    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.

  5. #5
    Join Date
    Dec 2007
    Location
    Bochum Germany
    Posts
    6,012
    Rep Power
    1

    Default Re: UART issue

    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.

  6. #6
    Join Date
    Dec 2016
    Posts
    12
    Rep Power
    1

    Default Re: UART issue

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

Similar Threads

  1. UART Test ISSUE (LOOPBACk)
    By kondasandeepkumar in forum General Discussion Forum
    Replies: 3
    Last Post: March 18th, 2016, 09:23 AM
  2. DE2-115 UART/RS-232 Issue when Booting from Flash
    By mclark in forum General Altera Discussion
    Replies: 1
    Last Post: September 10th, 2015, 09:50 PM
  3. Replies: 3
    Last Post: August 26th, 2015, 12:25 PM
  4. Change STDOUT dynamically amongst UART RS232 and JTAG UART in C program
    By anuj121990 in forum General Software Forum
    Replies: 1
    Last Post: October 2nd, 2014, 11:21 PM
  5. UART Buffer Length Issue
    By BigBoy in forum General Software Forum
    Replies: 2
    Last Post: January 8th, 2006, 03:33 AM

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •