【厉害了FPGA】Verilog实现接收帧数据的一种方法(帧数据同步搜索检测)
程序员文章站
2022-03-17 10:38:44
...
FPGA和其他设备进行通信的时候,如果传输的是大量数据,肯定需要打包(组帧)进行传输,而且都需要有帧头和校验位来确保帧数据传输正确。今天说一下最近自己做的一个项目涉及到的这个问题。
当FPGA作为接收端去接收帧数据的时候,即使保证一帧数据的帧头是正确的,而且校验位是正确的也不能百分百保证这帧数据正确接收了,可能情况:1、数据传输有错误,但是错误的数据也得到了一样正确的校验位;2、数据中正好有一位数据是帧头,而我们把这个数据当做了帧头,这个按帧头接收完一帧数据,帧尾的校验位也正好算出来也是对的,等其他小概率事件。对于第一种情况我们可以通过设计好的校验方式(CRC或者其他校验方式)来使这种概率减低,还有数据是突发的还是一直连续不断发送的,这些都是我们在接收机设计的时候必须考虑的。
为了避免这种情况,在每次接收数据的时候,我们设置接收数据的时候有两种状态,一种是同步态,一种是捕获态(如下图)。在同步态连续接收到几帧数据(在此处我们叫做权值)的时候,才能进入捕获态,在捕获态我们接收到的数据才视作正确的数据。这样我们设计的权值越大,那么第二种情况发生的概率越低,但是付出的代价是丢弃了好多数据帧。
话不多说,程序的状态转移图如图所示:
本次是基于Verilog的一个接收机设计,模块按阻塞赋值(顺序执行)的方式。数据是从PC用串口按8位数据的方式传输到FPGA,帧长是344位,即34字节。帧头是两字节,校验位是7位数据,校验和的方式。
[email protected](posedge i_rx_state_1 or negedge i_reset)//一个i_rx_state_1的上升沿代表接收了一字节数据(阻塞赋值)
begin
if(!i_reset)
begin
rx_frame_temp = 344'd0;
rx_frame = 344'd0;
work_state = 8'd0;
frameheader_cache = 16'd0;
rx_byte = 6'd0;
syn_weight = 2'd0;
capture_signal = 1'b0;
end
else
begin
case(work_state)
syn_check_frameheader:
begin
syn_weight = 2'd0;
rx_frame_temp = 344'd0;
frameheader_cache = frameheader_cache<<8;
frameheader_cache[7:0] = iv_rx_data_1;
if(frameheader_cache==16'hA555)//判断是帧头a555的话,进入同步态,否则继续检测
begin
work_state = synchronous_state;
rx_frame_temp[15:0] = frameheader_cache;
rx_byte = 6'd2;
end
else
work_state = syn_check_frameheader;
end
synchronous_state:
begin
frameheader_cache = 16'd0;//清除缓存
if(rx_byte>=6'd43)//如果接收满数据,则rx_byte一直处于满状态
rx_byte = rx_byte;
else
rx_byte = rx_byte+1'b1;
rx_frame_temp = rx_frame_temp<<8;
rx_frame_temp[7:0] = iv_rx_data_1;
if(rx_byte>=6'd43)//接收完一帧数据(满状态)
begin
check_byte = ;//计算校验位,自己按照自己需求设计,为了节省代码空间,省去
if((rx_frame_temp[7:0]==check_byte)&&(rx_frame_temp[343:328]==16'hA555))//校验位正确,等待权值为2的时候进入捕获态,否则继续接收数据
begin
syn_weight = syn_weight+1'b1;
if(syn_weight>=2'd2)//连续两个帧数据接收正确进入捕获态
work_state = capture_check_frameheader;
else //权值<2,再次检测下一个帧头
work_state = syn_check_frameheader;
end
else //校验位不正确,权值减一;下一次滑动接收数据,并检验帧头和校验位是否正确,不断循环,直到接收到正确的数据
begin
if(syn_weight==2'd0)//权值为0 滑动检测
begin
work_state = synchronous_state;
syn_weight = 2'd0;
end
else
begin
syn_weight = syn_weight-1'b1;
work_state = syn_check_frameheader;
end
end
end
end
capture_check_frameheader:
begin
syn_weight = 2'd0;
rx_frame_temp = 344'd0;
capture_signal = 1'b0;//复位捕获信号
rx_byte = 6'd0;//清除接收计数缓存
frameheader_cache =frameheader_cache<<8;
frameheader_cache[7:0]=iv_rx_data_1;
if(frameheader_cache==16'hA555)//判断是帧头的话,进入同步态,否则继续检测
begin
work_state = capture_state;
rx_frame_temp[15:0] = frameheader_cache;
rx_byte = 6'd0;//清除接收计数缓存
end
else
work_state = capture_check_frameheader;
end
capture_state:
begin
rx_byte = rx_byte+1'b1;
rx_frame_temp = rx_frame_temp<<8;
rx_frame_temp[7:0] = iv_rx_data_1;
if(rx_byte>=43)//接收完一帧数据
begin
capture_signal = 1'b1;//产生捕获信号
check_byte = ;//计算校验位
if((rx_frame_temp[7:0]==check_byte)&&(rx_frame_temp[343:328]==16'hA555))
begin
work_state = capture_check_frameheader;
rx_frame = rx_frame_temp;
end
else
begin
rx_byte = 6'd0;//清除接收计数缓存
work_state = syn_check_frameheader;
rx_frame_temp = 344'd0;
frameheader_cache = 16'd0;
syn_weight = 2'd0;
end
end
end
default:
begin
rx_byte = 6'd0;//清除接收计数缓存
work_state = syn_check_frameheader;
rx_frame_temp = 344'd0;
frameheader_cache = 16'd0;
syn_weight = 2'd0;
end
endcase
end
end
下一篇: stu 学生管理