FIFO求和实验

前言

FIFO(先进先出)队列在图像处理中的应用非常广泛,特别是在需要处理实时数据流和保证数据顺序的场景中。以下是一些具体应用实例:在实时视频流处理中,FIFO队列用于缓存图像帧。这样可以确保图像数据按照捕获顺序被处理,避免因处理延迟导致的图像丢失或混乱。例如,视频监控系统会将捕获到的视频帧存储在FIFO队列中,然后按顺序进行处理和分析。在图像缓冲区管理中,FIFO队列帮助维护图像数据的顺序。这对于处理高分辨率图像或多个图像流的应用非常重要。图像处理系统会将图像数据推送到FIFO队列中,并从中读取数据进行进一步的处理,如滤镜应用或特征提取。在流媒体应用中,例如直播流或视频会议,FIFO队列用于缓存和传输数据包。这样可以保证数据按照传输顺序到达接收端,并且能够有效处理网络抖动或丢包问题。在某些图像处理任务中,尤其是需要批量处理的场景,FIFO队列可以用来管理待处理的图像数据。比如,图像增强或图像拼接任务中,FIFO队列可以保持数据的顺序,并在处理过程中保证一致性。在需要从多个传感器获取数据的系统中,FIFO队列能够处理传感器数据的流入。图像传感器的数据流可以使用FIFO队列缓存,确保数据的顺序和时效性,以便进行实时分析或处理。FIFO队列在图像处理中的主要作用是维护数据的顺序性和实时性,特别是在处理需要高吞吐量和低延迟的数据流时。

正文

一、FIFO求和实验

1.项目需求

电脑模拟产生数据求和矩阵,(5,4)使用RS232将数据发送给FPGA,FPGA通过FIFO进行求和运算,(3行求和),将数据求和结果通过RS232传回电脑。

2.技术介绍

现有一5行4列数据矩阵

FIFO求和,对该矩阵数据,N = 5,M = 4,使X = 3进行列求和运算,得到S(3,4)新矩阵,则S(0,0)=D(0,0)+D(1,0)+D(2,0),S(0,1)= D(0,1)+D(1,1)+D(2,1),S(0,2)=D(0,2)+D(1,2)+D(2,2),S(0,3)=SD(0,3)+D(1,3)+D(2,3),S(1,0)=D(1,0)+D(2,0)+D(3,0)...S(2,0)=D(2,0)+D(3,0)+D(4,0)。(n*m)矩阵转换后变为((n-(x-1)*m))矩阵。

3.顶层架构

4.端口描述

|-------|------------|
| clk | 时钟信号 |
| rst_n | 复位信号 |
| rx | 传输到FPGA的数据 |
| tx | 传输到PC的数据 |

二、代码验证

数据接收

module uart_rx(
	input 			clk		,
	input				rst_n 	,
	input				rx			,
	
	output reg[7:0]po_data	,	//接收到的数据
	output reg  	po_flag		//数据输出有效

);

parameter 	uart_btl ='d9600			;//串口波特率
parameter 	clk_shuj ='d50_000_000	;//时钟频率

parameter 	cnt_max  =clk_shuj/uart_btl;

reg 			reg1,reg2,reg3	;//打排延迟周期,消除亚稳态
reg 			flag				;//uart工作信号(uart工作时在工作状态切换后产生一个时钟周期高电平)
reg 			en					;//uart工作使能标志信号(uart工作时在工作状态切换后的下一个时钟周期开始一直拉高,直到检测到停止信号)
reg [15:0]	cnt				;//每比特数据持续时钟周期计数器
reg [3 :0]	bit_cnt			;//数据个数计数器
reg 			bit_flag			;//每bit数据接收有效信号
reg [7 :0]	rx_data			;//存储输入数据
reg			rx_flag			;//输入数据并位结束信号

always@(posedge clk,negedge rst_n)//数据打排1
begin
	if(rst_n == 0)
		reg1 <= 1'b1;
	else
		reg1 <= rx;
