你的位置:EETOP 赛灵思(Xilinx) 社区 >> >> 全部 >> 详细内容

FPGA图像处理系列——基于ZEDBoard构建图像处理通路(Block Ram版本)

发布者:jackzhang 时间:2015-09-06 13:31:58

对于集FPGA和ARM于一体的Zynq系列平台来说,图像处理是Zynq平台主要的应用方向之一。图像采集部分是图像处理系统的重要组成部分,它 通过图像传感器将外部的图像信息采集进来,转换为数字信号存储到系统的帧存储器中。目前在工业图像采集领域,人们常用的两种图像传感器为CCD与CMOS图 像传感器。CCD一般输出带制式的模拟信号,需要经过视频解码器得到数字信号才能传入控制器中,而CMOS图像传感器直接输出数字信号,可以直接与控制器 进行连接。随着集成电路设计技术和工艺水平的提高,CMOS图像传感器像素单元的数量和采集速度都不断增大。由于CMOS器件的高速性,近年来,越来越多 的高速图像采集系统采用CMOS图像传感器作为图像采集器件。

常用CMOS传感器品牌以及选择:

Sony: 日产CMOS,高灵敏度和低噪声,偏重于摄影拍照,但开发的参考资料比较少;

Aptina:CMOS系统按拍照架构设计,开发流程较为繁琐,且价格偏高,成像品质性价比略高;

OmniVision:CMOS系统架构最适合图像采集,开发资料较充足,各系列间兼容性好。

 数字图像采集平台架构如图所示。系统通过CMOS传感器OV7725将图像高速采集进Zedboard并存储到BRAM,然后通过VGA控制模块将图像显示出来。


我们要在Vivado中实现以下功能:

l  驱动CMOS图像传感器OV7725,实现图像采集;

l  将图像存放到Block Ram中;

l  图像的VGA显示;

该实例将会涉及CMOS传感器的接口及驱动、CMOS图像传感器的寄存器参数配置、BRAM存放策略等方面。

1.OV7725的引脚以及驱动

   OV7725的引脚很多,但本系统中用到的OV7725模块只包含以下一些引脚:

D0~D9: CMOS输出的10位数据口.本实例只用到D2~D9。

RESET: CMOS输入信号,复位引脚,低电平有效。本实例将其置空

PWDN: CMOS输入信号,休眠模式选择,0为正常模式,1为休眠模式。本实例将其置空

PCLK:  CMOS输出的像素时钟

XCLK:  CMOS输入的时钟信号,本实例采用25MHz。

HREF:   CMOS输出的行同步信号

VSYNC: CMOS输出的帧同步信号

SIOC:   CMOS寄存器的IIC时钟输入

SIOD:   CMOS寄存器的IIC数据输入/输出

因为用到的引脚数量并不多,因此我们选择用Zedboard上JA,JB两组Pmod接口与OV7725模块相连。OV7725的驱动包含两个操作:1.配置寄存器 2.根据传入的时序信号(PCLK,HREF,VSYNC),对传入数据进行拼接,组合成RGB像素。

n  配置寄存器

OV7725的正常工作需要寄存器的正确配置。寄存器的配置遵从IIC协议,在PL提供的IIC时钟驱使下,向不同功能的寄存器地址写入数据。本实例构建了一个IIC的主模块,寄存器配置指令只需要两条即可:

0x1100;//11为CLKRC寄存器,设置为00值,采用内部时钟

0x1206;//分辨率设置为VGA 640x480,像素输出格式设置为RGB565

n  拼接数据得到像素RGB565

 OV7725像素格式为RGB565时,时序图如下:


当帧同步信号VSYNC出现有效边沿之后,在HREF为高电平时,第一个PCLK上升沿读取第一个byteD7~D0)。此时要注意,这个byte并不代表第一个像素,而是第一个像素的R[4:0]以及G[5:3],第二个PCLK上升沿读取的byte则是第一个像素的G[2:0]以及B[4:0]。当第二个PCLK上升沿到来时,将这两个byte组合成一个完整的像素,就得到了第一个像素。以此类推,采集一行数据(640x2个数据),就得到640个像素值。当采集完480行的时候,就完成了一帧数据的采集。


OV7725VGA时序可知,每一行有效时间为640x2pclk,无效时间为144x2pclk,每一行花费时间为784x2PCLK时钟;而每一帧总行数是510(有效行数是480);因此采集一帧数据的时间是784*510x2pclk的时间。

2.帧缓存(FrameBuffer)的实现

    为了方便进行显示,以及后续的图像处理,需要存储采集的图像。在vavadoIP catalog界面,在search 栏输入block mem,下方ip列表会显示出block memorygenerator,如图所示:


双击上图的蓝色区域,打开ip核定制界面。在Basic板块的Memory Type选项设置成Simple dual portram,然后在port A options port A width 设置成48bit,depth设置成76800.enable port type设置成 always enabled。在port B options port B width 设置成12bit,此时dept会自动设置成307200.同样,“enable port type设置成 always enabled

