当前位置:   article > 正文

FPGA开发(3)——fifo获得3×3数据矩阵_fifo设计3x3矩阵

fifo设计3x3矩阵

一、3×3矩阵的获取方式

查阅了一些FPGA图像处理的资料,总结出了获得3×3图像矩阵的方法主要有下面这几种。(1)用移位寄存器IP核;(2)用2个或者3个ram实现;(3)用2个或者3个fifo实现。我这边是使用vivado作为开发环境,quartus中有专门的IP核可以实现图像数据的缓存,但是vivado中的移位寄存器只可以缓存一行,而且最多缓存1088个,如下图所示。而且缓存数据很多时,会出现缓存数量不准确的现象,大家可以自己去试试。因此在vivado中推荐使用fifo或者ram来实现。
在这里插入图片描述

二、基于fifo提取3×3矩阵的时序图

利用时序图软件绘制了用fifo实现的移位寄存器的时序图,这边大致介绍下每个信号的作用。

clk:时钟信号
rst_n:复位信号,低有效
clken:数据有效信号,高有限
shiftin:数据输入信号
wren1:fifo1的写使能
data_count1:fifo1的数据计数
rden1:fifo1的读使能
dout:fifo1的数据输出
wren2:fifo2的写使能
data_count2:fifo2的数据计数
rden2:fifo2的读使能
taps1x:前前一行数据
taps0x:前一行数据
shift_in_dy2:第一行数据
clken_dy2:输出数据使能信号
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

然后时序图我假设每个fifo的深度是16,然后fifo每行缓存的数据是4个。当rst_n拉高后,clken是输入数据有效时刻,shift_in是输入数据。wren1和clken同步,把数据写到fifo1,data_count1开始计数。当计数满4个且clken为高电平时,rden1拉高开始从fifo1中读出数据,dout是从fifo1中读出的数据。wren2比rden1延迟一个时钟周期拉高,将fifo1中输出的数据写入到fifo2中。这是data_count2对fifo2中数据计数。当数据满足4个并且在clken_dy(clken延迟一个周期)为高时rden2有效,将fifo2中的数据读出。shift_in_dy2将输入信号延迟两个周期,clken_dy2将clken延迟两个周期以完成输出信号的同步。
在这里插入图片描述

三、基于fifo提取3×3矩阵的仿真

为了实现上述时序图的功能,首先需要例化一个fifo,例化过程如下图。选择同步fifo,然后设置位宽位深,打开fifo数据计数,其他默认即可。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
根据时序图编写的verilog代码以及tb文件代码如下所示。

module line_shift_fifo_8bit(
    input clk,
    input rst_n,
    input clken,
    input [7:0] shiftin,
    output [7:0] taps0x,
    output [7:0] taps1x
);

reg clken_dy;
wire wren1;
wire rden1;
wire wren2;
reg wren2_dy;
wire rden2;
wire [7:0] dout;
reg [7:0] taps0x_dy;
wire [3:0] data_count1;
wire [3:0] data_count2;

//delay a clock, because read1 is quicker than write2
always @(posedge clk or negedge rst_n) begin
  if(~rst_n)begin
    wren2_dy<=1'b0;
  end
  else wren2_dy<=rden1;
end
//delay a clock, make write2 and read 2 at same time
always @(posedge clk or negedge rst_n) begin
  if(~rst_n)begin
    clken_dy<=1'b0;
  end
  else clken_dy<=clken;
end
//delay a clock, taps0x_dy
always @(posedge clk or negedge rst_n) begin
  if(~rst_n)begin
    taps0x_dy<=8'd0;
  end
  else taps0x_dy<=dout;
end

