基于FPGA的中值滤波设计————(2)Verilog设计整体框架以及简单模块设计

        FPGA的设计经常讲究的原则是自顶向下,我们也遵从这个原则。

   前言

        首先通过前面两章(加上MATLAB那章)的学习,我们应该知道了设计的中值滤波要实现什么功能,接下来要做的就是明确我们设计的实现结构框架应该是什么?需要分为哪几个模块?

一,整体框架

        先说说我的思路,老规矩结合实际的设计直接上图,开局一张图,设计全靠编哈哈。

  基于FPGA的中值滤波设计————(2)Verilog设计整体框架以及简单模块设计_第1张图片

         这是在vivado设计出来生成的模块组成图也是原理图,图中含有了一部分的控制信号,看起来比较繁琐,下面我简化一下,

基于FPGA的中值滤波设计————(2)Verilog设计整体框架以及简单模块设计_第2张图片

         这里可以清晰的看到实际的数据流,还可以看到组成中值滤波设计的模块主要有4大个块,分别是顶层mid_top数据存储模块RAM_picture3X3矩阵生成模块mid3X3、最后是矩阵滤波模块midfilter

       整个设计工作的流程:

        首先图像数据输入顶层当中,紧接着数据直接进入到数据存储模块RAM.picture进行存储,然后数据经过mid3X3模块生成3x3的矩阵模板,接着将这个3x3的矩阵模板送入midfilter模块进行滤波处理,最后将滤波后的数据输出,每个模块都实现唯一的功能,这样的思路能够很好的降低设计难度和理解难度。

        接下来我们先看简单的模块设计实现。

二、顶层模块mid_top设计

        顶层的设计就比较简单,它的作用就是将各个模块连接起来。值得注意的是在设计顶层的时候,最好不要包含逻辑功能设计模块也就是always和assign功能块,只用结构化的描述方式设计也就是模块调用例化的方式,这样的方式主要也是让我们的设计有较强的可阅读性。

        上代码,看一下实际的设计:

module mid_top#(

    parameter picture_size =71200,
               picture_row=200,
               picture_col=356,
               data_width   =24
)(
    input clk,rst_n,rst_ram,
    input [data_width-1:0]data_in,
    
    output flag,
    output [data_width-1:0]data_out
    );
    wire [31:0] add;
    wire [data_width-1:0] ram_data;
    wire mid3x3_done;
    wire [data_width-1:0]c1,c2,c3,c4,c5,c6,c7,c8,c9;
RAM_picture m0(
    .clk(clk),
    .rst_n(rst_ram),
    
    .data_in(data_in),
    .address_out(add), 
    
    .data_out(ram_data)
    );  
mid3x3 m1(
    .clk(clk),
    .rst_n(rst_n),
    .flag(flag),
    .data_in(ram_data),
    
    .c1(c1),.c2(c2),.c3(c3),.c4(c4),.c5(c5),.c6(c6),.c7(c7),.c8(c8),.c9(c9),模板矩阵
    .address_out(add),
    .mid3x3_done(mid3x3_done)
    );      
midfilter m2(
    .clk(clk),
    .rst_n(rst_n),
    .mid3x3_done(mid3x3_done),   
    .c1(c1),.c2(c2),.c3(c3),.c4(c4),.c5(c5),.c6(c6),.c7(c7),.c8(c8),.c9(c9),模板矩阵
    
    .flag(flag),
   .data_out(data_out)  ///滤波后输出数据
    );    
    
endmodule

        顶层的设计是不是非常简单,首先利用parameter函数对基础的常量定义了4个,分别是图层的大小picture_size=71200、图层的行数picture_row、列数picture_col、一个像素的大小位宽data_width。