那么,读者朋友们会注意到刚才port A 的端口位宽是48bit。我们知道,要进行vga显示,zedboardVGA部分RGB每个通道都是4bit,显示一个像素需要12bit。因此,我们存储一个像素采用的位宽也是12bit,一共存储的像素数量为640x480 = 307200个像素。既然这样,那为什么存进RAM的位宽不是12bit呢?这是因为,ip核的写入端深度允许的范围只有2-130172,而读端口就没有这种限制,为了存储一帧图像,存储的位宽就需要增加。我们需要另写一个像素整合存储到ram的机制,使连续的四个像素在存储之前先整合成一个12x4bit的变量。

OV7725的采集模块代码如下:

 

module ov7725_capture(

input pclk,

input vsync,

input href,

input[7:0] d,

output[18:0] addr,

output[47:0] dout_48bit,

output reg we

);

reg [15:0] d_latch;

reg [18:0] address;

reg [18:0] address_next; 

reg [1:0] wr_hold;   

reg [47:0] dout_48bit_reg;

reg [1:0] cnt;

initial d_latch = 16'b0;

initial address = 19'b0;

initial address_next = 19'b0;

initial wr_hold = 2'b0;

initial dout_48bit_reg = 48'b0;    

initial cnt = 2'b0;       

assign addr =    address;

 

always@(posedge pclk)begin

 if(vsync ==1) begin

          address <=19'b0;

          address_next <= 19'b0;

          wr_hold <=  2'b0;

          cnt <=  2'b0;

          end

       else begin

          address <= address_next;

          we      <= wr_hold[1];

          wr_hold <= {wr_hold[0] , (href &&( ! wr_hold[0])) };

          d_latch <= {d_latch[7:0] , d};

 

          if (wr_hold[1] ==1 )begin

             

             address_next <=address_next+1;

             if(cnt >= 3)

                cnt <= 0;

             else

                cnt <= cnt + 1;

             

             case (cnt)

                 0 : dout_48bit_reg[11:0]  <= {d_latch[15:12] , d_latch[10:7] ,d_latch[4:1] };

                 1 : dout_48bit_reg[23:12]<= {d_latch[15:12] , d_latch[10:7] , d_latch[4:1] };

                 2 : dout_48bit_reg[35:24]<= {d_latch[15:12] , d_latch[10:7] , d_latch[4:1] };

                 3 : dout_48bit_reg[47:36]<= {d_latch[15:12] , d_latch[10:7] , d_latch[4:1] };

             endcase;        

          end

 

       end;

 end

 assign  dout_48bit =  dout_48bit_reg;     

endmodule    

3.VGA显示的实现

本实例中实现的VGA模块顶视图如图所示:


VGA部分除了产生VGA信号,将像素信号接到VGARGB三通道以外,还有一个比较重要的功能,就是产生读frame buffer的地址信号frame_addr

利用vga的列计数器和行计数器,可以轻松产生frame_addr:当行计数器范围在0-479,列计数器范围在0-639时,每来一个vga时钟信号,地址值加1。当行计数值等于480时,地址值清零。产生frame_addr的关键代码如下:

           if(vCounter  >= 480)

                           frame_addr  <= 19'b0;

                    else begin

                               if (hCounter  < 640)

                                     frame_addr <= frame_addr +1;

                           end

4.具体实现步骤:

   (1)启动Vivado2013.3,在工作目录(例如D\xup\Zed)下创建新工程Cam_OV7725_ImageShow.

   (2)选择RTL Project, target language选择verilog, part orboard部分选择xc7z020clg484-3,完成工程的创建

   3)添加verilog文件:在vivado主页面左边的project manager一栏,点击Add Sources,,勾选Add Existing Block Design Source,选择Add Files,添加/verilog_files文件夹下的所有v文件。记住勾选“Copy source into project,如图所示:


添加帧缓存ip核:点击IP Catalog,在search栏输入block mem,添加Block Memory Generator ip核,按照以下3图设置ip参数:





(4)添加时钟ip核:在IP Catalog中的search栏输入clock,选取clocking wizard ip,双击进入配置界面。元件名字改为clk_gen,output clocks板块增加两个时钟输出:50MHz25MHz,并勾去下方的resetlocked。如图所示:


(4)添加引脚配置文件:再一次点击Add Sources,,勾选Add or Create Constraints,选择Add Files,添加/constraints文件夹下的zed.xdc文件。

(5)保存,点击Generate Bitstream,综合、实现,生成bit文件。


系统调试及板级验证

将OV7725模块连接到Pmod转接板,转接板连上Zedboard的JA,JB口,上电,然后下载bit文件。可以看到红色的LED[0]亮 起,说明寄存器配置完毕,也可以按下BTNU按键再次进行寄存器配置。通过VGA显示器,可以看到OV7725采集到的图像,如图所示。


最新课程

  • 深入浅出玩儿转FPGA

    本视频基于Xilinx公司的Artix-7FPGA器件以及各种丰富的入门和进阶外设,提供了一些典型的工程实例,帮助读者从FPGA基础知识、逻辑设计概念

  • 从零开始大战FPGA基础篇

    本课程为“从零开始大战FPGA”系列课程的基础篇。课程通俗易懂、逻辑性强、示例丰富,课程中尤其强调在设计过程中对“时序”和“逻辑”的把控,以及硬件描述语言与硬件电路相对应的“

  • Verilog基础及典型数字

    课程中首先会给大家讲解在企业中一般数字电路从算法到流片这整个过程中会涉及到哪些流程,都分别使用什么工具,以及其中每个流程都分别做了