assign wren1= clken;
assign rden1= clken && (data_count1==4'd4);
assign wren2= wren2_dy;
assign rden2= clken_dy && (data_count2==4'd4);
assign taps0x=taps0x_dy;

fifo_generator_0 u_fifo_generator_0 (
  .clk              (clk),                // input wire clk
  .srst             (~rst_n),              // input wire srst
  .din              (shiftin),                // input wire [7 : 0] din
  .wr_en            (wren1),            // input wire wr_en
  .rd_en            (rden1),            // input wire rd_en
  .dout             (dout),              // output wire [7 : 0] dout
  .full             (),              // output wire full
  .empty            (),            // output wire empty
  .data_count       (data_count1)  // output wire [3 : 0] data_count
);

fifo_generator_0 u_fifo_generator_1 (
  .clk              (clk),                // input wire clk
  .srst             (~rst_n),              // input wire srst
  .din              (dout),                // input wire [7 : 0] din
  .wr_en            (wren2),            // input wire wr_en
  .rd_en            (rden2),            // input wire rd_en
  .dout             (taps1x),              // output wire [7 : 0] dout
  .full             (),              // output wire full
  .empty            (),            // output wire empty
  .data_count       (data_count2)  // output wire [3 : 0] data_count
);

endmodule 

  • 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
`timescale 1ns/1ns
module tb_fifo();

reg clk;
reg rst_n;
reg clken;
reg [7:0] shiftin;
wire [7:0] taps0x;
wire [7:0] taps1x;
reg [7:0] shiftin_dy1;
reg [7:0] shiftin_dy2;
wire clken_dy2;
reg [1:0] clken_dy_two;

always #10 clk=~clk;

initial begin
  clk<=1'b0;
  clken<=1'b0;
  rst_n<=1'b0;
  #20;
  rst_n<=1'b1;
end

//these has a difference between zuse and fei zuse when simulation
initial begin
  #30;
  clken<=1'b1;
  #80;
  clken<=1'b0;
  #40;
  clken<=1'b1;
  #80;
  clken<=1'b0;
  #40;
  clken<=1'b1;
  #80;
  clken<=1'b0;
  #40;
  clken<=1'b1;
  #80;
  clken<=1'b0;
  #40;
  clken<=1'b1;
  #80;
  clken<=1'b0;
end

always @(posedge clk or negedge rst_n) begin
  if(~rst_n)begin
    shiftin<=8'd0;
  end
  else if(clken==1'b1)begin
    shiftin<=shiftin+1'b1;
  end
  else shiftin<=shiftin;
end

always @(posedge clk or negedge rst_n) begin
  if(~rst_n)begin
    clken_dy_two<=2'd0;
  end
  else begin
    clken_dy_two<={clken_dy_two[0],clken};
  end
end

always @(posedge clk or negedge rst_n) begin
  if(~rst_n)begin
    shiftin_dy1<=8'd0;
    shiftin_dy2<=8'd0;
  end
  else begin
    shiftin_dy1<=shiftin;
    shiftin_dy2<=shiftin_dy1;
  end
end

assign clken_dy2=clken_dy_two[1];


line_shift_fifo_8bit u_line_shift_fifo_8bit(
    .clk     ( clk     ),
    .rst_n   ( rst_n   ),
    .clken   ( clken   ),
    .shiftin ( shiftin ),
    .taps0x  ( taps0x  ),
    .taps1x  ( taps1x  )
);

endmodule 
  • 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

最后给出vivado的仿真结果如下图所示。可以对比timgen的时序图和仿真的结果,是完全一致的。
在这里插入图片描述

四、利用fifo实现的3×3矩阵进行图像处理仿真

我这边是使用1024×768分辨率的屏幕,所以这边缓存数量选择1024个数据,改变一下fifo的深度为2048大于1024即可,然后代码中fifo技术改变位数,其他都不需要改动。
在之前的工程中用ram实现了矩阵生成的verilog代码,这边只需要将ram ip核改成fifo实现的就可以了。另外还需要注意的是,利用ram实现的缓存是只延迟了一拍,而用fifo实现的缓存则是消耗了两拍。所以最后给矩阵的数据是总共延迟了三拍,这点与之前不同。

module  VIP_matrix_generate
(
	input				clk,  		
	input				rst_n,				

	input				per_frame_vsync,
	input				per_frame_href,
	input				per_frame_clken,
	input        [7:0]  per_img_Y,

	output				matrix_frame_vsync,
	output				matrix_frame_href,
	output				matrix_frame_clken,
	output	reg  [7:0]  matrix_p11, 
	output	reg  [7:0]  matrix_p12,
	output	reg  [7:0]  matrix_p13,
	output	reg	 [7:0]  matrix_p21, 
	output	reg  [7:0]  matrix_p22, 
	output	reg  [7:0]  matrix_p23,
	output	reg	 [7:0]  matrix_p31, 
	output	reg  [7:0]  matrix_p32, 
	output	reg  [7:0]  matrix_p33
);

//wire define
wire  [7:0]  row1_data;
wire  [7:0]  row2_data;
wire	     read_frame_href ;
wire	     read_frame_clken;

//reg define
reg  [7:0]  row3_data;
reg  [7:0]  row3_data_dy;
reg  [2:0]  per_frame_vsync_r;
reg  [2:0]  per_frame_href_r;
reg  [2:0]  per_frame_clken_r;

assign	read_frame_href    = per_frame_href_r[1] ;
assign	read_frame_clken   = per_frame_clken_r[1];
assign	matrix_frame_vsync = per_frame_vsync_r[2];
assign	matrix_frame_href  = per_frame_href_r[2] ;
assign	matrix_frame_clken = per_frame_clken_r[2];

//present signal delay 2 clk 
always@(posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		row3_data_dy<= 0;
		row3_data <= 0;
	end
	else begin		
		if(per_frame_clken) begin
			row3_data_dy <= per_img_Y ;
			row3_data <= row3_data_dy;
		end
		else begin
			row3_data_dy<= row3_data_dy;
			row3_data <= row3_data;
		end
	end
end

line_shift_fifo_8bit u_line_shift_fifo_8bit(
    .clk     ( clk     			),
    .rst_n   ( rst_n   			),
    .clken   ( per_frame_clken  ),
    .shiftin ( per_img_Y 		),
    .taps0x  ( row2_data  		),
    .taps1x  ( row1_data  		)
);

//delay 3 tclk
always@(posedge clk or negedge rst_n) begin
	if(!rst_n) begin		
		per_frame_vsync_r <= 0;
		per_frame_href_r  <= 0;
		per_frame_clken_r <= 0;
	end
	else begin		
		per_frame_vsync_r <= { per_frame_vsync_r[1:0], per_frame_vsync };
		per_frame_href_r  <= { per_frame_href_r[1:0],  per_frame_href  };
		per_frame_clken_r <= { per_frame_clken_r[1:0], per_frame_clken };
	end
end

//generate the 3X3 matrix 
always@(posedge clk or negedge rst_n) begin
	if(!rst_n) begin		
		{matrix_p11, matrix_p12, matrix_p13} <= 24'h0;
		{matrix_p21, matrix_p22, matrix_p23} <= 24'h0;
		{matrix_p31, matrix_p32, matrix_p33} <= 24'h0;
	end
	else if(read_frame_href) begin
		if(read_frame_clken) begin			
			{matrix_p11, matrix_p12, matrix_p13} <= {matrix_p12, matrix_p13, row1_data};
			{matrix_p21, matrix_p22, matrix_p23} <= {matrix_p22, matrix_p23, row2_data};
			{matrix_p31, matrix_p32, matrix_p33} <= {matrix_p32, matrix_p33, row3_data};
		end
		else begin			
			{matrix_p11, matrix_p12, matrix_p13} <= {matrix_p11, matrix_p12, matrix_p13};
			{matrix_p21, matrix_p22, matrix_p23} <= {matrix_p21, matrix_p22, matrix_p23};
			{matrix_p31, matrix_p32, matrix_p33} <= {matrix_p31, matrix_p32, matrix_p33};
		end	
	end
	else begin		
		{matrix_p11, matrix_p12, matrix_p13} <= 24'h0;
		{matrix_p21, matrix_p22, matrix_p23} <= 24'h0;
		{matrix_p31, matrix_p32, matrix_p33} <= 24'h0;
	end
end

endmodule

  • 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

给出最后的仿真结果,可以看到数据缓存到row1、row2和row3中,之后在送到矩阵matrix中,具体细节不在阐述。
在这里插入图片描述
在这里插入图片描述
放上最后的结果图,原图是加了噪声的风景图,然后经过了rgb转灰度,sobel边缘检测后输出图像。
在这里插入图片描述
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/黑客灵魂/article/detail/896802
推荐阅读
相关标签
  

闽ICP备14008679号