Sunday, 30 July 2017

VHDL RS232 UART UnIversal asynchronous reciever transmitter FSM implementation Xilinx Spartan 3 code


FILES DOWNLOAD

MASTER UART CONTROLLER:
 Library ieee;  
 use ieee. std_logic_1164.all ;  
 use ieee . numeric_std.all ;  
 entity uart_test is  
 port (  
 clk, reset: in std_logic;  
 btn: std_logic_vector ( 2 downto 0 ) ;  
 rx: in std_logic;  
 tx: out std_logic;  
 sseg : out std_logic_vector ( 6 downto 0) ;  
 an: out std_logic_vector (3 downto 0 );  
 led: out std_logic_vector ( 7 downto 0 )  
 ) ;  
 end uart_test;  
 architecture arch of uart_test is  
 signal tx_full , rx_empty : std_logic;  
 signal rec_data ,rec_data1 : std_logic_vector ( 7 downto 0 ) ;  
 signal btn_tick: std_logic;  
 -- i n s t a n t i a t e u a r t  
 begin  
 uart_unit: entity work.uart(str_arch)  
 port map(clk=>clk, reset=>reset , rd_uart=>btn_tick,  
 wr_uart=>btn_tick, rx=>rx, w_data=>rec_data1,tx_full=>tx_full,   
 rx_empty=>rx_empty,  
 r_data=>rec_data, tx=>tx);  
 -- i n s t a n t i a t e d e b o u n c e c i r c u i t  
 btn_db_unit : entity work.debounce(exp_fsmd_arch)  
 port map(clk=>clk, reset=>reset , sw=>btn(0),  
 db_level=>open, db_tick=>btn_tick);  
 -- i n c r e m e n t e d d a t a l o o p b a c k  
 rec_data1 <= std_logic_vector(unsigned(rec_data)+1);  
 -- l e d d is p l a y  
 led <= rec_data;  
 process(rx_empty)  
 begin  
 if rx_empty = '1' then  
 sseg <= "1000000";  
 else   
 sseg <="0001110";  
 --sseg <= '0' & ( not tx_full) & "00" & ( rx_empty) & "000";  
 end if;  
 end process;  
 an <= "0001";  
 end arch;     --6542130  
          --"0001000" when "1110",--e  
                               --"0001110" when others;--f  
                               -------------------------------------------------  
      -- Encoder   
      -------------------------------------------------  
      -- HEX-to-seven-segment decoder   
      -- segment encoding   
      --   0   
      --   ---   
      -- 5 |  | 1  
      --   --- <------6  
      -- 4 |  | 2  
      --   ---   
      --   3  

UART MODULE
 library ieee;  
 use ieee.std_logic_1164.all;  
 use ieee.numeric_std.all;  
 entity uart is  
 generic (  
 -- D e f a u l t s e t t in g :  
 -- 1 9 2 0 0 b a u d , 8 d a t a b i t s , 1 s t o p b i t , 2 ^ 2 FIFO  
 DBIT : integer :=8; -- # d a t a b i t s  
 SB_TICK: integer:=16; -- # t i c k s f o r s t o p b i t s , 1 6 / 2 4 / 3 2  
 DVSR: integer:= 163; -- baud r a t e d i v i s o r  
 DVSR_BIT: integer:=8; -- # b i t s of DVSR  
 FIFO_W: integer:=2 -- # a d d r b i t s of FIFO  
 -- for 1 / 1 . 5 / 2 s t o p b i t s  
 -- DVSR = 5 0 M / ( 1 6 * b a u d r a t e )  
 -- # w o r d s in FIFO=2^FIFO_W  
 ) ;  
 port (  
 clk, reset: in std_logic;  
 rd_uart , wr_uart : in std_logic ;  
 rx: in std_logic;  
 w_data: in std_logic_vector ( 7 downto 0 ) ;  
 tx_full, rx_empty: out std_logic;  
 r_data: out std_logic_vector ( 7 downto 0) ;  
 tx: out std_logic  
 ) ;  
 end uart;  
 architecture str_arch of uart is  
 signal rx_done_tick: std_logic;  
 signal tick: std_logic ;  
 signal tx_fifo_out : std_logic_vector ( 7 downto 0) ;  
 signal rx_data_out : std_logic_vector ( 7 downto 0) ;  
 signal tx_empty , tx_fifo_not_empty : std_logic ;  
 signal tx_done_tick : std_logic ;  
 begin  
 baud_gen_unit: entity work.mod_m_counter(arch)  
 generic map(M=>DVSR , N=>DVSR_BIT)  
 port map(clk=>clk, reset=>reset ,  
 q=>open , max_tick=>tick) ;  
 uart_rx_unit: entity work.uart_rx(arch)  
 generic map(DBIT=>DBIT, SB_TICK=>SB_TICK)  
 port map(clk=>clk, reset=>reset , rx=>rx,  
 s_tick=>tick, rx_done_tick=>rx_done_tick,  
 dout=>rx_data_out) ;  
 fifo_rx_unit: entity work.fifo(arch)  
 generic map(B=>DBIT , W=>FIFO_W)  
 port map(clk=>clk, reset=>reset , rd=>rd_uart ,  
 wr=>rx_done_tick , w_data=>rx_data_out ,  
 empty=>rx_empty, full=>open, r_data=>r_data);  
 fifo_tx_unit: entity work.fifo(arch)  
 generic map(B=>DBIT , W=>FIFO_W)  
 port map(clk=>clk, reset=>reset, rd=>tx_done_tick,  
 wr=>wr_uart, w_data=>w_data, empty=>tx_empty,  
 full=>tx_full, r_data=>tx_fifo_out);  
 uart_tx_unit : entity work.uart_tx(arch)  
 generic map ( DBIT => DBIT , SB_TICK => SB_TICK )  
 port map(clk=>clk, reset=>reset ,  
 tx_start=>tx_fifo_not_empty,  
 s_tick=>tick, din=>tx_fifo_out,  
 tx_done_tick=> tx_done_tick, tx=>tx);  
 tx_fifo_not_empty <= not tx_empty;  
 end str_arch;  

