Abstract: Verilog UART  设计

更新记录

当前为 v4 版本

解决了之前版本连续收发时丢数据的问题

模块代码

Rx 部分

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
// UART 接收模块 可选波特率 可选数据位 仅支持一位停止位

module UART_Rx_module #(
parameter CLK_FREQ_MHZ = 27,
parameter BAUD_RATE = 9600,
parameter DATA_WIDTH = 8 // 数据位宽
) (
input in_sys_clk,
input in_rst_n,
input in_rx_ready, // 准备好接受串口数据
input in_rx_pin,

output [DATA_WIDTH-1:0] out_rx_data, // 接收到的串口数据 rx_data_ready和rx_data_valid均为高时送出
output out_rx_data_valid // 接收到的串口数据有效
);

localparam BAUD_CNT_THRESHOLD = CLK_FREQ_MHZ * 1000000 / BAUD_RATE; // 波特率计数最大值
localparam BAUD_CLK_CNT_THRESHOLD = (DATA_WIDTH + 2); // 波特率时钟计数最大值 数据位+起始位+结束位

wire w_rx_negedge;
wire w_rx_done; // 接收接收标识
wire w_sample_signal;
wire w_bit_rev_done;

reg r_rx_pin_t0, r_rx_pin_t1;
reg r_rx_state; // 接收状态
reg [$clog2(BAUD_CNT_THRESHOLD)-1:0] r_baud_rate_cnt; // 波特率计数器
reg [$clog2(BAUD_CLK_CNT_THRESHOLD)-1:0] r_baud_rate_clk_cnt; // 波特率时钟计数
reg [BAUD_CLK_CNT_THRESHOLD-1:0] r_rx_data_frame_byte; // 完整数据帧

assign w_rx_negedge = (r_rx_pin_t1 && ~r_rx_pin_t0);
assign w_rx_done = (r_baud_rate_clk_cnt==BAUD_CLK_CNT_THRESHOLD-1) && (r_baud_rate_cnt==BAUD_CNT_THRESHOLD/2+2); // 不判断完整的结束位
assign w_sample_signal = (r_baud_rate_cnt==BAUD_CNT_THRESHOLD/2);
assign w_bit_rev_done = (r_baud_rate_cnt==BAUD_CNT_THRESHOLD-1);

assign out_rx_data = (out_rx_data_valid && in_rx_ready)? r_rx_data_frame_byte[BAUD_CLK_CNT_THRESHOLD-2:1] : 'd0;
assign out_rx_data_valid = w_rx_done;

//****输入数据同步****//
always @(posedge in_sys_clk or negedge in_rst_n) begin
if (~in_rst_n) begin
r_rx_pin_t0 <= 1'b0;
r_rx_pin_t1 <= 1'b0;
end
else begin
r_rx_pin_t0 <= in_rx_pin;
r_rx_pin_t1 <= r_rx_pin_t0;
end
end
//********//

//****接收状态逻辑****//
always @(posedge in_sys_clk or negedge in_rst_n) begin
if (~in_rst_n) begin
r_rx_state <= 1'b0;
end
else begin
if (w_rx_negedge && ~r_rx_state) begin // 下降沿到来
r_rx_state <= 1'b1;
end
else if (w_rx_done) begin // 接收完成
r_rx_state <= 1'b0;
end
else if (r_baud_rate_clk_cnt=='d1 && r_rx_data_frame_byte[0]==1'b1) begin // 起始位采样后高电平居多
r_rx_state <= 1'b0;
end
else begin
r_rx_state <= r_rx_state; // 在一次接收中rx_state保持高电平
end
end
end
//********//

//****波特率计数器****//
always @(posedge in_sys_clk or negedge in_rst_n) begin
if (~in_rst_n) begin
r_baud_rate_cnt <= 'd0;
end
else begin
if (r_rx_state && ~w_rx_done) begin // 接收状态
if (w_bit_rev_done) begin
r_baud_rate_cnt <= 'd0;
end
else begin
r_baud_rate_cnt <= r_baud_rate_cnt + 1'd1;
end
end
else begin
r_baud_rate_cnt <= 'd0;
end
end
end
//********//

//****波特率时钟计数****//
always @(posedge in_sys_clk or negedge in_rst_n) begin
if (~in_rst_n) begin
r_baud_rate_clk_cnt <= 'd0;
end
else begin
if (r_rx_state && ~w_rx_done) begin
if (w_bit_rev_done) begin // 计数加一
r_baud_rate_clk_cnt <= r_baud_rate_clk_cnt + 1'd1;
end
else begin
r_baud_rate_clk_cnt <= r_baud_rate_clk_cnt;
end
end
else begin
r_baud_rate_clk_cnt <= 'd0;
end
end
end
//********//

//****串行数据存入****//
always @(posedge in_sys_clk or negedge in_rst_n) begin
if (~in_rst_n) begin
r_rx_data_frame_byte <= 'd0;
end
else begin
if (r_rx_state) begin
if (w_sample_signal) begin // 采样并移位
r_rx_data_frame_byte <= {r_rx_pin_t0, r_rx_data_frame_byte[BAUD_CLK_CNT_THRESHOLD-1:1]};
end
else begin
r_rx_data_frame_byte <= r_rx_data_frame_byte;
end
end
else begin
r_rx_data_frame_byte <= 'd0;
end
end
end
//********//