end	

always@(posedge clk,negedge rst_n)//数据打排2
begin
	if(rst_n == 0)
		reg2 <= 1'b1;
	else
		reg2 <= reg1;
end	

always@(posedge clk,negedge rst_n)//数据打排3
begin
	if(rst_n == 0)
		reg3 <= 1'b1;
	else
		reg3 <= reg2;
end	

always@(posedge clk,negedge rst_n)//uart工作信号赋值
begin
	if(rst_n == 0)
		flag <= 1'b0;
	else
		if((reg2 == 1'b0)&&(reg3 == 1'b1)&&(en == 1'b0))
			flag <= 1'b1;
		else
			flag <= 1'b0;
end

always@(posedge clk,negedge rst_n)//uart工作使能标志信号赋值
begin
	if(rst_n == 0)
		en <= 1'b0;
	else
		if(flag == 1'b1)
			en <= 1'b1;
		else
			if((bit_cnt == 4'd8)&&(bit_flag == 1'b1))
				en <= 1'b0;
			else
				en <= en;
end			

always@(posedge clk,negedge rst_n)//每比特数据持续时钟周期计数器驱动逻辑
begin
	if(rst_n == 0)	
		cnt <= 16'd0;
	else 	
		if((cnt == cnt_max - 1)||(en == 1'b0))
			cnt <= 16'd0;
		else
			cnt = cnt + 1'b1;
end

always@(posedge clk,negedge rst_n)//每比特数据持续时钟周期计数器驱动逻辑
begin
	if(rst_n == 0)	
		bit_flag <= 1'b0;
	else
		if(cnt == cnt_max/2 - 1)
			bit_flag <= 1'b1;
		else
			bit_flag <= 1'b0;
end

always@(posedge clk,negedge rst_n)//数据个数计数器驱动逻辑
begin
	if(rst_n == 0)	
		bit_cnt <= 4'd0;
	else	
		if((bit_cnt == 4'd8)&&(bit_flag == 1'b1))
			bit_cnt <= 4'd0;
		else 
			if(bit_flag == 1'b1)
				bit_cnt <= bit_cnt + 1'b1;
			else
				bit_cnt <= bit_cnt;
end

always@(posedge clk,negedge rst_n)//接收数据并位
begin
    if(rst_n == 0)
        rx_data <= 8'd0;
    else
        if((bit_cnt >= 4'd1)&&(bit_cnt <= 4'd8)&&(bit_flag == 1'b1))
            rx_data <= {reg3,rx_data[7:1]};
end

always@(posedge clk,negedge rst_n)//输入数据并位结束信号
begin
    if(rst_n == 0)
        rx_flag <= 1'b0;
    else 
        if((bit_cnt == 4'd8)&&(bit_flag == 1'b1))
            rx_flag <= 1'b1;
        else
            rx_flag <= 1'b0;
end

always@(posedge clk,negedge rst_n)//输出数据传递
begin
    if(rst_n == 0)
        po_data <= 8'd0;
    else 
        if(rx_flag == 1'b1)
            po_data <= rx_data;
        else
            po_data <= po_data;
end

always@(posedge clk,negedge rst_n)//输出使能
begin
    if(rst_n == 0)
        po_flag <= 1'b0;
    else 
        po_flag <= rx_flag;
end

endmodule

数据处理

module fifo_add(
	input 			clk  		,
	input 			rst_n		,
	input	[7:0]		data		,//rs232传输到FPGA的数据
	input				flag		,
	
	output reg[7:0]data_out	,//求和结果
	output reg		out_flag	 //输出使能
);

parameter l_max = 'd3,//列数
			 h_max = 'd4;//行数

reg	[3:0]l_cnt		;//列计数器	
reg	[3:0]h_cnt		;//行计数器
	
reg	fifo1_en	;//fifo_1写使能	 
reg	[7:0]fifo1_data;//fifo_1写数据

reg	fifo2_en	;//fifo_2写使能	 
reg	[7:0]fifo2_data;//fifo_2写数据
			
reg	rd_en;//读使能信号	
wire	[7:0]data1;	//fifo1读出数据
wire	[7:0]data2;	//fifo2读出数据
reg	add_en;//求和标志信号	
reg	data_flag;//fifo1的写使能信号		

always@(posedge clk,negedge rst_n)//列计数器驱动
begin
	if(rst_n == 0)
		l_cnt <= 4'd0;
	else
		if((l_cnt == l_max)&&(flag == 1'b1))
			l_cnt <= 4'd0;
		else
			if(flag == 1'b1)
				l_cnt <= l_cnt + 4'd1;
			else
				l_cnt <= l_cnt;
end

always@(posedge clk,negedge rst_n)//行计数器驱动
begin
	if(rst_n == 0)
		h_cnt <= 4'd0;
	else
		if((h_cnt == h_max)&&(l_cnt == l_max)&&(flag == 1'b1))
			h_cnt <= 4'd0;
		else
			if((l_cnt == l_max)&&(flag == 1'b1))
				h_cnt <= h_cnt + 4'd1;
			else
				h_cnt <= h_cnt;
end

always@(posedge clk,negedge rst_n)//fifo_1写使能
begin
	if(rst_n == 0)
		fifo1_en <= 1'b0;
	else
		if((h_cnt == 0)&&(flag == 1'b1))
			fifo1_en <= 1'b1;
		else
			fifo1_en <= data_flag;
end

always@(posedge clk,negedge rst_n)//fifo_1写数据
begin
	if(rst_n == 0)
		fifo1_data <= 8'd0;
	else
		if((h_cnt == 0)&&(flag == 1'b1))
			fifo1_data <= data;
		else
			if(data_flag == 1'b1)
				fifo1_data <= data2;
			else
				fifo1_data <= fifo1_data;
end

always@(posedge clk,negedge rst_n)//fifo_2写使能
begin
	if(rst_n == 0)
		fifo2_en <= 1'b0;
	else
		if((h_cnt >= 4'd1)&&(h_cnt <= h_max - 4'd1)&&(flag == 1'b1))
			fifo2_en <= 1'b1;
		else
			fifo2_en <= 1'b0;
end

always@(posedge clk,negedge rst_n)//fifo_2写数据
begin
	if(rst_n == 0)
		fifo2_data <= 8'd0;
	else
		if((h_cnt >= 4'd1)&&(h_cnt <= h_max - 4'd1)&&(flag == 1'b1))
			fifo2_data <= data;
		else
			fifo2_data <= fifo2_data;
end

always@(posedge clk,negedge rst_n)//fifo读写使能(共用)
begin
	if(rst_n == 0)
		rd_en <= 1'b0;
	else
		if((h_cnt >= 4'd2)&&(flag <= h_max)&&(flag == 1'b1))
			rd_en <= 1'b1;
		else
			rd_en <= 1'b0;
end

always@(posedge clk,negedge rst_n)//fifo1的写使能信号	
begin
	if(rst_n == 0)
		data_flag <= 1'b0;
	else
		if((fifo2_en == 1'b1)&&(rd_en == 1'b1))
			data_flag <= 1'b1;
		else
			data_flag <= 1'b0;
end

always@(posedge clk,negedge rst_n)//求和使能信号	
begin
	if(rst_n == 0)
		add_en <= 1'b0;
	else
		if(rd_en == 1'b1)
			add_en <= 1'b1;
		else
			add_en <= 1'b0;
end

always@(posedge clk,negedge rst_n)//结果输出
begin
	if(rst_n == 0)
		data_out <= 8'd0;
	else
		if(add_en == 1'b1)
			data_out <= data + data1 + data2;
		else
			data_out <= data_out;
end

always@(posedge clk,negedge rst_n)//结果输出使能
begin
	if(rst_n == 0)
		out_flag <= 1'b0;
	else
		out_flag <= add_en;
end

fifo1	fifo1_inst (
	.clock 	( clk  		 ),
	.data 	( fifo1_data ),
	.rdreq 	( rd_en 		 ),
	.wrreq 	( fifo1_en   ),
	
	.q 		( data1 )
	);

fifo1	fifo2_inst (
	.clock 	( clk   		 ),
	.data 	( fifo2_data ),
	.rdreq 	( rd_en      ),
	.wrreq 	( fifo2_en   ),
	
	.q 		( data2 )
	);


endmodule

数据发送

module uart_tx(

    input       clk     ,
    input       rst_n   ,
    input [7:0] pi_data ,
    input       pi_flag ,
    
    output reg  tx
);

parameter 	uart_btl ='d9600			;//串口波特率
parameter 	clk_shuj ='d50_000_000	;//时钟频率

parameter 	cnt_max  =clk_shuj/uart_btl;

reg         en      ;
reg [15:0]  cnt     ;//每bit数据传输完成计数器
reg         flag    ;//
reg [3 :0]  bit_cnt ;//bit计数器

always@(posedge clk,negedge rst_n)
begin 
    if(rst_n == 0)
        en <= 1'b0;
    else
        if(pi_flag == 1'b1)
            en <= 1'b1;
        else
            if((bit_cnt == 4'd9)&&(flag == 1'b1))
                en <= 1'b0;
            else 
                en <= en;          
end

always@(posedge clk,negedge rst_n)
begin
    if(rst_n == 0)
        cnt <= 16'd0;
    else
        if((en == 1'b0)||(cnt == cnt_max - 1'd2))
            cnt <= 16'd0;
        else
            if(en == 1'b1)
                cnt <= cnt + 1'b1;
            else
                cnt <= cnt;
end

always@(posedge clk,negedge rst_n)
begin
    if(rst_n == 0)
        flag <= 1'b0;
    else 
        if(cnt == 16'd1)
           flag <= 1'b1; 
        else
           flag <= 1'b0;
end

always@(posedge clk,negedge rst_n)
begin
    if(rst_n == 0)
        bit_cnt <= 4'd0;
    else
        if((bit_cnt == 4'd9)&&(flag == 1'b1))
            bit_cnt <= 4'd0;
        else
            if((en == 1'b1)&&(flag == 1'b1))
                bit_cnt <= bit_cnt + 1'b1;
            else
                bit_cnt <= bit_cnt;
end                
            
always@(posedge clk,negedge rst_n)
begin
    if(rst_n == 0)
        tx <= 1'b1;
    else
        if(flag == 1'b1)
            case(bit_cnt)
                0:  tx <= 1'b0;
                1:  tx <= pi_data[0];
                2:  tx <= pi_data[1];
                3:  tx <= pi_data[2];
                4:  tx <= pi_data[3];
                5:  tx <= pi_data[4];
                6:  tx <= pi_data[5];
                7:  tx <= pi_data[6];
                8:  tx <= pi_data[7];
                9:  tx <= 1'b1;
                default :tx <= 1'b1;
            endcase    
end

endmodule

顶层文件

module fifo_add_top(
	input 			clk  		,
	input 			rst_n		,
	input				rx 		,//rs232传输到FPGA的数据
	
	output			tx    	 //rs232传输到PC的数据
);

wire [7:0]po_data;
wire [7:0]pi_data;
wire pi_flag;
wire po_flag;

fifo_add fifo_add(
	.clk  		(clk  	),
	.rst_n		(rst_n	),
	.data		(po_data	),//rs232传输到FPGA的数据
	.flag		(po_flag	),
	         
	.data_out	(pi_data),//求和结果
	.out_flag	(pi_flag)	 //输出使能
);

uart_tx uart_tx(

    .clk     (clk     ),
    .rst_n   (rst_n   ),
    .pi_data (pi_data ),
    .pi_flag (pi_flag ),
	         
    .tx		(tx		)	
);

uart_rx uart_rx(
	.clk		(clk	),
	.rst_n 	(rst_n ),
	.rx			(rx		),
        
	.po_data	(po_data),	//接收到的数据
	.po_flag	(po_flag)	//数据输出有效

);

endmodule

仿真代码

`timescale 1ns/1ps
module fifo_add_top_tb;

	reg 			clk	;
	reg 			rst_n	;
	reg 			rx		;
	reg [7:0]	data_a[19:0];
	
	wire 			tx		;

fifo_add_top fifo_add_top(
	.clk  (clk  ),
	.rst_n(rst_n),
	.rx 	(rx 	),//rs232浼犺緭鍒癋PGA鐨勬暟鎹
	.tx   (tx   ) //rs232浼犺緭鍒癙C鐨勬暟鎹);
);

initial 
	$readmemh("E:/FPGA_exer/fifo_add_0904/doc/data.txt",data_a);//灏嗘暟鎹彁鍙栧埌浠跨湡鏂囦欢鐨勫瓨鍌ㄥ櫒涓
	
initial clk = 1'b1;
always #10 clk = ~clk;


initial begin
	rst_n = 1'b0;
	rx = 1'b1;
	#40
	rst_n = 1'b1;
	#200
	re_byte();
	#100000
	$stop;
end
//璧嬪€煎嚱鏁	
	task	rx_bit(input [7:0]data);
		
	integer i;
 
	for(i = 0;i < 10; i = i + 1)//寰幆9娆			
			begin
				case(i)
					0:  rx <= 1'b0;
					1:  rx <= data[0];
					2:  rx <= data[1];
					3:  rx <= data[2];
					4:  rx <= data[3];
					5:  rx <= data[4];
					6:  rx <= data[5];
					7:  rx <= data[6];
					8:  rx <= data[7];
					9:  rx <= 1'b1;
				endcase
			#(5208*20);//姣忔寤舵椂
			end
	endtask
	
	//defparam fifo_add_top.uart_rx.clk_shuj = 50_000;
	
	task re_byte();
		integer j;
			for(j = 0;j < 20;j = j + 1)
				rx_bit(data_a[j]);//浼犻€鈥斺€锛涓暟鎹	
	endtask


	
	
	
endmodule 

三、仿真验证

运行仿真,将data,data1,data2数据调到一起,观察data_out

观察几组数据4,1,5,=10,5,2,1=8,求和正确,数据传输到RS232数据发送模块,可以看到,数据正常通过tx输出。

输出正常,实验成功。

参考资料

fifo求和原理

相关推荐
fei_sun17 小时前
【Verilog】第一章作业
fpga开发·verilog
深圳市雷龙发展有限公司longsto18 小时前
基于FPGA(现场可编程门阵列)的SD NAND图片显示系统是一个复杂的项目,它涉及硬件设计、FPGA编程、SD卡接口、NAND闪存控制以及图像显示等多个方面
fpga开发
9527华安1 天前
FPGA实现PCIE3.0视频采集转10G万兆UDP网络输出,基于XDMA+GTH架构,提供工程源码和技术支持
网络·fpga开发·udp·音视频·xdma·pcie3.0·万兆网
able陈1 天前
为什么verilog中递归函数需要定义为automatic?
fpga开发
fei_sun1 天前
【Verilog】第二章作业
fpga开发·verilog
碎碎思1 天前
如何使用 Vivado 从源码构建 Infinite-ISP FPGA 项目
fpga开发·接口隔离原则
江山如画,佳人北望1 天前
fpga-状态机的设计及应用
fpga开发
晓晓暮雨潇潇1 天前
Xilinx IP核(3)XADC IP核
fpga开发·vivado·xadc·ip核
CWNULT1 天前
AMD(Xilinx) FPGA配置Flash大小选择
fpga开发
碎碎思2 天前
很能体现FPGA硬件思维的一道面试题
fpga开发