MOD M COUNTER
 library IEEE;  
 use IEEE.STD_LOGIC_1164.ALL;  
 use IEEE.numeric_std.ALL;  
 entity mod_m_counter is  
 generic (  
 N: integer := 4; -- number o f b i t s  
 M : integer := 10); -- m o d 4  
 port (  
 clk, reset: in std_logic;  
 max_tick: out std_logic;  
 q: out std_logic_vector ( N - 1 downto 0);  
 an: out std_logic_vector(3 downto 0);  
 sseg: out std_logic_vector ( 7 downto 0)  
 );  
 end mod_m_counter ;  
 architecture arch of mod_m_counter is  
 signal cath,off: std_logic ;  
 signal r_reg : unsigned ( N - 1 downto 0 ) ;  
 signal r_next : unsigned ( N - 1 downto 0 ) ;  
 begin  
 --enabling the fir  
 process (clk, reset)  
 begin  
 if (reset='1') then  
 r_reg <= ( others => '0' ) ;  
 elsif (clk'event and clk='1') then  
 r_reg <= r_next;  
 end if ;  
 end process ;  
 --n e x t - s t a t e l o g i c  
 r_next <= ( others => '0' ) when r_reg=(M-1) else  
 r_reg + 1;  
 -- o u t p u t l o g i c  
 q <= std_logic_vector(r_reg);  
 max_tick <= '1' when r_reg=(M-1) else '0' ;  
 end arch;  

UART RECEIVER
 library ieee;  
 use ieee.std_logic_1164.all;  
 use ieee.numeric_std.all;  
 entity uart_rx is  
 generic (  
 DBIT : integer := 8 ; -- # data b i t s  
 SB_TICK: integer := 16 -- # t i c k s f o r stop b i t s  
 ) ;  
 port (  
 clk , reset : in std_logic ;  
 rx : in std_logic ;  
 s_tick : in std_logic ;  
 rx_done_tick : out std_logic ;  
 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 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 state_reg , state_next : state_type ;  
 begin  
 -- FSMD s t a t e & data r e g is t e r s  
 process ( clk , reset )  
 begin  
 if reset = '1' then  
 state_reg <= idle ;  
 s_reg <= ( others => '0' ) ;  
 n_reg <= ( others => '0' ) ;  
 b_reg <= ( others => '0' ) ;  
 elsif ( clk'event and clk = '1' ) then  
 state_reg <= state_next ;  
 s_reg <= s_next ;  
 n_reg <= n_next ;  
 b_reg <= b_next ;  
 end if ;  
 end process ;  
 process ( state_reg , s_reg , n_reg , b_reg , s_tick, rx )  
 begin  
 -- n e x t - s t a t e l o g i c & data p a t h f u n c t i o n a l u n i t s / r o u t i n g  
 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 ( s_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 ( s_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 ( s_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;  

FIFO BUFFER
 library ieee;  
 use ieee.std_logic_1164.all;  
 use ieee.numeric_std.all ;  
 entity fifo is  
 generic (  
 B: natural:=8; -- number of b i t s  
 W: natural:=4 -- number o f a d d r e s s b i t s  
 );  
 port (  
 clk, reset: in std_logic;  
 rd, wr: in std_logic;  
 w_data: in std_logic_vector ( B - 1 downto 0) ;  
 empty, full : out std_logic;  
 r_data: out std_logic_vector ( B - 1 downto 0 )  
 );  
 end fifo;  
 architecture arch of fifo is  
 type reg_file_type is array (2**W-1 downto 0) of std_logic_vector ( B - 1 downto 0) ;  
 signal array_reg : reg_file_type ;  
 signal w_ptr_reg , w_ptr_next , w_ptr_succ : std_logic_vector (W-1 downto 0 ) ;  
 signal r_ptr_reg , r_ptr_next , r_ptr_succ:std_logic_vector ( W - 1 downto 0) ;  
 signal full_reg , empty_reg , full_next , empty_next :std_logic;  
 signal wr_op: std_logic_vector (1 downto 0 ) ;  
 signal wr_en : std_logic ;  
 begin  
 -- r e g is t e r f i l e  
 process (clk, reset)  
 begin  
 if (reset='1' ) then  
 array_reg <= ( others => ( others => '0' ) ) ;  
 elsif (clk'event and clk='1') then  
 if wr_en='1' then  
 array_reg(to_integer(unsigned(w_ptr_reg)))  
 <= w_data;  
 end if ;  
 end if ;  
 end process ;  
 -- r e a d p o r t  
 r_data <= array_reg(to_integer(unsigned(r_ptr_reg)));  
 --w r i t e e n a b l e d o n l y when FIFO is not f u l l  
 wr_en <= wr and ( not full_reg);  
 --  
 -- f if o c o n t r o l l o g i c  
 -- r e g is t e r f o r r e a d and w r i t e p o in t e r s  
 process (clk , reset)  
 begin  
 if (reset='1') then  
 w_ptr_reg <= ( others => '0' ) ;  
 r_ptr_reg <= ( others => '0' ) ;  
 full_reg <= '0' ;  
 empty_reg <= '1' ;  
 elsif(clk'event and clk='1') then  
 w_ptr_reg <= w_ptr_next ;  
 r_ptr_reg <= r_ptr_next ;  
 full_reg <= full_next;  
 empty_reg <= empty_next ;  
 end if ;  
 end process ;  
 -- s u c c e s s i v e p o in t e r v a l u e s  
 w_ptr_succ <= std_logic_vector (unsigned(w_ptr_reg)+1) ;  
 r_ptr_succ <= std_logic_vector(unsigned(r_ptr_reg)+1);  
 -- n e x t - s t a t e logic f o r r e a d and w r i t e p o in t e r s  
 wr_op <= wr & rd;  
 process (w_ptr_reg, w_ptr_succ ,r_ptr_reg ,r_ptr_succ ,wr_op,empty_reg , full_reg)  
 begin  
 w_ptr_next <= w_ptr_reg;  
 r_ptr_next <= r_ptr_reg;  
 full_next <= full_reg;  
 empty_next <= empty_reg ;  
 case wr_op is  
 when "00" => -- no op  
 when "01" => -- r e a d  
 if (empty_reg /= '1') then -- not e m p t y  
 r_ptr_next <= r_ptr_succ;  
 full_next <= '0' ;  
 if (r_ptr_succ=w_ptr_reg) then  
 empty_next <='1';  
 end if ;  
 end if ;  
 when "10" => -- w r i t e  
 if (full_reg /= '1' ) then -- if fifo not f u l l we write values  
 w_ptr_next <= w_ptr_succ;  
 empty_next <= '0' ;  
 if (w_ptr_succ=r_ptr_reg) then-- otherwise stop writing because is full, write pointer and read pointer point to the same place   
 full_next <='1';  
 end if ;  
 end if ;  
 when others => -- w r i t e / r e a d ;  
 w_ptr_next <= w_ptr_succ ;  
 r_ptr_next <= r_ptr_succ ;  
 end case ;  
 end process ;  
 -- out p u t  
 full <= full_reg;  
 empty <= empty_reg;  
 end arch;  

UART TX
 library ieee;  
 use ieee.std_logic_1164.all;  
 use ieee.numeric_std.all;  
 entity uart_tx is  
 generic(  
 DBIT :  integer :=8 ; -- # data b i t s  
 SB_TICK: integer :=16 -- # t i c k s f o r stop b i t s  
 );  
 port (  
 clk, reset: in std_logic;  
 tx_start : in std_logic;  
 s_tick: in std_logic ;  
 din: in std_logic_vector ( 7 downto 0) ;  
 tx_done_tick: out std_logic;  
 tx: out std_logic  
 ) ;  
 end uart_tx ;  
 architecture arch of uart_tx 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 tx_reg , tx_next : std_logic ;  
 -- FSMD s t a t e C? data r e g is t e r s  
 begin  
 process (clk, reset)  
 begin  
 if reset= '1' then  
 state_reg <= idle;  
 s_reg <= ( others => '0' ) ;  
 n_reg <= ( others => '0' ) ;  
 b_reg <= ( others => '0' ) ;  
 tx_reg <= '1';  
 elsif ( clk'event and clk = '1' ) then  
 state_reg <= state_next;  
 s_reg <= s_next;  
 n_reg <= n_next;  
 b_reg <= b_next;  
 tx_reg <= tx_next;  
 end if ;  
 end process ;  
 -- n e x t - s t a t e l o g i c & data p a t h f u n c t i o n a l u n i t s / r o u t i n g  
 process (state_reg , s_reg ,n_reg ,b_reg, s_tick,tx_reg,tx_start,din)  
 begin  
 state_next <= state_reg;  
 s_next <= s_reg;  
 n_next <= n_reg;  
 b_next <= b_reg;  
 tx_next <= tx_reg ;  
 tx_done_tick <= '0' ;  
 case state_reg is  
 when idle =>  
 tx_next <= '1' ;  
 if tx_start = '1' then  
 state_next <= start ;  
 s_next <= ( others => '0' ) ;  
 b_next <= din ;  
 end if ;  
 when start =>  
 tx_next <= '0' ;  
 if ( s_tick = '1') then  
 if s_reg = 15 then  
 state_next <= data ;  
 s_next <= ( others => '0' ) ;  
 n_next <= ( others => '0' ) ;  
 else  
 s_next <= s_reg + 1 ;  
 end if ;  
 end if ;  
 when data =>  
 tx_next <= b_reg(0);  
 if ( s_tick = '1') then  
 if s_reg = 15 then  
 s_next <= ( others => '0' ) ;  
 b_next <= '0' & 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 =>  
 tx_next <= '1' ;  
 if ( s_tick = '1') then  
 if s_reg = (SB_TICK -1) then  
 state_next <= idle ;  
 tx_done_tick <= '1';  
 else  
 s_next <= s_reg + 1;  
 end if ;  
 end if ;  
 end case ;  
 end process ;  
 tx <= tx_reg ;  
 end arch ;  


DEBOUNCING MODULE
 library ieee;  
 use ieee.std_logic_1164.all;  
 use ieee.numeric_std.all;  
 entity debounce is  
 port(  
 clk,reset : in std_logic;  
 sw:in std_logic;  
 db_level, db_tick: out std_logic  
 );  
 end debounce ;  
 architecture exp_fsmd_arch of debounce is--20ms is typically used to debounce --666.7hz -- 3Mhz  
 constant N : integer :=21; -- f i l t e r of (2 ^ N) * 1.49 ms = 40ms debounce interval -------1.49ms is the period of my clock with frequency 666.7 ----1/666.7=1.49ms (2^X) * 1.49ms =40ms ----2^X = 40ms/1.49ms--- 2^X= 27.97----- log2 (27.97)= X --- X= 4.80--- 2^5 * 1.49ms= 40ms   
 type state_type is ( zero , wait0 , one , wait1); --the signals below we create can have 4 states  
 signal state_reg , state_next : state_type;  -- these signals  
 signal q_reg , q_next : unsigned ( N-1 downto 0 ) ;   
 signal q_load , q_dec , q_zero : std_logic ; --we use these signals as markers to go to the next stage in the design  
 begin  
 -- FSMD s t a t e C? d a t a r e g is t e r s  
 process (clk ,reset)  
 begin  
 if reset = '1' then -- if we reset we clear everything and wait for inputs  
 state_reg <= zero ; -- this is the state of the input  
 q_reg <= ( others => '0' ) ; --this is the state of the design which will progress depending of what happens with the input   
 elsif( clk'event and clk = '1' ) then --if rising edge of the clock   
 state_reg <= state_next ; -- state_next which is the signal that will be changing goes to the signal that wont change for the moment and that will be used for display until updated   
 q_reg <= q_next ; -- we update state of the design in q reg (nosrmally anything that is _next is the one that changes and stored in the one that doesnt change)  
 end if ;  
 end process ;  
 -- FSMD d a t a p a t h ( c o u n t e r ) n e x t - s t a t e  
 q_next<= (others => '1') when q_load = '1' else ---we decremetnt the states of the FSM if conditions met  
 q_reg - 1 when q_dec = '1' else  
 q_reg ;  
 q_zero<= '1' when q_next = 0 else '0' ;  
 --FSMD c o n t r o l p a t h n e x t - s t a t e  
 process ( state_reg ,sw,q_zero)  
 begin  
 q_load <= '0' ; --load the value of actual voltage state  
 q_dec <= '0' ; --decrement states  
 db_tick <= '0' ;-- if there has been a debounce 1  
 state_next <= state_reg ;  
 case state_reg is  
 --from 0 to 1  
 when zero => -- when is a 0   
                     db_level <= '0' ; --voltage level is 0 transition to 1 below  
                     if ( sw = '1') then -- if there is an input   
                               state_next <= wait1; --wait some time until 1 hs been there for a while   
                               q_load <= '1'; --load a 1  
                     end if ;  
 when wait1=>  
                     db_level <= '0' ; -- voltage level 0 as there has not been a real input  
                     if ( sw = '1' ) then  
                               q_dec <= '1';   -- decrement states  
                               if ( q_zero = '1' ) then    
                                    state_next <= one ;  
                                    db_tick <= '1'; -- debounced   
                               end if ;  
                          else -- sw = '0'  
                          state_next<= zero ; -- --REMAIN AS 0  
                     end if ;  
 -- from 1 to 0  
 when one =>  --transition from 1 to 0  
                     db_level <= '1'; -- if voltage level is 1 then wait until 0 is confirmed  
                     if ( sw = '0' ) then  
                          state_next <= wait0 ;  
                          q_load <= '1';  
                     end if ;  
 when wait0 =>  
                     db_level <= '1'; -- voltage level set as 1 as input has been stable for a while  
                     if ( sw = '0' ) then  
                          q_dec <= '1';       
                          if( q_zero = '1' ) then  
                               state_next<= zero ;  
                          end if ;  
                      else   
                      state_next<= one ;  
                     end if ;  
 end case ;  
 end process ;  
 end exp_fsmd_arch ;  

CONSTRAINT FILE
 #8I/Os_2 (Input)  
 NET "reset" LOC = "p94" ;  
 #16I/Os_1 (output)  
 NET "led[0]" LOC = "p126" ;  
 NET "led[1]" LOC = "p125" ;  
 NET "led[2]" LOC = "p124" ;  
 NET "led[3]" LOC = "p123" ;  
 NET "led[4]" LOC = "p122" ;  
 NET "led[5]" LOC = "p117" ;  
 NET "led[6]" LOC = "p116" ;  
 NET "led[7]" LOC = "p113" ;  
 #8I/Os_2 (Input)  
 NET "btn[0]" LOC = "p93" ;  
 NET "btn[1]" LOC = "p92" ;  
 NET "btn[2]" LOC = "p91" ;  
 #8I/Os_1  
 NET "rx" LOC = "p54" ;  
 NET "tx" LOC = "p58" ;  
 NET "an[0]" LOC = "p71" ;  
 NET "an[1]" LOC = "p75" ;  
 NET "an[2]" LOC = "p77" ;  
 NET "an[3]" LOC = "p82" ;  
 #16I/Os_2  
 #NET "sseg[7]" LOC = "p60"  ;  
 NET "sseg[6]" LOC = "p63"  ;  
 NET "sseg[5]" LOC = "p67" ;  
 NET "sseg[4]" LOC ="p70"  ;  
 NET "sseg[3]" LOC ="p74" ;  
 NET "sseg[3]" LOC = "p76" ;  
 NET "sseg[2]" LOC = "p81"  ;  
 NET "sseg[0]" LOC = "p83" ;  
 #Created by Constraints Editor (xc3s250e-tq144-4) - 2017/07/29  
 NET "clk" LOC = "P129"; #TNM_NET = clk;  
 TIMESPEC TS_clk = PERIOD "clk" 50 MHz HIGH 50%;  





TUTORIAL ON HOW TO ADD CLOCK TIMING CONSTRAINTS IN A MODULE

No comments:

Post a Comment