URL
https://opencores.org/ocsvn/simple_uart_for_fpga/simple_uart_for_fpga/trunk
Subversion Repositories simple_uart_for_fpga
Compare Revisions
- This comparison shows the changes necessary to convert path
/simple_uart_for_fpga
- from Rev 1 to Rev 2
- ↔ Reverse comparison
Rev 1 → Rev 2
/trunk/source/uart_tb.vhd
0,0 → 1,136
-------------------------------------------------------------------------------- |
-- PROJECT: SIMPLE UART FOR FPGA |
-------------------------------------------------------------------------------- |
-- MODULE: TESTBANCH OF UART TOP MODULE |
-- AUTHORS: Jakub Cabal <jakubcabal@gmail.com> |
-- lICENSE: The MIT License (MIT) |
-- WEBSITE: https://github.com/jakubcabal/uart_for_fpga |
-------------------------------------------------------------------------------- |
|
library IEEE; |
use IEEE.STD_LOGIC_1164.ALL; |
use IEEE.NUMERIC_STD.ALL; |
|
entity UART_TB is |
end UART_TB; |
|
architecture FULL of UART_TB is |
|
signal CLK : std_logic := '0'; |
signal RST : std_logic := '0'; |
signal tx_uart : std_logic; |
signal rx_uart : std_logic := '1'; |
signal data_vld : std_logic; |
signal data_out : std_logic_vector(7 downto 0); |
signal frame_error : std_logic; |
signal data_send : std_logic; |
signal busy : std_logic; |
signal data_in : std_logic_vector(7 downto 0); |
|
constant clk_period : time := 20 ns; |
constant uart_period : time := 8680.56 ns; |
constant data_value : std_logic_vector(7 downto 0) := "10100111"; |
constant data_value2 : std_logic_vector(7 downto 0) := "00110110"; |
|
begin |
|
utt: entity work.UART |
generic map ( |
CLK_FREQ => 50e6, |
BAUD_RATE => 115200, |
PARITY_BIT => "none" |
) |
port map ( |
CLK => CLK, |
RST => RST, |
-- UART INTERFACE |
UART_TXD => tx_uart, |
UART_RXD => rx_uart, |
-- USER DATA INPUT INTERFACE |
DATA_OUT => data_out, |
DATA_VLD => data_vld, |
FRAME_ERROR => frame_error, |
-- USER DATA OUTPUT INTERFACE |
DATA_IN => data_in, |
DATA_SEND => data_send, |
BUSY => busy |
); |
|
clk_process : process |
begin |
CLK <= '0'; |
wait for clk_period/2; |
CLK <= '1'; |
wait for clk_period/2; |
end process; |
|
test_rx_uart : process |
begin |
rx_uart <= '1'; |
RST <= '1'; |
wait for 100 ns; |
RST <= '0'; |
|
wait until rising_edge(CLK); |
|
rx_uart <= '0'; -- start bit |
wait for uart_period; |
|
for i in 0 to (data_value'LENGTH-1) loop |
rx_uart <= data_value(i); -- data bits |
wait for uart_period; |
end loop; |
|
rx_uart <= '1'; -- stop bit |
wait for uart_period; |
|
rx_uart <= '0'; -- start bit |
wait for uart_period; |
|
for i in 0 to (data_value2'LENGTH-1) loop |
rx_uart <= data_value2(i); -- data bits |
wait for uart_period; |
end loop; |
|
rx_uart <= '1'; -- stop bit |
wait for uart_period; |
|
wait; |
|
end process; |
|
test_tx_uart : process |
begin |
data_send <= '0'; |
RST <= '1'; |
wait for 100 ns; |
RST <= '0'; |
|
wait until rising_edge(CLK); |
|
data_send <= '1'; |
data_in <= data_value; |
|
wait until rising_edge(CLK); |
|
data_send <= '0'; |
|
wait until rising_edge(CLK); |
|
wait for 80 us; |
wait until rising_edge(CLK); |
|
data_send <= '1'; |
data_in <= data_value2; |
|
wait until rising_edge(CLK); |
|
data_send <= '0'; |
|
wait until rising_edge(CLK); |
|
wait; |
|
end process; |
|
end FULL; |
/trunk/source/uart.vhd
0,0 → 1,131
-------------------------------------------------------------------------------- |
-- PROJECT: SIMPLE UART FOR FPGA |
-------------------------------------------------------------------------------- |
-- MODULE: UART TOP MODULE |
-- AUTHORS: Jakub Cabal <jakubcabal@gmail.com> |
-- lICENSE: The MIT License (MIT) |
-- WEBSITE: https://github.com/jakubcabal/uart_for_fpga |
-------------------------------------------------------------------------------- |
|
library IEEE; |
use IEEE.STD_LOGIC_1164.ALL; |
use IEEE.NUMERIC_STD.ALL; |
|
-- UART FOR FPGA REQUIRES: 1 START BIT, 8 DATA BITS, 1 STOP BIT!!! |
-- OTHER PARAMETERS CAN BE SET USING GENERICS. |
|
entity UART is |
Generic ( |
CLK_FREQ : integer := 50e6; -- set system clock frequency in Hz |
BAUD_RATE : integer := 115200; -- baud rate value |
PARITY_BIT : string := "none" -- legal values: "none", "even", "odd", "mark", "space" |
); |
Port ( |
CLK : in std_logic; -- system clock |
RST : in std_logic; -- high active synchronous reset |
-- UART INTERFACE |
UART_TXD : out std_logic; |
UART_RXD : in std_logic; |
-- USER DATA INPUT INTERFACE |
DATA_IN : in std_logic_vector(7 downto 0); |
DATA_SEND : in std_logic; -- when DATA_SEND = 1, data on DATA_IN will be transmit, DATA_SEND can set to 1 only when BUSY = 0 |
BUSY : out std_logic; -- when BUSY = 1 transiever is busy, you must not set DATA_SEND to 1 |
-- USER DATA OUTPUT INTERFACE |
DATA_OUT : out std_logic_vector(7 downto 0); |
DATA_VLD : out std_logic; -- when DATA_VLD = 1, data on DATA_OUT are valid |
FRAME_ERROR : out std_logic -- when FRAME_ERROR = 1, stop bit was invalid, current and next data may be invalid |
); |
end UART; |
|
architecture FULL of UART is |
|
constant divider_value : integer := CLK_FREQ/(16*BAUD_RATE); |
|
signal uart_ticks : integer range 0 to divider_value-1; |
signal uart_clk_en : std_logic; |
signal uart_rxd_shreg : std_logic_vector(3 downto 0); |
signal uart_rxd_debounced : std_logic; |
|
begin |
|
-- ------------------------------------------------------------------------- |
-- UART OVERSAMPLING CLOCK DIVIDER |
-- ------------------------------------------------------------------------- |
|
uart_oversampling_clk_divider : process (CLK) |
begin |
if (rising_edge(CLK)) then |
if (RST = '1') then |
uart_ticks <= 0; |
uart_clk_en <= '0'; |
elsif (uart_ticks = divider_value-1) then |
uart_ticks <= 0; |
uart_clk_en <= '1'; |
else |
uart_ticks <= uart_ticks + 1; |
uart_clk_en <= '0'; |
end if; |
end if; |
end process; |
|
-- ------------------------------------------------------------------------- |
-- UART RXD DEBAUNCER |
-- ------------------------------------------------------------------------- |
|
uart_rxd_debouncer : process (CLK) |
begin |
if (rising_edge(CLK)) then |
if (RST = '1') then |
uart_rxd_shreg <= (others => '1'); |
uart_rxd_debounced <= '1'; |
else |
uart_rxd_shreg <= UART_RXD & uart_rxd_shreg(3 downto 1); |
uart_rxd_debounced <= uart_rxd_shreg(0) OR |
uart_rxd_shreg(1) OR |
uart_rxd_shreg(2) OR |
uart_rxd_shreg(3); |
end if; |
end if; |
end process; |
|
-- ------------------------------------------------------------------------- |
-- UART TRANSMITTER |
-- ------------------------------------------------------------------------- |
|
uart_tx_i: entity work.UART_TX |
generic map ( |
PARITY_BIT => PARITY_BIT |
) |
port map ( |
CLK => CLK, |
RST => RST, |
-- UART INTERFACE |
UART_CLK_EN => uart_clk_en, |
UART_TXD => UART_TXD, |
-- USER DATA INPUT INTERFACE |
DATA_IN => DATA_IN, |
DATA_SEND => DATA_SEND, |
BUSY => BUSY |
); |
|
-- ------------------------------------------------------------------------- |
-- UART RECEIVER |
-- ------------------------------------------------------------------------- |
|
uart_rx_i: entity work.UART_RX |
generic map ( |
PARITY_BIT => PARITY_BIT |
) |
port map ( |
CLK => CLK, |
RST => RST, |
-- UART INTERFACE |
UART_CLK_EN => uart_clk_en, |
UART_RXD => uart_rxd_debounced, |
-- USER DATA OUTPUT INTERFACE |
DATA_OUT => DATA_OUT, |
DATA_VLD => DATA_VLD, |
FRAME_ERROR => FRAME_ERROR |
); |
|
end FULL; |
/trunk/source/comp/uart_parity.vhd
0,0 → 1,73
-------------------------------------------------------------------------------- |
-- PROJECT: SIMPLE UART FOR FPGA |
-------------------------------------------------------------------------------- |
-- MODULE: UART PARITY BIT GENERATOR |
-- AUTHORS: Jakub Cabal <jakubcabal@gmail.com> |
-- lICENSE: The MIT License (MIT) |
-- WEBSITE: https://github.com/jakubcabal/uart_for_fpga |
-------------------------------------------------------------------------------- |
|
library IEEE; |
use IEEE.STD_LOGIC_1164.ALL; |
use IEEE.NUMERIC_STD.ALL; |
|
entity UART_PARITY is |
Generic ( |
DATA_WIDTH : integer := 8; |
PARITY_TYPE : string := "none" -- legal values: "none", "even", "odd", "mark", "space" |
); |
Port ( |
DATA_IN : in std_logic_vector(DATA_WIDTH-1 downto 0); |
PARITY_OUT : out std_logic |
); |
end UART_PARITY; |
|
architecture FULL of UART_PARITY is |
|
begin |
|
-- ------------------------------------------------------------------------- |
-- PARITY BIT GENERATOR |
-- ------------------------------------------------------------------------- |
|
even_parity_g : if (PARITY_TYPE = "even") generate |
|
process (DATA_IN) |
variable parity_temp : std_logic; |
begin |
parity_temp := '0'; |
for i in DATA_IN'range loop |
parity_temp := parity_temp XOR DATA_IN(i); |
end loop; |
PARITY_OUT <= parity_temp; |
end process; |
|
end generate; |
|
odd_parity_g : if (PARITY_TYPE = "odd") generate |
|
process (DATA_IN) |
variable parity_temp : std_logic; |
begin |
parity_temp := '1'; |
for i in DATA_IN'range loop |
parity_temp := parity_temp XOR DATA_IN(i); |
end loop; |
PARITY_OUT <= parity_temp; |
end process; |
|
end generate; |
|
mark_parity_g : if (PARITY_TYPE = "mark") generate |
|
PARITY_OUT <= '1'; |
|
end generate; |
|
space_parity_g : if (PARITY_TYPE = "space") generate |
|
PARITY_OUT <= '0'; |
|
end generate; |
|
end FULL; |
/trunk/source/comp/uart_rx.vhd
0,0 → 1,272
-------------------------------------------------------------------------------- |
-- PROJECT: SIMPLE UART FOR FPGA |
-------------------------------------------------------------------------------- |
-- MODULE: UART RECEIVER |
-- AUTHORS: Jakub Cabal <jakubcabal@gmail.com> |
-- lICENSE: The MIT License (MIT) |
-- WEBSITE: https://github.com/jakubcabal/uart_for_fpga |
-------------------------------------------------------------------------------- |
|
library IEEE; |
use IEEE.STD_LOGIC_1164.ALL; |
use IEEE.NUMERIC_STD.ALL; |
|
entity UART_RX is |
Generic ( |
PARITY_BIT : string := "none" -- legal values: "none", "even", "odd", "mark", "space" |
); |
Port ( |
CLK : in std_logic; -- system clock |
RST : in std_logic; -- high active synchronous reset |
-- UART INTERFACE |
UART_CLK_EN : in std_logic; -- oversampling (16x) UART clock enable |
UART_RXD : in std_logic; |
-- USER DATA OUTPUT INTERFACE |
DATA_OUT : out std_logic_vector(7 downto 0); |
DATA_VLD : out std_logic; -- when DATA_VLD = 1, data on DATA_OUT are valid |
FRAME_ERROR : out std_logic -- when FRAME_ERROR = 1, stop bit was invalid, current and next data may be invalid |
); |
end UART_RX; |
|
architecture FULL of UART_RX is |
|
signal rx_clk_en : std_logic; |
signal rx_ticks : unsigned(3 downto 0); |
signal rx_clk_divider_en : std_logic; |
signal rx_data : std_logic_vector(7 downto 0); |
signal rx_bit_count : unsigned(2 downto 0); |
signal rx_bit_count_en : std_logic; |
signal rx_data_shreg_en : std_logic; |
signal rx_parity_bit : std_logic; |
signal rx_parity_error : std_logic; |
signal rx_parity_check_en : std_logic; |
signal rx_output_reg_en : std_logic; |
|
type state is (idle, startbit, databits, paritybit, stopbit); |
signal rx_pstate : state; |
signal rx_nstate : state; |
|
begin |
|
-- ------------------------------------------------------------------------- |
-- UART RECEIVER CLOCK DIVIDER |
-- ------------------------------------------------------------------------- |
|
uart_rx_clk_divider : process (CLK) |
begin |
if (rising_edge(CLK)) then |
if (rx_clk_divider_en = '1') then |
if (uart_clk_en = '1') then |
if (rx_ticks = "1111") then |
rx_ticks <= (others => '0'); |
rx_clk_en <= '0'; |
elsif (rx_ticks = "0111") then |
rx_ticks <= rx_ticks + 1; |
rx_clk_en <= '1'; |
else |
rx_ticks <= rx_ticks + 1; |
rx_clk_en <= '0'; |
end if; |
else |
rx_ticks <= rx_ticks; |
rx_clk_en <= '0'; |
end if; |
else |
rx_ticks <= (others => '0'); |
rx_clk_en <= '0'; |
end if; |
end if; |
end process; |
|
-- ------------------------------------------------------------------------- |
-- UART RECEIVER BIT COUNTER |
-- ------------------------------------------------------------------------- |
|
uart_rx_bit_counter : process (CLK) |
begin |
if (rising_edge(CLK)) then |
if (RST = '1') then |
rx_bit_count <= (others => '0'); |
elsif (rx_bit_count_en = '1' AND rx_clk_en = '1') then |
if (rx_bit_count = "111") then |
rx_bit_count <= (others => '0'); |
else |
rx_bit_count <= rx_bit_count + 1; |
end if; |
end if; |
end if; |
end process; |
|
-- ------------------------------------------------------------------------- |
-- UART RECEIVER DATA SHIFT REGISTER |
-- ------------------------------------------------------------------------- |
|
uart_rx_data_shift_reg : process (CLK) |
begin |
if (rising_edge(CLK)) then |
if (RST = '1') then |
rx_data <= (others => '0'); |
elsif (rx_clk_en = '1' AND rx_data_shreg_en = '1') then |
rx_data <= UART_RXD & rx_data(7 downto 1); |
end if; |
end if; |
end process; |
|
DATA_OUT <= rx_data; |
|
-- ------------------------------------------------------------------------- |
-- UART RECEIVER PARITY GENERATOR AND CHECK |
-- ------------------------------------------------------------------------- |
|
uart_rx_parity_g : if (PARITY_BIT /= "none") generate |
uart_rx_parity_gen_i: entity work.UART_PARITY |
generic map ( |
DATA_WIDTH => 8, |
PARITY_TYPE => PARITY_BIT |
) |
port map ( |
DATA_IN => rx_data, |
PARITY_OUT => rx_parity_bit |
); |
|
uart_rx_parity_check_reg : process (CLK) |
begin |
if (rising_edge(CLK)) then |
if (RST = '1') then |
rx_parity_error <= '0'; |
elsif (rx_parity_check_en = '1') then |
rx_parity_error <= rx_parity_bit XOR UART_RXD; |
end if; |
end if; |
end process; |
end generate; |
|
uart_rx_noparity_g : if (PARITY_BIT = "none") generate |
rx_parity_error <= '0'; |
end generate; |
|
-- ------------------------------------------------------------------------- |
-- UART RECEIVER OUTPUT REGISTER |
-- ------------------------------------------------------------------------- |
|
uart_rx_output_reg : process (CLK) |
begin |
if (rising_edge(CLK)) then |
if (RST = '1') then |
DATA_VLD <= '0'; |
FRAME_ERROR <= '0'; |
else |
if (rx_output_reg_en = '1') then |
DATA_VLD <= NOT rx_parity_error AND UART_RXD; |
FRAME_ERROR <= NOT UART_RXD; |
else |
DATA_VLD <= '0'; |
FRAME_ERROR <= '0'; |
end if; |
end if; |
end if; |
end process; |
|
-- ------------------------------------------------------------------------- |
-- UART RECEIVER FSM |
-- ------------------------------------------------------------------------- |
|
-- PRESENT STATE REGISTER |
process (CLK) |
begin |
if (rising_edge(CLK)) then |
if (RST = '1') then |
rx_pstate <= idle; |
else |
rx_pstate <= rx_nstate; |
end if; |
end if; |
end process; |
|
-- NEXT STATE AND OUTPUTS LOGIC |
process (rx_pstate, UART_RXD, rx_clk_en, rx_bit_count) |
begin |
case rx_pstate is |
|
when idle => |
rx_output_reg_en <= '0'; |
rx_bit_count_en <= '0'; |
rx_data_shreg_en <= '0'; |
rx_clk_divider_en <= '0'; |
rx_parity_check_en <= '0'; |
|
if (UART_RXD = '0') then |
rx_nstate <= startbit; |
else |
rx_nstate <= idle; |
end if; |
|
when startbit => |
rx_output_reg_en <= '0'; |
rx_bit_count_en <= '0'; |
rx_data_shreg_en <= '0'; |
rx_clk_divider_en <= '1'; |
rx_parity_check_en <= '0'; |
|
if (rx_clk_en = '1') then |
rx_nstate <= databits; |
else |
rx_nstate <= startbit; |
end if; |
|
when databits => |
rx_output_reg_en <= '0'; |
rx_bit_count_en <= '1'; |
rx_data_shreg_en <= '1'; |
rx_clk_divider_en <= '1'; |
rx_parity_check_en <= '0'; |
|
if ((rx_clk_en = '1') AND (rx_bit_count = "111")) then |
if (PARITY_BIT = "none") then |
rx_nstate <= stopbit; |
else |
rx_nstate <= paritybit; |
end if ; |
else |
rx_nstate <= databits; |
end if; |
|
when paritybit => |
rx_output_reg_en <= '0'; |
rx_bit_count_en <= '0'; |
rx_data_shreg_en <= '0'; |
rx_clk_divider_en <= '1'; |
rx_parity_check_en <= '1'; |
|
if (rx_clk_en = '1') then |
rx_nstate <= stopbit; |
else |
rx_nstate <= paritybit; |
end if; |
|
when stopbit => |
rx_bit_count_en <= '0'; |
rx_data_shreg_en <= '0'; |
rx_clk_divider_en <= '1'; |
rx_parity_check_en <= '0'; |
|
if (rx_clk_en = '1') then |
rx_nstate <= idle; |
rx_output_reg_en <= '1'; |
else |
rx_nstate <= stopbit; |
rx_output_reg_en <= '0'; |
end if; |
|
when others => |
rx_output_reg_en <= '0'; |
rx_bit_count_en <= '0'; |
rx_data_shreg_en <= '0'; |
rx_clk_divider_en <= '0'; |
rx_parity_check_en <= '0'; |
rx_nstate <= idle; |
|
end case; |
end process; |
|
end FULL; |
/trunk/source/comp/uart_tx.vhd
0,0 → 1,269
-------------------------------------------------------------------------------- |
-- PROJECT: SIMPLE UART FOR FPGA |
-------------------------------------------------------------------------------- |
-- MODULE: UART TRANSMITTER |
-- AUTHORS: Jakub Cabal <jakubcabal@gmail.com> |
-- lICENSE: The MIT License (MIT) |
-- WEBSITE: https://github.com/jakubcabal/uart_for_fpga |
-------------------------------------------------------------------------------- |
|
library IEEE; |
use IEEE.STD_LOGIC_1164.ALL; |
use IEEE.NUMERIC_STD.ALL; |
|
entity UART_TX is |
Generic ( |
PARITY_BIT : string := "none" -- legal values: "none", "even", "odd", "mark", "space" |
); |
Port ( |
CLK : in std_logic; -- system clock |
RST : in std_logic; -- high active synchronous reset |
-- UART INTERFACE |
UART_CLK_EN : in std_logic; -- oversampling (16x) UART clock enable |
UART_TXD : out std_logic; |
-- USER DATA INPUT INTERFACE |
DATA_IN : in std_logic_vector(7 downto 0); |
DATA_SEND : in std_logic; -- when DATA_SEND = 1, data on DATA_IN will be transmit, DATA_SEND can set to 1 only when BUSY = 0 |
BUSY : out std_logic -- when BUSY = 1 transiever is busy, you must not set DATA_SEND to 1 |
); |
end UART_TX; |
|
architecture FULL of UART_TX is |
|
signal tx_clk_en : std_logic; |
signal tx_clk_divider_en : std_logic; |
signal tx_ticks : unsigned(3 downto 0); |
signal tx_data : std_logic_vector(7 downto 0); |
signal tx_bit_count : unsigned(2 downto 0); |
signal tx_bit_count_en : std_logic; |
signal tx_busy : std_logic; |
signal tx_parity_bit : std_logic; |
signal tx_data_out_sel : std_logic_vector(1 downto 0); |
|
type state is (idle, txsync, startbit, databits, paritybit, stopbit); |
signal tx_pstate : state; |
signal tx_nstate : state; |
|
begin |
|
BUSY <= tx_busy; |
|
-- ------------------------------------------------------------------------- |
-- UART TRANSMITTER CLOCK DIVIDER |
-- ------------------------------------------------------------------------- |
|
uart_tx_clk_divider : process (CLK) |
begin |
if (rising_edge(CLK)) then |
if (tx_clk_divider_en = '1') then |
if (uart_clk_en = '1') then |
if (tx_ticks = "1111") then |
tx_ticks <= (others => '0'); |
tx_clk_en <= '0'; |
elsif (tx_ticks = "0001") then |
tx_ticks <= tx_ticks + 1; |
tx_clk_en <= '1'; |
else |
tx_ticks <= tx_ticks + 1; |
tx_clk_en <= '0'; |
end if; |
else |
tx_ticks <= tx_ticks; |
tx_clk_en <= '0'; |
end if; |
else |
tx_ticks <= (others => '0'); |
tx_clk_en <= '0'; |
end if; |
end if; |
end process; |
|
-- ------------------------------------------------------------------------- |
-- UART TRANSMITTER INPUT DATA REGISTER |
-- ------------------------------------------------------------------------- |
|
uart_tx_input_data_reg : process (CLK) |
begin |
if (rising_edge(CLK)) then |
if (RST = '1') then |
tx_data <= (others => '0'); |
elsif (DATA_SEND = '1' AND tx_busy = '0') then |
tx_data <= DATA_IN; |
end if; |
end if; |
end process; |
|
-- ------------------------------------------------------------------------- |
-- UART TRANSMITTER BIT COUNTER |
-- ------------------------------------------------------------------------- |
|
uart_tx_bit_counter : process (CLK) |
begin |
if (rising_edge(CLK)) then |
if (RST = '1') then |
tx_bit_count <= (others => '0'); |
elsif (tx_bit_count_en = '1' AND tx_clk_en = '1') then |
if (tx_bit_count = "111") then |
tx_bit_count <= (others => '0'); |
else |
tx_bit_count <= tx_bit_count + 1; |
end if; |
end if; |
end if; |
end process; |
|
-- ------------------------------------------------------------------------- |
-- UART TRANSMITTER PARITY GENERATOR |
-- ------------------------------------------------------------------------- |
|
uart_tx_parity_g : if (PARITY_BIT /= "none") generate |
uart_tx_parity_gen_i: entity work.UART_PARITY |
generic map ( |
DATA_WIDTH => 8, |
PARITY_TYPE => PARITY_BIT |
) |
port map ( |
DATA_IN => tx_data, |
PARITY_OUT => tx_parity_bit |
); |
end generate; |
|
uart_tx_noparity_g : if (PARITY_BIT = "none") generate |
tx_parity_bit <= 'Z'; |
end generate; |
|
-- ------------------------------------------------------------------------- |
-- UART TRANSMITTER OUTPUT DATA REGISTER |
-- ------------------------------------------------------------------------- |
|
uart_tx_output_data_reg : process (CLK) |
begin |
if (rising_edge(CLK)) then |
if (RST = '1') then |
UART_TXD <= '1'; |
else |
case tx_data_out_sel is |
when "01" => -- START BIT |
UART_TXD <= '0'; |
when "10" => -- DATA BITS |
UART_TXD <= tx_data(to_integer(tx_bit_count)); |
when "11" => -- PARITY BIT |
UART_TXD <= tx_parity_bit; |
when others => -- STOP BIT OR IDLE |
UART_TXD <= '1'; |
end case; |
end if; |
end if; |
end process; |
|
-- ------------------------------------------------------------------------- |
-- UART TRANSMITTER FSM |
-- ------------------------------------------------------------------------- |
|
-- PRESENT STATE REGISTER |
process (CLK) |
begin |
if (rising_edge(CLK)) then |
if (RST = '1') then |
tx_pstate <= idle; |
else |
tx_pstate <= tx_nstate; |
end if; |
end if; |
end process; |
|
-- NEXT STATE AND OUTPUTS LOGIC |
process (tx_pstate, DATA_SEND, tx_clk_en, tx_bit_count) |
begin |
|
case tx_pstate is |
|
when idle => |
tx_busy <= '0'; |
tx_data_out_sel <= "00"; |
tx_bit_count_en <= '0'; |
tx_clk_divider_en <= '0'; |
|
if (DATA_SEND = '1') then |
tx_nstate <= txsync; |
else |
tx_nstate <= idle; |
end if; |
|
when txsync => |
tx_busy <= '1'; |
tx_data_out_sel <= "00"; |
tx_bit_count_en <= '0'; |
tx_clk_divider_en <= '1'; |
|
if (tx_clk_en = '1') then |
tx_nstate <= startbit; |
else |
tx_nstate <= txsync; |
end if; |
|
when startbit => |
tx_busy <= '1'; |
tx_data_out_sel <= "01"; |
tx_bit_count_en <= '0'; |
tx_clk_divider_en <= '1'; |
|
if (tx_clk_en = '1') then |
tx_nstate <= databits; |
else |
tx_nstate <= startbit; |
end if; |
|
when databits => |
tx_busy <= '1'; |
tx_data_out_sel <= "10"; |
tx_bit_count_en <= '1'; |
tx_clk_divider_en <= '1'; |
|
if ((tx_clk_en = '1') AND (tx_bit_count = "111")) then |
if (PARITY_BIT = "none") then |
tx_nstate <= stopbit; |
else |
tx_nstate <= paritybit; |
end if ; |
else |
tx_nstate <= databits; |
end if; |
|
when paritybit => |
tx_busy <= '1'; |
tx_data_out_sel <= "11"; |
tx_bit_count_en <= '0'; |
tx_clk_divider_en <= '1'; |
|
if (tx_clk_en = '1') then |
tx_nstate <= stopbit; |
else |
tx_nstate <= paritybit; |
end if; |
|
when stopbit => |
tx_busy <= '0'; |
tx_data_out_sel <= "00"; |
tx_bit_count_en <= '0'; |
tx_clk_divider_en <= '1'; |
|
if (DATA_SEND = '1') then |
tx_nstate <= txsync; |
elsif (tx_clk_en = '1') then |
tx_nstate <= idle; |
else |
tx_nstate <= stopbit; |
end if; |
|
when others => |
tx_busy <= '1'; |
tx_data_out_sel <= "00"; |
tx_bit_count_en <= '0'; |
tx_clk_divider_en <= '0'; |
tx_nstate <= idle; |
|
end case; |
end process; |
|
end FULL; |
/trunk/LICENSE
0,0 → 1,22
The MIT License (MIT) |
|
Copyright (c) 2015 Jakub Cabal |
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
of this software and associated documentation files (the "Software"), to deal |
in the Software without restriction, including without limitation the rights |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
copies of the Software, and to permit persons to whom the Software is |
furnished to do so, subject to the following conditions: |
|
The above copyright notice and this permission notice shall be included in all |
copies or substantial portions of the Software. |
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
SOFTWARE. |
|
/trunk/example/uart_loopback.vhd
0,0 → 1,67
-------------------------------------------------------------------------------- |
-- PROJECT: SIMPLE UART FOR FPGA |
-------------------------------------------------------------------------------- |
-- MODULE: UART LOOPBACK EXAMPLE TOP MODULE |
-- AUTHORS: Jakub Cabal <jakubcabal@gmail.com> |
-- lICENSE: The MIT License (MIT) |
-- WEBSITE: https://github.com/jakubcabal/uart_for_fpga |
-------------------------------------------------------------------------------- |
|
library IEEE; |
use IEEE.STD_LOGIC_1164.ALL; |
use IEEE.NUMERIC_STD.ALL; |
|
-- UART FOR FPGA REQUIRES: 1 START BIT, 8 DATA BITS, 1 STOP BIT!!! |
-- OTHER PARAMETERS CAN BE SET USING GENERICS. |
|
entity UART_LOOPBACK is |
Generic ( |
CLK_FREQ : integer := 50e6; -- set system clock frequency in Hz |
BAUD_RATE : integer := 115200; -- baud rate value |
PARITY_BIT : string := "none" -- legal values: "none", "even", "odd", "mark", "space" |
); |
Port ( |
CLK : in std_logic; -- system clock |
RST_N : in std_logic; -- low active synchronous reset |
-- UART INTERFACE |
UART_TXD : out std_logic; |
UART_RXD : in std_logic; |
-- DEBUG INTERFACE |
BUSY : out std_logic; |
FRAME_ERR : out std_logic |
); |
end UART_LOOPBACK; |
|
architecture FULL of UART_LOOPBACK is |
|
signal data : std_logic_vector(7 downto 0); |
signal valid : std_logic; |
signal reset : std_logic; |
|
begin |
|
reset <= not RST_N; |
|
uart_i: entity work.UART |
generic map ( |
CLK_FREQ => CLK_FREQ, |
BAUD_RATE => BAUD_RATE, |
PARITY_BIT => PARITY_BIT |
) |
port map ( |
CLK => CLK, |
RST => reset, |
-- UART INTERFACE |
UART_TXD => UART_TXD, |
UART_RXD => UART_RXD, |
-- USER DATA OUTPUT INTERFACE |
DATA_OUT => data, |
DATA_VLD => valid, |
FRAME_ERROR => FRAME_ERR, |
-- USER DATA INPUT INTERFACE |
DATA_IN => data, |
DATA_SEND => valid, |
BUSY => BUSY |
); |
|
end FULL; |
/trunk/example/uart_loopback_tb.vhd
0,0 → 1,115
-------------------------------------------------------------------------------- |
-- PROJECT: SIMPLE UART FOR FPGA |
-------------------------------------------------------------------------------- |
-- MODULE: TESTBANCH OF UART LOOPBACK EXAMPLE TOP MODULE |
-- AUTHORS: Jakub Cabal <jakubcabal@gmail.com> |
-- lICENSE: The MIT License (MIT) |
-- WEBSITE: https://github.com/jakubcabal/uart_for_fpga |
-------------------------------------------------------------------------------- |
|
library IEEE; |
use IEEE.STD_LOGIC_1164.ALL; |
use IEEE.NUMERIC_STD.ALL; |
|
entity UART_LOOPBACK_TB is |
end UART_LOOPBACK_TB; |
|
architecture FULL of UART_LOOPBACK_TB is |
|
signal CLK : std_logic := '0'; |
signal RST_N : std_logic := '0'; |
signal tx_uart : std_logic; |
signal rx_uart : std_logic := '1'; |
signal busy : std_logic; |
signal frame_error : std_logic; |
|
constant clk_period : time := 20 ns; |
constant uart_period : time := 8680.56 ns; |
constant data_value : std_logic_vector(7 downto 0) := "10100111"; |
constant data_value2 : std_logic_vector(7 downto 0) := "00110110"; |
|
begin |
|
utt: entity work.UART_LOOPBACK |
generic map ( |
CLK_FREQ => 50e6, |
BAUD_RATE => 115200, |
PARITY_BIT => "none" |
) |
port map ( |
CLK => CLK, |
RST_N => RST_N, |
-- UART INTERFACE |
UART_TXD => tx_uart, |
UART_RXD => rx_uart, |
-- DEBUG INTERFACE |
BUSY => busy, |
FRAME_ERR => frame_error |
); |
|
clk_process : process |
begin |
CLK <= '0'; |
wait for clk_period/2; |
CLK <= '1'; |
wait for clk_period/2; |
end process; |
|
test_rx_uart : process |
begin |
rx_uart <= '1'; |
RST_N <= '0'; |
wait for 100 ns; |
RST_N <= '1'; |
|
wait for uart_period; |
|
rx_uart <= '0'; -- start bit |
wait for uart_period; |
|
for i in 0 to (data_value'LENGTH-1) loop |
rx_uart <= data_value(i); -- data bits |
wait for uart_period; |
end loop; |
|
rx_uart <= '1'; -- stop bit |
wait for uart_period; |
|
rx_uart <= '0'; -- start bit |
wait for uart_period; |
|
for i in 0 to (data_value2'LENGTH-1) loop |
rx_uart <= data_value2(i); -- data bits |
wait for uart_period; |
end loop; |
|
rx_uart <= '1'; -- stop bit |
wait for uart_period; |
|
rx_uart <= '0'; -- start bit |
wait for uart_period; |
|
for i in 0 to (data_value'LENGTH-1) loop |
rx_uart <= data_value(i); -- data bits |
wait for uart_period; |
end loop; |
|
rx_uart <= '1'; -- stop bit |
wait for uart_period; |
|
rx_uart <= '0'; -- start bit |
wait for uart_period; |
|
for i in 0 to (data_value2'LENGTH-1) loop |
rx_uart <= data_value2(i); -- data bits |
wait for uart_period; |
end loop; |
|
rx_uart <= '1'; -- stop bit |
wait for uart_period; |
|
wait; |
|
end process; |
|
end FULL; |
/trunk/README.md
0,0 → 1,32
# Simple UART for FPGA |
|
Simple UART for FPGA is UART (Universal Asynchronous Receiver & Transmitter) controller for serial communication with an FPGA. The UART controller was implemented using VHDL 93 and is applicable to any FPGA. |
|
**Simple UART for FPGA requires: 1 start bit, 8 data bits, 1 stop bit!** |
|
The UART controller was simulated and tested in hardware. |
|
# Inputs and outputs ports: |
|
Port name | IN/OUT | Width | Port description |
---|:---:|:---:|--- |
CLK | IN | 1b | System clock. |
RST | IN | 1b | High active synchronous reset. |
UART_TXD | OUT | 1b | Serial transmit data. |
UART_RXD | IN | 1b | Serial receive data. |
DATA_IN | IN | 8b | Data byte for transmit. |
DATA_SEND | IN | 1b | Send data byte for transmit. |
BUSY | OUT | 1b | Transmitter is busy, can not send next data. |
DATA_OUT | OUT | 8b | Received data byte. |
DATA_VLD | OUT | 1b | Received data byte is valid. |
FRAME_ERROR | OUT | 1b | Stop bit is invalid, current and next data may be corrupted. |
|
# Synthesis resource usage summary: |
|
Parity | LE (LUT) | FF | BRAM |
:---:|:---:|:---:|:---: |
none | 80 | 55 | 0 |
even/odd | 91 | 58 | 0 |
mark/space | 84 | 58 | 0 |
|
*Synthesis was performed using Quartus II 64-Bit Version 13.0.1 for FPGA Altera Cyclone II with these settings: 115200 baud rate and 50 MHz system clock .* |