Skip to content

Commit e556cb6

Browse files
authoredDec 23, 2019
Merge pull request #2 from jakubcabal/dev
Merge version 1.2 of UART module to master.
2 parents 7235180 + 0cf9c37 commit e556cb6

11 files changed

+336
-345
lines changed
 

‎README.md

+9-10
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,16 @@ USE_DEBOUNCER : boolean := True -- enable/disable debouncer
3636

3737
## Table of resource usage summary:
3838

39-
Use debouncer | Parity type | LE (LUT+FF) | LUT | FF | BRAM | Fmax
39+
Use debouncer | Parity type | LE (LUT+FF) | LUT | FF | M9k | Fmax
4040
:---:|:---:|:---:|:---:|:---:|:---:|:---:
41-
True | none | 74 | 59 | 53 | 0 | 220.0 MHz
42-
True | even/odd | 81 | 70 | 56 | 0 | 193.3 MHz
43-
True | mark/space | 78 | 63 | 56 | 0 | 210.2 MHz
44-
False | none | 70 | 57 | 49 | 0 | 182.3 MHz
45-
False | even/odd | 78 | 68 | 52 | 0 | 183.5 MHz
46-
False | mark/space | 74 | 61 | 52 | 0 | 186.2 MHz
41+
True | none | 76 | 62 | 56 | 0 | 304.8 MHz
42+
True | even/odd | 86 | 73 | 59 | 0 | 277.3 MHz
43+
True | mark/space | 80 | 66 | 59 | 0 | 292.3 MHz
44+
False | none | 73 | 60 | 52 | 0 | 308.7 MHz
45+
False | even/odd | 79 | 71 | 55 | 0 | 278.7 MHz
46+
False | mark/space | 77 | 64 | 55 | 0 | 338.0 MHz
4747

48-
*Implementation was performed using Quartus Prime Lite Edition 17.0.0 for FPGA Altera Cyclone IV E EP4CE6E22C8. Setting of some generics: BAUD_RATE = 115200, CLK_FREQ = 50e6.*
48+
*Implementation was performed using Quartus Prime Lite Edition 18.1.0 for Intel Cyclone 10 FPGA (10CL025YU256C8G). Setting of some generics: BAUD_RATE = 115200, CLK_FREQ = 50e6.*
4949

5050
## Simulation:
5151

@@ -57,8 +57,7 @@ vsim -do sim/sim.tcl
5757

5858
## UART loopback example:
5959

