-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathUART_RX.vhd
142 lines (115 loc) · 4.08 KB
/
UART_RX.vhd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
----------------------------------------------------------------------
-- File Downloaded from http://www.nandland.com
----------------------------------------------------------------------
-- This file contains the UART Receiver. This receiver is able to
-- receive 8 bits of serial data, one start bit, one stop bit,
-- and no parity bit. When receive is complete o_rx_dv will be
-- driven high for one clock cycle.
--
-- Set Generic g_CLKS_PER_BIT as follows:
-- g_CLKS_PER_BIT = (Frequency of i_Clk)/(Frequency of UART)
-- Example: 10 MHz Clock, 115200 baud UART
-- (10000000)/(115200) = 87
--
library ieee;
use ieee.std_logic_1164.ALL;
use ieee.numeric_std.all;
entity UART_RX is
generic (
g_CLKS_PER_BIT : integer := 115 -- Needs to be set correctly
);
port (
i_Clk : in std_logic;
i_RX_Serial : in std_logic;
o_RX_DV : out std_logic;
o_RX_Byte : out std_logic_vector(7 downto 0)
);
end UART_RX;
architecture rtl of UART_RX is
type t_SM_Main is (s_Idle, s_RX_Start_Bit, s_RX_Data_Bits,
s_RX_Stop_Bit, s_Cleanup);
signal r_SM_Main : t_SM_Main := s_Idle;
signal r_RX_Data_R : std_logic := '0';
signal r_RX_Data : std_logic := '0';
signal r_Clk_Count : integer range 0 to g_CLKS_PER_BIT-1 := 0;
signal r_Bit_Index : integer range 0 to 7 := 0; -- 8 Bits Total
signal r_RX_Byte : std_logic_vector(7 downto 0) := (others => '0');
signal r_RX_DV : std_logic := '0';
begin
-- Purpose: Double-register the incoming data.
-- This allows it to be used in the UART RX Clock Domain.
-- (It removes problems caused by metastabiliy)
p_SAMPLE : process (i_Clk)
begin
if rising_edge(i_Clk) then
r_RX_Data_R <= i_RX_Serial;
r_RX_Data <= r_RX_Data_R;
end if;
end process p_SAMPLE;
-- Purpose: Control RX state machine
p_UART_RX : process (i_Clk)
begin
if rising_edge(i_Clk) then
case r_SM_Main is
when s_Idle =>
r_RX_DV <= '0';
r_Clk_Count <= 0;
r_Bit_Index <= 0;
if r_RX_Data = '0' then -- Start bit detected
r_SM_Main <= s_RX_Start_Bit;
else
r_SM_Main <= s_Idle;
end if;
-- Check middle of start bit to make sure it's still low
when s_RX_Start_Bit =>
if r_Clk_Count = (g_CLKS_PER_BIT-1)/2 then
if r_RX_Data = '0' then
r_Clk_Count <= 0; -- reset counter since we found the middle
r_SM_Main <= s_RX_Data_Bits;
else
r_SM_Main <= s_Idle;
end if;
else
r_Clk_Count <= r_Clk_Count + 1;
r_SM_Main <= s_RX_Start_Bit;
end if;
-- Wait g_CLKS_PER_BIT-1 clock cycles to sample serial data
when s_RX_Data_Bits =>
if r_Clk_Count < g_CLKS_PER_BIT-1 then
r_Clk_Count <= r_Clk_Count + 1;
r_SM_Main <= s_RX_Data_Bits;
else
r_Clk_Count <= 0;
r_RX_Byte(r_Bit_Index) <= r_RX_Data;
-- Check if we have sent out all bits
if r_Bit_Index < 7 then
r_Bit_Index <= r_Bit_Index + 1;
r_SM_Main <= s_RX_Data_Bits;
else
r_Bit_Index <= 0;
r_SM_Main <= s_RX_Stop_Bit;
end if;
end if;
-- Receive Stop bit. Stop bit = 1
when s_RX_Stop_Bit =>
-- Wait g_CLKS_PER_BIT-1 clock cycles for Stop bit to finish
if r_Clk_Count < g_CLKS_PER_BIT-1 then
r_Clk_Count <= r_Clk_Count + 1;
r_SM_Main <= s_RX_Stop_Bit;
else
r_RX_DV <= '1';
r_Clk_Count <= 0;
r_SM_Main <= s_Cleanup;
end if;
-- Stay here 1 clock
when s_Cleanup =>
r_SM_Main <= s_Idle;
r_RX_DV <= '0';
when others =>
r_SM_Main <= s_Idle;
end case;
end if;
end process p_UART_RX;
o_RX_DV <= r_RX_DV;
o_RX_Byte <= r_RX_Byte;
end rtl;