parameter picture_size =71200,
               picture_row=200,
               picture_col=356,
               data_width   =24

       接着是输入输出端口的定义,时钟是clk,它的大小在前一章的tb里面可以改,然后是两个复位信号rst_n、rst_ram,解释一下两个复位的原因,主要因为在我们生成3x3的矩阵时候,往往需要取跨行和跨列的数据组成矩阵模板,而我们输入的数据是图像的从左边到右边,从上往下,一个一个数据写进RAM,所以就需要RAM至少提前存入当前中心点像素下一行的数据,矩阵模板才能取到这个数据。为了达到这个效果,实现的方式就是让RAM_piucture先启动存图像数据。当存完第一行数据乃至第二行第三行...后,再启动后面的mid3X3和滤波模块,开始第一个模板的处理,而rst就是相当于启动信号。
    输入数据端口是data_in,输出数据端口是data_out,然后是 flag信号,这个flag信号上一章也说过,代表一个像素点滤波数据处理完成了。

input clk,rst_n,rst_ram,
input [data_width-1:0]data_in,
    
output flag,
output [data_width-1:0]data_out

        然后是连线的定义,其中add代表由mid3X3模块产生用来控制RAM输出的矩阵地址,一个一个的取出对应坐标的模板矩阵的9个数,ram_data就是对应地址读出的像素点数据,mid3x3_done代表的是模板产生成功,通知midfilter模块可以开始滤波了,而c1到c9就代表的是由mid3x3产生的矩阵的9个数。

wire [31:0] add;
wire [data_width-1:0] ram_data;
wire mid3x3_done;
wire [data_width-1:0]c1,c2,c3,c4,c5,c6,c7,c8,c9;

        最后就是模块实例化调用,同时将各个模块对应端口连接起来。

三、图像数据存取模块RAM_picture

        这个模块的功能作用前面都描述差不多了,就是存储图像数据,然后根据相应的读地址输出像素数据。对于这个模块的设计需要注意的一点是你的图片大小,我们通过PL(programmable logic)端verilog语言方式设计的的RAM都是利用芯片的内部存储寄存器生成的,简单的说芯片实现RAM的资源空间有限,太大了就会出现这个警告,不对是错误:

        所以在设计的时候我选择了356*200大小的图片,而不是像之前很清晰但很大的的图片,实在是空间有限。解决这个问题的方法有很多,但是目前我们设计的重点不在这里,就不再过多的纠结。

        上这部分的代码:

module RAM_picture#(
    parameter picture_size =71200,
               data_width   =24
)
(
    input clk,rst_n,
    
    input [data_width-1:0] data_in,
    input [31:0] address_out, 
    
    output reg [data_width-1:0]data_out
    );

reg [data_width-1:0] ram_data[picture_size-1:0];
reg [31:0] address_in;
integer i;
always@(posedge clk)
    if(!rst_n)
    begin
        address_in<=0;
        for(i=0;i<=picture_size;i=i+1)
            ram_data[i]<=0;
    end
      else
          begin
            address_in<=address_in+1;
            ram_data[address_in]<=data_in;
          end
always@(posedge clk)
    if(!rst_n)
        data_out<=0;
        else
        data_out<=ram_data[address_out];
endmodule

        设计的代码逻辑也很简单,对于常量和端口大家就可以根据我前面的分析步骤类推。功能逻辑主要是通过定义了一个宽度为[data_width-1:0] 深度为[picture_size-1:0]的寄存器ram_data对数据进行存取。

        写:在存数据也就是写入数据的时候,只需要将数据一个一个的写进来,所以写数据的写地址是依次累加的,一个时钟进来一个数据,同时写地址加一。这里用了一个for循环对所有的寄存器初始化为0。

        读:在取数据也就是读出数据的时候,需要根据输入的读地址,读取相应地址的数据就行了。

四、总结

        这一章主要是向大家介绍了中值滤波设计的顶层结构,然后十分详细的设计了顶层模块和数据存储模块。这两个模块都比较简单,其中的数据存储模块大家应该能直接自己写出来。顶层的话每个模块的具体信号还没实际设计过,可能写不出来。不过我们设计一般都是先把框架搭出来,具体的模块写好了再在顶层中例化调用,调整细节,所以不急,后面应该还有两个章节就可以完成整个的设计了。

        打工人,奥利给!!!

你可能感兴趣的:(FPGA开发,fpga开发,开发语言,图像处理)