60-
The UART loopback example design is for testing data transfer between FPGA and PC.
61-
I use it on my cheap FPGA board ([EP4CE6 Starter Board](http://www.ebay.com/itm/111975895262) with Altera FPGA Cyclone IV EP4CE6E22C8) together with external USB to UART Bridge.
60+
The UART loopback example design is for testing data transfer between FPGA and PC. I use it on my FPGA board [CYC1000](https://shop.trenz-electronic.de/en/TEI0003-02-CYC1000-with-Cyclone-10-FPGA-8-MByte-SDRAM) with Intel Cyclone 10 FPGA (10CL025YU256C8G) and FTDI USB to UART Bridge.
6261

6362
## License:
6463

Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
#-------------------------------------------------------------------------------
22
# PROJECT: SIMPLE UART FOR FPGA
33
#-------------------------------------------------------------------------------
4-
# NAME: QUARTUS PROJECT FILE
54
# AUTHORS: Jakub Cabal <jakubcabal@gmail.com>
65
# LICENSE: The MIT License (MIT), please read LICENSE file
76
# WEBSITE: https://github.com/jakubcabal/uart-for-fpga
87
#-------------------------------------------------------------------------------
98

10-
PROJECT_REVISION = "uart_loopback"
9+
PROJECT_REVISION = "UART_LOOPBACK_CYC1000"
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,31 @@
11
#-------------------------------------------------------------------------------
22
# PROJECT: SIMPLE UART FOR FPGA
33
#-------------------------------------------------------------------------------
4-
# NAME: QUARTUS SETTINGS FILE FOR EP4CE6 STARTER BOARD
54
# AUTHORS: Jakub Cabal <jakubcabal@gmail.com>
65
# LICENSE: The MIT License (MIT), please read LICENSE file
76
# WEBSITE: https://github.com/jakubcabal/uart-for-fpga
87
#-------------------------------------------------------------------------------
98

10-
set_global_assignment -name FAMILY "Cyclone IV E"
11-
set_global_assignment -name DEVICE EP4CE6E22C8
12-
set_global_assignment -name TOP_LEVEL_ENTITY UART_LOOPBACK
9+
# QUARTUS SETTINGS FILE FOR CYC1000 BOARD
10+
set_global_assignment -name FAMILY "Cyclone 10 LP"
11+
set_global_assignment -name DEVICE 10CL025YU256C8G
12+
set_global_assignment -name TOP_LEVEL_ENTITY UART_LOOPBACK_CYC1000
1313

1414
# PROJECT VHDL FILES
15-
set_global_assignment -name VHDL_FILE ../uart_loopback.vhd
16-
set_global_assignment -name VHDL_FILE ../../rtl/uart.vhd
17-
set_global_assignment -name VHDL_FILE ../../rtl/comp/uart_tx.vhd
18-
set_global_assignment -name VHDL_FILE ../../rtl/comp/uart_rx.vhd
15+
set_global_assignment -name VHDL_FILE ../../rtl/comp/uart_clk_div.vhd
1916
set_global_assignment -name VHDL_FILE ../../rtl/comp/uart_parity.vhd
2017
set_global_assignment -name VHDL_FILE ../../rtl/comp/uart_debouncer.vhd
18+
set_global_assignment -name VHDL_FILE ../../rtl/comp/uart_tx.vhd
19+
set_global_assignment -name VHDL_FILE ../../rtl/comp/uart_rx.vhd
20+
set_global_assignment -name VHDL_FILE ../../rtl/uart.vhd
21+
set_global_assignment -name VHDL_FILE ../rst_sync.vhd
22+
set_global_assignment -name VHDL_FILE ../uart_loopback_cyc1000.vhd
2123

2224
# TIMING CONSTRAINTS
23-
set_global_assignment -name SDC_FILE ../timing_constraints.sdc
25+
set_global_assignment -name SDC_FILE ./uart_loopback_cyc1000.sdc
2426

25-
# FPGA PINS ASSIGNMENT FOR EP4CE6 STARTER BOARD
26-
set_location_assignment PIN_91 -to CLK
27-
set_location_assignment PIN_25 -to RST
28-
set_location_assignment PIN_85 -to UART_TXD
29-
set_location_assignment PIN_86 -to UART_RXD
27+
# FPGA PINS ASSIGNMENT
28+
set_location_assignment PIN_M2 -to CLK_12M
29+
set_location_assignment PIN_N6 -to RST_BTN_N
30+
set_location_assignment PIN_T7 -to UART_TXD
31+
set_location_assignment PIN_R7 -to UART_RXD
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
#-------------------------------------------------------------------------------
22
# PROJECT: SIMPLE UART FOR FPGA
33
#-------------------------------------------------------------------------------
4-
# MODULE: TIMING CONSTRAINTS
54
# AUTHORS: Jakub Cabal <jakubcabal@gmail.com>
65
# LICENSE: The MIT License (MIT), please read LICENSE file
76
# WEBSITE: https://github.com/jakubcabal/uart-for-fpga
87
#-------------------------------------------------------------------------------
98

10-
create_clock -name CLK50 -period 20.000 [get_ports {CLK}]
9+
create_clock -name CLK12M -period 12MHz [get_ports {CLK_12M}]

‎example/rst_sync.vhd

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
--------------------------------------------------------------------------------
2+
-- PROJECT: SIMPLE UART FOR FPGA
3+
--------------------------------------------------------------------------------
4+
-- AUTHORS: Jakub Cabal <jakubcabal@gmail.com>
5+
-- LICENSE: The MIT License (MIT), please read LICENSE file
6+
-- WEBSITE: https://github.com/jakubcabal/uart-for-fpga
7+
--------------------------------------------------------------------------------
8+
9+
library IEEE;
10+
use IEEE.STD_LOGIC_1164.ALL;
11+
use IEEE.NUMERIC_STD.ALL;
12+
13+
entity RST_SYNC is
14+
Port (
15+
CLK : in std_logic;
16+
ASYNC_RST : in std_logic;
17+
SYNCED_RST : out std_logic
18+
);
19+
end entity;
20+
21+
architecture RTL of RST_SYNC is
22+
23+
attribute ALTERA_ATTRIBUTE : string;
24+
attribute PRESERVE : boolean;
25+
26+
signal meta_reg : std_logic;
27+
signal reset_reg : std_logic;
28+
29+
attribute ALTERA_ATTRIBUTE of RTL : architecture is "-name SDC_STATEMENT ""set_false_path -to [get_registers {*RST_SYNC:*|meta_reg}] """;
30+
attribute ALTERA_ATTRIBUTE of meta_reg : signal is "-name SYNCHRONIZER_IDENTIFICATION ""FORCED IF ASYNCHRONOUS""";
31+
attribute ALTERA_ATTRIBUTE of reset_reg : signal is "-name SYNCHRONIZER_IDENTIFICATION ""FORCED IF ASYNCHRONOUS""";
32+
attribute PRESERVE of meta_reg : signal is TRUE;
33+
attribute PRESERVE of reset_reg : signal is TRUE;
34+
35+
begin
36+
37+
process (CLK, ASYNC_RST)
38+
begin
39+
if (ASYNC_RST = '1') then
40+
meta_reg <= '1';
41+
reset_reg <= '1';
42+
elsif (rising_edge(CLK)) then
43+
meta_reg <= '0';
44+
reset_reg <= meta_reg;
45+
end if;
46+
end process;
47+
48+
SYNCED_RST <= reset_reg;
49+
50+
end architecture;
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
--------------------------------------------------------------------------------
22
-- PROJECT: SIMPLE UART FOR FPGA
33
--------------------------------------------------------------------------------
4-
-- MODULE: UART LOOPBACK EXAMPLE TOP MODULE
54
-- AUTHORS: Jakub Cabal <jakubcabal@gmail.com>
65
-- LICENSE: The MIT License (MIT), please read LICENSE file
76
-- WEBSITE: https://github.com/jakubcabal/uart-for-fpga
@@ -11,32 +10,45 @@ library IEEE;
1110
use IEEE.STD_LOGIC_1164.ALL;
1211
use IEEE.NUMERIC_STD.ALL;
1312

13+
-- UART LOOPBACK EXAMPLE TOP MODULE FOR CYC1000 BOARD
14+
-- ==================================================
1415
-- UART FOR FPGA REQUIRES: 1 START BIT, 8 DATA BITS, 1 STOP BIT!!!
1516
-- OTHER PARAMETERS CAN BE SET USING GENERICS.
1617

17-
entity UART_LOOPBACK is
18+
entity UART_LOOPBACK_CYC1000 is
1819
Generic (
19-
CLK_FREQ : integer := 50e6; -- set system clock frequency in Hz
20+
CLK_FREQ : integer := 12e6; -- set system clock frequency in Hz
2021
BAUD_RATE : integer := 115200; -- baud rate value
2122
PARITY_BIT : string := "none"; -- legal values: "none", "even", "odd", "mark", "space"
2223
USE_DEBOUNCER : boolean := True -- enable/disable debouncer
2324
);
2425
Port (
25-
CLK : in std_logic; -- system clock
26-
RST : in std_logic; -- high active synchronous reset
26+
CLK_12M : in std_logic; -- system clock 12 MHz
27+
RST_BTN_N : in std_logic; -- low active reset button
2728
-- UART INTERFACE
28-
UART_TXD : out std_logic;
29-
UART_RXD : in std_logic
29+
UART_TXD : out std_logic;
30+
UART_RXD : in std_logic
3031
);
31-
end UART_LOOPBACK;
32+
end entity;
3233

33-
architecture FULL of UART_LOOPBACK is
34+
architecture RTL of UART_LOOPBACK_CYC1000 is
3435

35-
signal data : std_logic_vector(7 downto 0);
36-
signal valid : std_logic;
36+
signal rst_btn : std_logic;
37+
signal reset : std_logic;
38+
signal data : std_logic_vector(7 downto 0);
39+
signal valid : std_logic;
3740

3841
begin
3942

43+
rst_btn <= not RST_BTN_N;
44+
45+
rst_sync_i : entity work.RST_SYNC
46+
port map (
47+
CLK => CLK_12M,
48+
ASYNC_RST => rst_btn,
49+
SYNCED_RST => reset
50+
);
51+
4052
uart_i: entity work.UART
4153
generic map (
4254
CLK_FREQ => CLK_FREQ,
@@ -45,8 +57,8 @@ begin
4557
USE_DEBOUNCER => USE_DEBOUNCER
4658
)
4759
port map (
48-
CLK => CLK,
49-
RST => RST,
60+
CLK => CLK_12M,
61+
RST => reset,
5062
-- UART INTERFACE
5163
UART_TXD => UART_TXD,
5264
UART_RXD => UART_RXD,
@@ -60,4 +72,4 @@ begin
6072
DIN_RDY => open
6173
);
6274

63-
end FULL;
75+
end architecture;

‎example/uart_loopback_tb.vhd

-115
This file was deleted.

‎rtl/comp/uart_clk_div.vhd

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
--------------------------------------------------------------------------------
2+
-- PROJECT: SIMPLE UART FOR FPGA
3+
--------------------------------------------------------------------------------
4+
-- AUTHORS: Jakub Cabal <jakubcabal@gmail.com>
5+
-- LICENSE: The MIT License (MIT), please read LICENSE file
6+
-- WEBSITE: https://github.com/jakubcabal/uart-for-fpga
7+
--------------------------------------------------------------------------------
8+
9+
library IEEE;
10+
use IEEE.STD_LOGIC_1164.ALL;
11+
use IEEE.NUMERIC_STD.ALL;
12+
use IEEE.MATH_REAL.ALL;
13+
14+
entity UART_CLK_DIV is
15+
Generic (
16+
DIV_MAX_VAL : integer := 16;
17+
DIV_MARK_POS : integer := 1
18+
);
19+
Port (
20+
CLK : in std_logic; -- system clock
21+
RST : in std_logic; -- high active synchronous reset
22+
-- USER INTERFACE
23+
CLEAR : in std_logic; -- clock divider counter clear
24+
ENABLE : in std_logic; -- clock divider counter enable
25+
DIV_MARK : out std_logic -- output divider mark (divided clock enable)
26+
);
27+
end entity;
28+
29+
architecture RTL of UART_CLK_DIV is
30+
31+
constant CLK_DIV_WIDTH : integer := integer(ceil(log2(real(DIV_MAX_VAL))));
32+
33+
signal clk_div_cnt : unsigned(CLK_DIV_WIDTH-1 downto 0);
34+
signal clk_div_cnt_mark : std_logic;
35+
36+
begin
37+
38+
clk_div_cnt_p : process (CLK)
39+
begin
40+
if (rising_edge(CLK)) then
41+
if (CLEAR = '1') then
42+
clk_div_cnt <= (others => '0');
43+
elsif (ENABLE = '1') then
44+
if (clk_div_cnt = DIV_MAX_VAL-1) then
45+
clk_div_cnt <= (others => '0');
46+
else
47+
clk_div_cnt <= clk_div_cnt + 1;
48+
end if;
49+
end if;
50+
end if;
51+
end process;
52+
53+
clk_div_cnt_mark <= '1' when (clk_div_cnt = DIV_MARK_POS) else '0';
54+
55+
div_mark_p : process (CLK)
56+
begin
57+
if (rising_edge(CLK)) then
58+
if (RST = '1') then
59+
DIV_MARK <= '0';
60+
else
61+
DIV_MARK <= ENABLE and clk_div_cnt_mark;
62+
end if;
63+
end if;
64+
end process;
65+
66+
end architecture;

‎rtl/comp/uart_rx.vhd

+75-94
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
--------------------------------------------------------------------------------
22
-- PROJECT: SIMPLE UART FOR FPGA
33
--------------------------------------------------------------------------------
4-
-- MODULE: UART RECEIVER
54
-- AUTHORS: Jakub Cabal <jakubcabal@gmail.com>
65
-- LICENSE: The MIT License (MIT), please read LICENSE file
76
-- WEBSITE: https://github.com/jakubcabal/uart-for-fpga
@@ -13,75 +12,58 @@ use IEEE.NUMERIC_STD.ALL;
1312

1413
entity UART_RX is
1514
Generic (
16-
PARITY_BIT : string := "none" -- type of parity: "none", "even", "odd", "mark", "space"
15+
CLK_DIV_VAL : integer := 16;
16+
PARITY_BIT : string := "none" -- type of parity: "none", "even", "odd", "mark", "space"
1717
);
1818
Port (
19-
CLK : in std_logic; -- system clock
20-
RST : in std_logic; -- high active synchronous reset
19+
CLK : in std_logic; -- system clock
20+
RST : in std_logic; -- high active synchronous reset
2121
-- UART INTERFACE
22-
UART_CLK_EN : in std_logic; -- oversampling (16x) UART clock enable
23-
UART_RXD : in std_logic; -- serial receive data
22+
UART_CLK_EN : in std_logic; -- oversampling (16x) UART clock enable
23+
UART_RXD : in std_logic; -- serial receive data
2424
-- USER DATA OUTPUT INTERFACE
25-
DOUT : out std_logic_vector(7 downto 0); -- output data received via UART
26-
DOUT_VLD : out std_logic; -- when DOUT_VLD = 1, output data (DOUT) are valid (is assert only for one clock cycle)
27-
FRAME_ERROR : out std_logic -- when FRAME_ERROR = 1, stop bit was invalid (is assert only for one clock cycle)
25+
DOUT : out std_logic_vector(7 downto 0); -- output data received via UART
26+
DOUT_VLD : out std_logic; -- when DOUT_VLD = 1, output data (DOUT) are valid without errors (is assert only for one clock cycle)
27+
FRAME_ERROR : out std_logic; -- when FRAME_ERROR = 1, stop bit was invalid (is assert only for one clock cycle)
28+
PARITY_ERROR : out std_logic -- when PARITY_ERROR = 1, parity bit was invalid (is assert only for one clock cycle)
2829
);
29-
end UART_RX;
30+
end entity;
3031

31-
architecture FULL of UART_RX is
32+
architecture RTL of UART_RX is
3233

3334
signal rx_clk_en : std_logic;
34-
signal rx_ticks : unsigned(3 downto 0);
35-
signal rx_clk_divider_en : std_logic;
3635
signal rx_data : std_logic_vector(7 downto 0);
3736
signal rx_bit_count : unsigned(2 downto 0);
38-
signal rx_receiving_data : std_logic;
3937
signal rx_parity_bit : std_logic;
4038
signal rx_parity_error : std_logic;
4139
signal rx_parity_check_en : std_logic;
42-
signal rx_output_reg_en : std_logic;
40+
signal rx_done : std_logic;
41+
signal fsm_idle : std_logic;
42+
signal fsm_databits : std_logic;
43+
signal fsm_stopbit : std_logic;
4344

4445
type state is (idle, startbit, databits, paritybit, stopbit);
45-
signal rx_pstate : state;
46-
signal rx_nstate : state;
46+
signal fsm_pstate : state;
47+
signal fsm_nstate : state;
4748

4849
begin
4950

5051
-- -------------------------------------------------------------------------
5152
-- UART RECEIVER CLOCK DIVIDER AND CLOCK ENABLE FLAG
5253
-- -------------------------------------------------------------------------
5354

54-
uart_rx_clk_divider_p : process (CLK)
55-
begin
56-
if (rising_edge(CLK)) then
57-
if (rx_clk_divider_en = '1') then
58-
if (UART_CLK_EN = '1') then
59-
if (rx_ticks = "1111") then
60-
rx_ticks <= (others => '0');
61-
else
62-
rx_ticks <= rx_ticks + 1;
63-
end if;
64-
else
65-
rx_ticks <= rx_ticks;
66-
end if;
67-
else
68-
rx_ticks <= (others => '0');
69-
end if;
70-
end if;
71-
end process;
72-
73-
uart_rx_clk_en_p : process (CLK)
74-
begin
75-
if (rising_edge(CLK)) then
76-
if (RST = '1') then
77-
rx_clk_en <= '0';
78-
elsif (UART_CLK_EN = '1' AND rx_ticks = "0111") then
79-
rx_clk_en <= '1';
80-
else
81-
rx_clk_en <= '0';
82-
end if;
83-
end if;
84-
end process;
55+
rx_clk_divider_i : entity work.UART_CLK_DIV
56+
generic map(
57+
DIV_MAX_VAL => CLK_DIV_VAL,
58+
DIV_MARK_POS => 3
59+
)
60+
port map (
61+
CLK => CLK,
62+
RST => RST,
63+
CLEAR => fsm_idle,
64+
ENABLE => UART_CLK_EN,
65+
DIV_MARK => rx_clk_en
66+
);
8567

8668
-- -------------------------------------------------------------------------
8769
-- UART RECEIVER BIT COUNTER
@@ -92,7 +74,7 @@ begin
9274
if (rising_edge(CLK)) then
9375
if (RST = '1') then
9476
rx_bit_count <= (others => '0');
95-
elsif (rx_clk_en = '1' AND rx_receiving_data = '1') then
77+
elsif (rx_clk_en = '1' AND fsm_databits = '1') then
9678
if (rx_bit_count = "111") then
9779
rx_bit_count <= (others => '0');
9880
else
@@ -109,7 +91,7 @@ begin
10991
uart_rx_data_shift_reg_p : process (CLK)
11092
begin
11193
if (rising_edge(CLK)) then
112-
if (rx_clk_en = '1' AND rx_receiving_data = '1') then
94+
if (rx_clk_en = '1' AND fsm_databits = '1') then
11395
rx_data <= UART_RXD & rx_data(7 downto 1);
11496
end if;
11597
end if;
@@ -150,20 +132,19 @@ begin
150132
-- UART RECEIVER OUTPUT REGISTER
151133
-- -------------------------------------------------------------------------
152134

135+
rx_done <= rx_clk_en and fsm_stopbit;
136+
153137
uart_rx_output_reg_p : process (CLK)
154138
begin
155139
if (rising_edge(CLK)) then
156140
if (RST = '1') then
157-
DOUT_VLD <= '0';
158-
FRAME_ERROR <= '0';
141+
DOUT_VLD <= '0';
142+
FRAME_ERROR <= '0';
143+
PARITY_ERROR <= '0';
159144
else
160-
if (rx_clk_en = '1' AND rx_output_reg_en = '1') then
161-
DOUT_VLD <= NOT rx_parity_error AND UART_RXD;
162-
FRAME_ERROR <= NOT UART_RXD;
163-
else
164-
DOUT_VLD <= '0';
165-
FRAME_ERROR <= '0';
166-
end if;
145+
DOUT_VLD <= rx_done and not rx_parity_error and UART_RXD;
146+
FRAME_ERROR <= rx_done and not UART_RXD;
147+
PARITY_ERROR <= rx_done and rx_parity_error;
167148
end if;
168149
end if;
169150
end process;
@@ -177,84 +158,84 @@ begin
177158
begin
178159
if (rising_edge(CLK)) then
179160
if (RST = '1') then
180-
rx_pstate <= idle;
161+
fsm_pstate <= idle;
181162
else
182-
rx_pstate <= rx_nstate;
163+
fsm_pstate <= fsm_nstate;
183164
end if;
184165
end if;
185166
end process;
186167

187168
-- NEXT STATE AND OUTPUTS LOGIC
188-
process (rx_pstate, UART_RXD, rx_clk_en, rx_bit_count)
169+
process (fsm_pstate, UART_RXD, rx_clk_en, rx_bit_count)
189170
begin
190-
case rx_pstate is
171+
case fsm_pstate is
191172

192173
when idle =>
193-
rx_output_reg_en <= '0';
194-
rx_receiving_data <= '0';
195-
rx_clk_divider_en <= '0';
174+
fsm_stopbit <= '0';
175+
fsm_databits <= '0';
176+
fsm_idle <= '1';
196177

197178
if (UART_RXD = '0') then
198-
rx_nstate <= startbit;
179+
fsm_nstate <= startbit;
199180
else
200-
rx_nstate <= idle;
181+
fsm_nstate <= idle;
201182
end if;
202183

203184
when startbit =>
204-
rx_output_reg_en <= '0';
205-
rx_receiving_data <= '0';
206-
rx_clk_divider_en <= '1';
185+
fsm_stopbit <= '0';
186+
fsm_databits <= '0';
187+
fsm_idle <= '0';
207188

208189
if (rx_clk_en = '1') then
209-
rx_nstate <= databits;
190+
fsm_nstate <= databits;
210191
else
211-
rx_nstate <= startbit;
192+
fsm_nstate <= startbit;
212193
end if;
213194

214195
when databits =>
215-
rx_output_reg_en <= '0';
216-
rx_receiving_data <= '1';
217-
rx_clk_divider_en <= '1';
196+
fsm_stopbit <= '0';
197+
fsm_databits <= '1';
198+
fsm_idle <= '0';
218199

219200
if ((rx_clk_en = '1') AND (rx_bit_count = "111")) then
220201
if (PARITY_BIT = "none") then
221-
rx_nstate <= stopbit;
202+
fsm_nstate <= stopbit;
222203
else
223-
rx_nstate <= paritybit;
204+
fsm_nstate <= paritybit;
224205
end if ;
225206
else
226-
rx_nstate <= databits;
207+
fsm_nstate <= databits;
227208
end if;
228209

229210
when paritybit =>
230-
rx_output_reg_en <= '0';
231-
rx_receiving_data <= '0';
232-
rx_clk_divider_en <= '1';
211+
fsm_stopbit <= '0';
212+
fsm_databits <= '0';
213+
fsm_idle <= '0';
233214

234215
if (rx_clk_en = '1') then
235-
rx_nstate <= stopbit;
216+
fsm_nstate <= stopbit;
236217
else
237-
rx_nstate <= paritybit;
218+
fsm_nstate <= paritybit;
238219
end if;
239220

240221
when stopbit =>
241-
rx_output_reg_en <= '1';
242-
rx_receiving_data <= '0';
243-
rx_clk_divider_en <= '1';
222+
fsm_stopbit <= '1';
223+
fsm_databits <= '0';
224+
fsm_idle <= '0';
244225

245226
if (rx_clk_en = '1') then
246-
rx_nstate <= idle;
227+
fsm_nstate <= idle;
247228
else
248-
rx_nstate <= stopbit;
229+
fsm_nstate <= stopbit;
249230
end if;
250231

251232
when others =>
252-
rx_output_reg_en <= '0';
253-
rx_receiving_data <= '0';
254-
rx_clk_divider_en <= '0';
255-
rx_nstate <= idle;
233+
fsm_stopbit <= '0';
234+
fsm_databits <= '0';
235+
fsm_idle <= '0';
236+
fsm_nstate <= idle;
256237

257238
end case;
258239
end process;
259240

260-
end FULL;
241+
end architecture;

‎rtl/comp/uart_tx.vhd

+30-50
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
--------------------------------------------------------------------------------
22
-- PROJECT: SIMPLE UART FOR FPGA
33
--------------------------------------------------------------------------------
4-
-- MODULE: UART TRANSMITTER
54
-- AUTHORS: Jakub Cabal <jakubcabal@gmail.com>
65
-- LICENSE: The MIT License (MIT), please read LICENSE file
76
-- WEBSITE: https://github.com/jakubcabal/uart-for-fpga
@@ -13,7 +12,8 @@ use IEEE.NUMERIC_STD.ALL;
1312

1413
entity UART_TX is
1514
Generic (
16-
PARITY_BIT : string := "none" -- type of parity: "none", "even", "odd", "mark", "space"
15+
CLK_DIV_VAL : integer := 16;
16+
PARITY_BIT : string := "none" -- type of parity: "none", "even", "odd", "mark", "space"
1717
);
1818
Port (
1919
CLK : in std_logic; -- system clock
@@ -30,15 +30,14 @@ end UART_TX;
3030

3131
architecture FULL of UART_TX is
3232

33-
signal tx_clk_en : std_logic;
34-
signal tx_clk_divider_en : std_logic;
35-
signal tx_ticks : unsigned(3 downto 0);
36-
signal tx_data : std_logic_vector(7 downto 0);
37-
signal tx_bit_count : unsigned(2 downto 0);
38-
signal tx_bit_count_en : std_logic;
39-
signal tx_ready : std_logic;
40-
signal tx_parity_bit : std_logic;
41-
signal tx_data_out_sel : std_logic_vector(1 downto 0);
33+
signal tx_clk_en : std_logic;
34+
signal tx_clk_div_clr : std_logic;
35+
signal tx_data : std_logic_vector(7 downto 0);
36+
signal tx_bit_count : unsigned(2 downto 0);
37+
signal tx_bit_count_en : std_logic;
38+
signal tx_ready : std_logic;
39+
signal tx_parity_bit : std_logic;
40+
signal tx_data_out_sel : std_logic_vector(1 downto 0);
4241

4342
type state is (idle, txsync, startbit, databits, paritybit, stopbit);
4443
signal tx_pstate : state;
@@ -49,40 +48,21 @@ begin
4948
DIN_RDY <= tx_ready;
5049

5150
-- -------------------------------------------------------------------------
52-
-- UART TRANSMITTER CLOCK DIVIDER
51+
-- UART TRANSMITTER CLOCK DIVIDER AND CLOCK ENABLE FLAG
5352
-- -------------------------------------------------------------------------
5453

55-
uart_tx_clk_divider_p : process (CLK)
56-
begin
57-
if (rising_edge(CLK)) then
58-
if (tx_clk_divider_en = '1') then
59-
if (uart_clk_en = '1') then
60-
if (tx_ticks = "1111") then
61-
tx_ticks <= (others => '0');
62-
else
63-
tx_ticks <= tx_ticks + 1;
64-
end if;
65-
else
66-
tx_ticks <= tx_ticks;
67-
end if;
68-
else
69-
tx_ticks <= (others => '0');
70-
end if;
71-
end if;
72-
end process;
73-
74-
uart_tx_clk_en_p : process (CLK)
75-
begin
76-
if (rising_edge(CLK)) then
77-
if (RST = '1') then
78-
tx_clk_en <= '0';
79-
elsif (uart_clk_en = '1' AND tx_ticks = "0001") then
80-
tx_clk_en <= '1';
81-
else
82-
tx_clk_en <= '0';
83-
end if;
84-
end if;
85-
end process;
54+
tx_clk_divider_i : entity work.UART_CLK_DIV
55+
generic map(
56+
DIV_MAX_VAL => CLK_DIV_VAL,
57+
DIV_MARK_POS => 1
58+
)
59+
port map (
60+
CLK => CLK,
61+
RST => RST,
62+
CLEAR => tx_clk_div_clr,
63+
ENABLE => UART_CLK_EN,
64+
DIV_MARK => tx_clk_en
65+
);
8666

8767
-- -------------------------------------------------------------------------
8868
-- UART TRANSMITTER INPUT DATA REGISTER
@@ -186,7 +166,7 @@ begin
186166
tx_ready <= '1';
187167
tx_data_out_sel <= "00";
188168
tx_bit_count_en <= '0';
189-
tx_clk_divider_en <= '0';
169+
tx_clk_div_clr <= '1';
190170

191171
if (DIN_VLD = '1') then
192172
tx_nstate <= txsync;
@@ -198,7 +178,7 @@ begin
198178
tx_ready <= '0';
199179
tx_data_out_sel <= "00";
200180
tx_bit_count_en <= '0';
201-
tx_clk_divider_en <= '1';
181+
tx_clk_div_clr <= '0';
202182

203183
if (tx_clk_en = '1') then
204184
tx_nstate <= startbit;
@@ -210,7 +190,7 @@ begin
210190
tx_ready <= '0';
211191
tx_data_out_sel <= "01";
212192
tx_bit_count_en <= '0';
213-
tx_clk_divider_en <= '1';
193+
tx_clk_div_clr <= '0';
214194

215195
if (tx_clk_en = '1') then
216196
tx_nstate <= databits;
@@ -222,7 +202,7 @@ begin
222202
tx_ready <= '0';
223203
tx_data_out_sel <= "10";
224204
tx_bit_count_en <= '1';
225-
tx_clk_divider_en <= '1';
205+
tx_clk_div_clr <= '0';
226206

227207
if ((tx_clk_en = '1') AND (tx_bit_count = "111")) then
228208
if (PARITY_BIT = "none") then
@@ -238,7 +218,7 @@ begin
238218
tx_ready <= '0';
239219
tx_data_out_sel <= "11";
240220
tx_bit_count_en <= '0';
241-
tx_clk_divider_en <= '1';
221+
tx_clk_div_clr <= '0';
242222

243223
if (tx_clk_en = '1') then
244224
tx_nstate <= stopbit;
@@ -250,7 +230,7 @@ begin
250230
tx_ready <= '1';
251231
tx_data_out_sel <= "00";
252232
tx_bit_count_en <= '0';
253-
tx_clk_divider_en <= '1';
233+
tx_clk_div_clr <= '0';
254234

255235
if (DIN_VLD = '1') then
256236
tx_nstate <= txsync;
@@ -264,7 +244,7 @@ begin
264244
tx_ready <= '0';
265245
tx_data_out_sel <= "00";
266246
tx_bit_count_en <= '0';
267-
tx_clk_divider_en <= '0';
247+
tx_clk_div_clr <= '0';
268248
tx_nstate <= idle;
269249

270250
end case;

‎rtl/uart.vhd

+62-44
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
--------------------------------------------------------------------------------
22
-- PROJECT: SIMPLE UART FOR FPGA
33
--------------------------------------------------------------------------------
4-
-- MODULE: UART TOP MODULE
54
-- AUTHORS: Jakub Cabal <jakubcabal@gmail.com>
65
-- LICENSE: The MIT License (MIT), please read LICENSE file
76
-- WEBSITE: https://github.com/jakubcabal/uart-for-fpga
@@ -27,6 +26,11 @@ use IEEE.MATH_REAL.ALL;
2726
-- Removed unnecessary resets.
2827
-- Signal BUSY replaced by DIN_RDY.
2928
-- Many other optimizations and changes.
29+
-- Version 1.2 - released on 23 December 2019
30+
-- Added double FF for safe CDC.
31+
-- Fixed fake received transaction after FPGA boot without reset.
32+
-- Added more precisely clock dividers, dividing with rounding.
33+
-- UART loopback example is for CYC1000 board now.
3034

3135
entity UART is
3236
Generic (
@@ -51,41 +55,50 @@ entity UART is
5155
DOUT_VLD : out std_logic; -- when DOUT_VLD = 1, output data (DOUT) are valid (is assert only for one clock cycle)
5256
FRAME_ERROR : out std_logic -- when FRAME_ERROR = 1, stop bit was invalid (is assert only for one clock cycle)
5357
);
54-
end UART;
58+
end entity;
5559

56-
architecture FULL of UART is
60+
architecture RTL of UART is
5761

58-
constant DIVIDER_VALUE : integer := CLK_FREQ/(16*BAUD_RATE);
59-
constant CLK_CNT_WIDTH : integer := integer(ceil(log2(real(DIVIDER_VALUE))));
60-
constant CLK_CNT_MAX : unsigned := to_unsigned(DIVIDER_VALUE-1, CLK_CNT_WIDTH);
62+
constant OS_CLK_DIV_VAL : integer := integer(real(CLK_FREQ)/real(16*BAUD_RATE));
63+
constant UART_CLK_DIV_VAL : integer := integer(real(CLK_FREQ)/real(OS_CLK_DIV_VAL*BAUD_RATE));
6164

62-
signal uart_clk_cnt : unsigned(CLK_CNT_WIDTH-1 downto 0);
63-
signal uart_clk_en : std_logic;
64-
signal uart_rxd_debounced : std_logic;
65+
signal os_clk_en : std_logic;
66+
signal uart_rxd_meta_n : std_logic;
67+
signal uart_rxd_synced_n : std_logic;
68+
signal uart_rxd_debounced_n : std_logic;
69+
signal uart_rxd_debounced : std_logic;
6570

6671
begin
6772

6873
-- -------------------------------------------------------------------------
69-
-- UART CLOCK COUNTER AND CLOCK ENABLE FLAG
74+
-- UART OVERSAMPLING (~16X) CLOCK DIVIDER AND CLOCK ENABLE FLAG
7075
-- -------------------------------------------------------------------------
7176

72-
uart_clk_cnt_p : process (CLK)
77+
os_clk_divider_i : entity work.UART_CLK_DIV
78+
generic map(
79+
DIV_MAX_VAL => OS_CLK_DIV_VAL,
80+
DIV_MARK_POS => OS_CLK_DIV_VAL-1
81+
)
82+
port map (
83+
CLK => CLK,
84+
RST => RST,
85+
CLEAR => RST,
86+
ENABLE => '1',
87+
DIV_MARK => os_clk_en
88+
);
89+
90+
-- -------------------------------------------------------------------------
91+
-- UART RXD CROSS DOMAIN CROSSING
92+
-- -------------------------------------------------------------------------
93+
94+
uart_rxd_cdc_reg_p : process (CLK)
7395
begin
7496
if (rising_edge(CLK)) then
75-
if (RST = '1') then
76-
uart_clk_cnt <= (others => '0');
77-
else
78-
if (uart_clk_en = '1') then
79-
uart_clk_cnt <= (others => '0');
80-
else
81-
uart_clk_cnt <= uart_clk_cnt + 1;
82-
end if;
83-
end if;
97+
uart_rxd_meta_n <= not UART_RXD;
98+
uart_rxd_synced_n <= uart_rxd_meta_n;
8499
end if;
85100
end process;
86101

87-
uart_clk_en <= '1' when (uart_clk_cnt = CLK_CNT_MAX) else '0';
88-
89102
-- -------------------------------------------------------------------------
90103
-- UART RXD DEBAUNCER
91104
-- -------------------------------------------------------------------------
@@ -97,53 +110,58 @@ begin
97110
)
98111
port map (
99112
CLK => CLK,
100-
DEB_IN => UART_RXD,
101-
DEB_OUT => uart_rxd_debounced
113+
DEB_IN => uart_rxd_synced_n,
114+
DEB_OUT => uart_rxd_debounced_n
102115
);
103116
end generate;
104117

105118
not_use_debouncer_g : if (USE_DEBOUNCER = False) generate
106-
uart_rxd_debounced <= UART_RXD;
119+
uart_rxd_debounced_n <= uart_rxd_synced_n;
107120
end generate;
108121

122+
uart_rxd_debounced <= not uart_rxd_debounced_n;
123+
109124
-- -------------------------------------------------------------------------
110-
-- UART TRANSMITTER
125+
-- UART RECEIVER
111126
-- -------------------------------------------------------------------------
112127

113-
uart_tx_i: entity work.UART_TX
128+
uart_rx_i: entity work.UART_RX
114129
generic map (
130+
CLK_DIV_VAL => UART_CLK_DIV_VAL,
115131
PARITY_BIT => PARITY_BIT
116132
)
117133
port map (
118-
CLK => CLK,
119-
RST => RST,
134+
CLK => CLK,
135+
RST => RST,
120136
-- UART INTERFACE
121-
UART_CLK_EN => uart_clk_en,
122-
UART_TXD => UART_TXD,
123-
-- USER DATA INPUT INTERFACE
124-
DIN => DIN,
125-
DIN_VLD => DIN_VLD,
126-
DIN_RDY => DIN_RDY
137+
UART_CLK_EN => os_clk_en,
138+
UART_RXD => uart_rxd_debounced,
139+
-- USER DATA OUTPUT INTERFACE
140+
DOUT => DOUT,
141+
DOUT_VLD => DOUT_VLD,
142+
FRAME_ERROR => FRAME_ERROR,
143+
PARITY_ERROR => open
127144
);
128145

129146
-- -------------------------------------------------------------------------
130-
-- UART RECEIVER
147+
-- UART TRANSMITTER
131148
-- -------------------------------------------------------------------------
132149

133-
uart_rx_i: entity work.UART_RX
150+
uart_tx_i: entity work.UART_TX
134151
generic map (
152+
CLK_DIV_VAL => UART_CLK_DIV_VAL,
135153
PARITY_BIT => PARITY_BIT
136154
)
137155
port map (
138156
CLK => CLK,
139157
RST => RST,
140158
-- UART INTERFACE
141-
UART_CLK_EN => uart_clk_en,
142-
UART_RXD => uart_rxd_debounced,
143-
-- USER DATA OUTPUT INTERFACE
144-
DOUT => DOUT,
145-
DOUT_VLD => DOUT_VLD,
146-
FRAME_ERROR => FRAME_ERROR
159+
UART_CLK_EN => os_clk_en,
160+
UART_TXD => UART_TXD,
161+
-- USER DATA INPUT INTERFACE
162+
DIN => DIN,
163+
DIN_VLD => DIN_VLD,
164+
DIN_RDY => DIN_RDY
147165
);
148166

149-
end FULL;
167+
end architecture;

0 commit comments

Comments
 (0)
Please sign in to comment.