-
Notifications
You must be signed in to change notification settings - Fork 0
/
uart_rx.v
104 lines (84 loc) · 2.35 KB
/
uart_rx.v
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
module uart_rx #(
// number of clock cycles per single bit of UART transmission
parameter p_delay_cnt,
// number of data bit expected
parameter p_bit_cnt = 4'd8
)(
input i_clk,
input i_rst,
input i_sig,
output [p_bit_cnt - 1:0] o_fifo_wr_data,
output o_fifo_wr_en,
input i_fifo_full
);
localparam
s_idle = 3'd0,
s_start = 3'd1,
s_data = 3'd2,
s_stop = 3'd3,
s_store = 3'd4;
// UART signal shadow
reg r_sig;
// current state
reg [2:0] r_state;
// data bit received
reg [p_bit_cnt - 1:0] r_bit;
// number of data bit received
reg [$clog2(p_bit_cnt):0] r_bit_cnt;
// number of clock cycles left until next event
reg [$clog2(p_delay_cnt):0] r_delay_cnt;
assign o_fifo_wr_data = r_bit;
assign o_fifo_wr_en = r_state == s_store;
initial
r_state <= s_idle;
always @(posedge i_clk)
r_sig <= i_sig;
always @(posedge i_clk) begin
if (i_rst)
r_state <= s_idle;
else
case (r_state)
s_idle: // wait for start bit
if (~r_sig) begin // falling edge of start bit
r_state <= s_start;
r_delay_cnt <= p_delay_cnt / 2'd2;
end
s_start: // check start bit
if (r_delay_cnt == 1'd1) begin // right time to observe
if (~r_sig) begin // valid start bit
r_state <= s_data;
r_delay_cnt <= p_delay_cnt;
r_bit_cnt <= p_bit_cnt;
end
else
r_state <= s_idle;
end
else
r_delay_cnt <= r_delay_cnt - 1'd1; // count time
s_data: // capture data bit
if (r_delay_cnt == 1'd1) begin
r_delay_cnt <= p_delay_cnt;
r_bit <= {
r_sig,
r_bit[p_bit_cnt - 1:1]
};
if (r_bit_cnt == 1'd1)
r_state <= s_stop;
else
r_bit_cnt <= r_bit_cnt - 1'd1;
end
else
r_delay_cnt <= r_delay_cnt - 1'd1;
s_stop: // check stop bit
if (r_delay_cnt == 1'd1)
if (r_sig & ~i_fifo_full) // valid stop bit and fifo is not full
r_state <= s_store;
else
r_state <= s_idle;
else
r_delay_cnt <= r_delay_cnt - 1'd1;
s_store:
r_state <= s_idle;
endcase
end
endmodule