endmodule

Tx 部分

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
// UART 发送模块 可选波特率 可选数据位 仅支持一位停止位

module UART_Tx_module #(
parameter CLK_FREQ_MHZ = 27,
parameter BAUD_RATE = 9600,
parameter DATA_WIDTH = 8 // 数据位宽
) (
input in_sys_clk,
input in_rst_n,
input [DATA_WIDTH-1:0] in_tx_data, // 准备发送的数据
input in_tx_data_valid, // 发送的数据有效

output out_tx_ready, // 发送模块已准备好发送数据
output out_tx_pin // 发送的串口数据 tx_data_ready和tx_data_valid都为高时数据被发送
);
localparam BAUD_CLK_CNT_THRESHOLD = (DATA_WIDTH + 2); // 波特率时钟计数最大值 数据位+起始位(两位)+停止位(一位)
localparam BAUD_CNT_THRESHOLD = (CLK_FREQ_MHZ * 1000000 / BAUD_RATE); // 波特率计数最大值

wire w_tx_done; // 发送完成
wire w_shift_signal;
wire w_bit_send_done;

reg [BAUD_CLK_CNT_THRESHOLD-1:0] r_tx_data_frame; // 准备发送的完整数据帧
reg r_tx_state; // 发送状态
reg [$clog2(BAUD_CNT_THRESHOLD)-1:0] r_baud_rate_cnt; // 波特率计数器
reg [$clog2(BAUD_CLK_CNT_THRESHOLD)-1:0] r_baud_rate_clk_cnt; // 波特率时钟计数
reg r_tx_pin;

