FPGA实际运行时,寄存器(变量)的值乱跳的解决办法

下面是串口接收代码。实际运行时,发现i有时候会从10跳变为2或8,但程序中却没有这样的语句,让人百思不得其解。

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
module UARTReceiver #(
parameter SYSCLK = 50000000
)(
input clock, // 系统时钟
input nrst, // 模块复位
input rx, // 串口接收引脚
input [23:0] baud_rate, // 波特率
output reg received, // 是否收到了数据
output reg [7:0] data // 收到的数据内容 (received信号为上升沿或者高电平时才可以读取)
);

wire _rx = rx;

integer counter; // 波特率计数器
reg [3:0] bit_i; // 当前正在接收第几位数据 (0为起始位, 1-8为数据位, 9为停止位, 10为空闲)
wire bit_sample = (counter == SYSCLK / baud_rate / 2 - 1); // 采样信号
wire bit_end = (counter == SYSCLK / baud_rate - 1); // 位结束信号

// 接收数据
always @(posedge clock, negedge nrst) begin
if (!nrst) begin
// 模块复位
bit_i <= 10;
counter <= 0;
received <= 0;
end
else begin
if (bit_i <= 9) begin
if (bit_end) begin
// 当前位结束, 准备接收下一位
bit_i <= bit_i + 1'b1;
counter <= 0;
end
else begin
if (bit_sample) begin
// 当前位数据采样
if (bit_i == 0 && _rx)
bit_i <= 10; // 起始位错误, 停止接收
else if (bit_i >= 1 && bit_i <= 8)
data[bit_i - 1] <= _rx; // 收到数据位
else if (bit_i == 9) begin
// 收到停止位
bit_i <= 10; // 接收完毕
if (_rx)
received <= 1;
end
end
counter <= counter + 1;
end
end
else if (!_rx) begin
// 检测到起始位, 开始接收
bit_i <= 0;
counter <= 1;
received <= 0;
end
else begin
// 空闲
if (bit_end) begin
counter <= 0;
received <= 0;
end
else if (counter != 0)
counter <= counter + 1;
end
end
end
endmodule

img

img

而且这个错误出现的概率非常大,连续发几次长一点的串口数据就会出错。 第二张图片中,本来0x68后面该接收到的是0x70,就是因为i由10变成了8,完全打乱了后面的接收流程,数据被解码成了0xdc。

解决办法是给串口输入引脚加一级寄存器缓冲,将wire _rx = rx改为:

1
2
3
4
5
6
7
8
9
// 用寄存器缓冲一下串口输入引脚rx, 以免输入信号对bit_i的赋值产生影响
// (比如收到起始位时bit_i本应从10变为0, 但是实际运行时bit_i却从10直接跳到2或8, 致使后面的数据全部出错)
reg _rx;
always @(posedge clock, negedge nrst) begin
if (!nrst)
_rx <= 1;
else
_rx <= rx;
end

注意必须用非阻塞赋值(给次态赋值),不能用阻塞赋值(给现态赋值)。

加了一级寄存器缓冲后,问题就解决了,i清零时,不会再出现i由10(二进制1010)变为2(二进制0010)或8(二进制1000)的错误了。

这可能是因为串口输入引脚rx的下降沿不太陡,程序中又有两个if语句用到了rx,导致逻辑混乱。
加了寄存器缓冲,_rx就是FPGA内部的信号,就是标准的下降沿。


FPGA实际运行时,寄存器(变量)的值乱跳的解决办法
http://blog.uanet.cn/FPGA/FPGA实际运行时,寄存器(变量)的值乱跳的解决办法.html
作者
dnsnat
发布于
2025年2月13日
许可协议