assign w_tx_done = (r_baud_rate_clk_cnt==BAUD_CLK_CNT_THRESHOLD);
assign w_shift_signal = (r_baud_rate_cnt=='d1);
assign w_bit_send_done = (r_baud_rate_cnt==BAUD_CNT_THRESHOLD-1);

assign out_tx_ready = ~r_tx_state;
assign out_tx_pin = r_tx_pin;

//****发送数据帧生成****//
always @(posedge in_sys_clk or negedge in_rst_n) begin
if (~in_rst_n) begin
r_tx_data_frame <= 'd0;
end
else begin
if (in_tx_data_valid && out_tx_ready) begin
r_tx_data_frame <= {1'b1, in_tx_data, 1'b0};
end
else begin
if (w_shift_signal) begin // 低位发送后移位
r_tx_data_frame <= {1'b0, r_tx_data_frame[BAUD_CLK_CNT_THRESHOLD-1:1]}; // 数据帧移位
end
else begin
r_tx_data_frame <= r_tx_data_frame;
end
end
end
end
//********//

//****发送状态逻辑****//
always @(posedge in_sys_clk or negedge in_rst_n) begin
if (~in_rst_n) begin
r_tx_state <= 1'b0;
end
else begin
if (in_tx_data_valid && out_tx_ready) begin
r_tx_state <= 1'b1;
end
else if (w_tx_done) begin
r_tx_state <= 1'b0;
end
else begin
r_tx_state <= r_tx_state;
end
end
end
//********//

//****波特率计数器****//
always @(posedge in_sys_clk or negedge in_rst_n) begin
if (~in_rst_n) begin
r_baud_rate_cnt <= 'd0;
end
else begin
if (r_tx_state && ~w_tx_done) begin // 接收状态
if (w_bit_send_done) begin
r_baud_rate_cnt <= 'd0;
end
else begin
r_baud_rate_cnt <= r_baud_rate_cnt + 1'd1;
end
end
else begin
r_baud_rate_cnt <= 'd0;
end
end
end
//********//

//****波特率时钟计数****//
always @(posedge in_sys_clk or negedge in_rst_n) begin
if (~in_rst_n) begin
r_baud_rate_clk_cnt <= 'd0;
end
else begin
if (r_tx_state && ~w_tx_done) begin
if (w_bit_send_done) begin
r_baud_rate_clk_cnt <= r_baud_rate_clk_cnt + 1'd1;
end
else begin
r_baud_rate_clk_cnt <= r_baud_rate_clk_cnt;
end
end
else begin
r_baud_rate_clk_cnt <= 'd0;
end
end
end
//********//

//****发送数据部分****//
always @(posedge in_sys_clk or negedge in_rst_n) begin
if (~in_rst_n) begin
r_tx_pin <= 1'b1;
end
else begin
if (r_tx_state && ~w_tx_done) begin
if (w_shift_signal) begin // 数据帧移位前送出
r_tx_pin <= r_tx_data_frame[0]; // 数据低位送出
end
else begin
r_tx_pin <= r_tx_pin;
end
end
else begin
r_tx_pin <= 1'b1;
end
end
end
//********//

endmodule

Module-sim 测试代码

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
// UART 模型测试

`timescale 1ns/1ns

module UART_module_tb;

wire [7:0] rx_data_tb;
wire uart_tb;
wire rx_data_valid_tb;
wire tx_data_ready_tb;

reg sys_clk_tb;
reg rst_n_tb;
reg tx_data_valid_tb;
reg [7:0] tx_data_tb;

wire true;

assign true = ((tx_data_tb == rx_data_tb) && rx_data_valid_tb);

initial begin
sys_clk_tb = 1'b0;
rst_n_tb = 1'b0;
tx_data_valid_tb = 1'b0;
tx_data_tb = 8'h0;
# 5;
rst_n_tb = 1'b1;
tx_data_valid_tb = 1'b1;
tx_data_tb = 8'h5d;
end

initial begin
# 10000;
$finish;
end

always #1 begin
sys_clk_tb = ~sys_clk_tb;
end

always begin
@(posedge tx_data_ready_tb) tx_data_valid_tb = 1'b1; tx_data_tb = ($random) % 256;
@(negedge tx_data_ready_tb) tx_data_valid_tb = 1'b0; tx_data_tb = tx_data_tb;
end

UART_Rx_module #(
.CLK_FREQ_MHZ(500),
.BAUD_RATE(1152000)
) u_uart_rx (
.in_sys_clk(sys_clk_tb),
.in_rst_n(rst_n_tb),
.in_rx_ready(1'b1), // 准备好接受串口数据
.in_rx_pin(uart_tb),

.out_rx_data(rx_data_tb), // 接收到的串口数据 rx_data_ready和rx_data_valid均为高时送出
.out_rx_data_valid(rx_data_valid_tb) // 接收到的串口数据有效
);

UART_Tx_module #(
.CLK_FREQ_MHZ(500),
.BAUD_RATE(1152000)
) u_uart_tx (
.in_sys_clk(sys_clk_tb),
.in_rst_n(rst_n_tb),
.in_tx_data(tx_data_tb), // 准备发送的数据
.in_tx_data_valid(tx_data_valid_tb), // 发送的数据有效

.out_tx_ready(tx_data_ready_tb), // 发送模块已准备好发送数据
.out_tx_pin(uart_tb) // 发送的串口数据 tx_data_ready和tx_data_valid都为高时数据被发送
);

endmodule

Gowin FPGA 烧录测试代码

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
// 收到数据后发送回去

module top_module #(
parameter CLK_FREQ_MHZ = 27,
parameter BAUD_RATE = 115200
) (
input in_sys_clk,
input in_rst_n,
input in_rx_pin, // UART 接收

output out_tx_pin // UART 发送
);
wire w_rx_data_valid; // 接收数据有效
wire [7:0] w_rx_data; // 接收到的数据
wire w_tx_ready;

reg r_rx_data_valid;
reg [7:0] r_rx_data;
reg r_tx_ready_t0, r_tx_ready_t1;

always @(posedge in_sys_clk or negedge in_rst_n) begin
if (~in_rst_n) begin
r_tx_ready_t0 <= 1'b0;
r_tx_ready_t1 <= 1'b0;
end
else begin
r_tx_ready_t0 <= w_tx_ready;
r_tx_ready_t1 <= r_tx_ready_t0;
end
end

always @(posedge in_sys_clk or negedge in_rst_n) begin
if (~in_rst_n) begin
r_rx_data_valid <= 1'b0;
r_rx_data <= 8'd0;
end
else begin
if (w_rx_data_valid) begin
r_rx_data_valid <= 1'b1;
end
else if (~r_tx_ready_t0 && r_tx_ready_t1) begin
r_rx_data_valid <= 1'b0;
end
else begin
r_rx_data_valid <= r_rx_data_valid;
end


if (w_rx_data_valid) begin
r_rx_data <= w_rx_data;
end
else begin
r_rx_data <= r_rx_data;
end
end
end

UART_Rx_module #(
.CLK_FREQ_MHZ(CLK_FREQ_MHZ),
.BAUD_RATE(BAUD_RATE)
) u_uart_rx (
.in_sys_clk(in_sys_clk),
.in_rst_n(in_rst_n),
.in_rx_ready(1'b1), // 准备好接受串口数据
.in_rx_pin(in_rx_pin),

.out_rx_data(w_rx_data), // 接收到的串口数据 rx_data_ready和rx_data_valid均为高时送出
.out_rx_data_valid(w_rx_data_valid) // 接收到的串口数据有效
);

UART_Tx_module #(
.CLK_FREQ_MHZ(CLK_FREQ_MHZ),
.BAUD_RATE(BAUD_RATE)
) u_uart_tx (
.in_sys_clk(in_sys_clk),
.in_rst_n(in_rst_n),
.in_tx_data(r_rx_data), // 准备发送的数据
.in_tx_data_valid(r_rx_data_valid), // 发送的数据有效

.out_tx_ready(w_tx_ready), // 发送模块已准备好发送数据
.out_tx_pin(out_tx_pin) // 发送的串口数据 tx_data_ready和tx_data_valid都为高时数据被发送
);

endmodule