admin 发表于 2019-4-10 23:32:05

【更新0412】小梅哥OV7670摄像头适配的工程实例和使用说明

2019年4月10日
OV7670_SDRAM_VGA


一、功能说明:ov7670_sdram_vga工程实现了FPGA采集OV7670型CMOS摄像头的图像数据,存储到SDRAM,并经由VGA显示在VGA显示器上的功能。
二、适配板卡:该工程支持小梅哥的众多FPGA开发板,包括AC620、AC609以及红色经典(Starter)开发板。
三、配置文件:在工程文件夹内,提供了一个名为sof的文件夹,该文件夹下存放了可以直接下载到对应的硬件板卡中查看实验现象的FPGA配置文件(.sof),连接好GM7123型VGA模块和OV7670摄像头,下载对应的sof文件到开发板中。就能在VGA显示器上查看到实时的摄像头采集图像了。
四、引脚分配脚本:另外在工程文件夹内,提供了一个名为tcl的文件夹,该文件夹下存放了针对每个FPGA开发板的引脚分配脚本,当用户需要基于某个具体的板卡进行调试时,只需要在Quartus软件中依次点击tools -》 tcl scripts,然后选中对应板卡的tcl文件,点击run按钮即可完成引脚更新。

2019年4月12日
OV7670_SDRAM_Display

在上一版ov7670_sdram_vga工程的基础上,进行了进一步的修改,实现支持VGA(640*480分辨率)、4.3寸TFT显示屏(480*272分辨率)、5寸触摸TFT显示屏(800*480)分辨率,继续支持AC620、AC609、Starter开发板。

应用说明:
一、模式配置:
为了一个工程能够同时支持多个板卡(AC620、AC609以及红色经典(Starter)),以及每个板卡能够支持多种显示设备(VGA、4.3寸屏、5寸屏),在显示设备驱动设计时,使用了一个配置文件,名为“disp_parameter_cfg.v”,该文件中提供了3个可选择的预定义项:

1、显示设备类型:`define HW_TFT
//`define HW_VGA

这两项主要定义硬件输出设备是使用VGA(GM7123 VGA输出模块)还是使用TFT显示屏(4.3、5寸屏),使用哪种硬件,就将对应的定义取消注释,以使其生效,而另一项通过注释的方式屏蔽。该定义主要在“disp_driver.v”文件的60~68行左右位置生效,为了调整显示设备的输出像素时钟相位,VGA输出时需要把控制器时钟取反输出,才能正常工作,否则会花屏,而TFT屏则不能取反,因此采用条件编译的方式实现。


2、显示设备颜色模式`define MODE_RGB888
//`define MODE_RGB565

这两项主要定义硬件输出设备使用的颜色模式,从硬件设计上来讲,GM7123型VGA 输出模块设计的是24位色RGB888模式,而4.3寸和5寸显示屏使用的是16位色RGB565模式。本意是使用哪种硬件,就选择对应的颜色输出模式,但是发现这样会给工程的可移植性增加很多麻烦,因此在实际使用时,一律使用24位色RGB888模式,对于不同硬件的颜色位数的适配,放到了引脚分配时候完成,如果是VGA,则Red、Green、Blue三个颜色每个8位都分配指定引脚;如果是TFT,则将Red、Green、Blue分别分配给TFT屏的Red、Green、Blue,剩余信号不再指定管脚。
因此,在实际使用时,该项参数固定为选择MODE_RGB888

3、分辨率设定
VGA输出为640*480分辨率、4.3寸TFT显示屏480*272分辨率、5寸触摸TFT显示屏800*480分辨率,当选择不同的硬件时,显示设备驱动所需要采用的时序参数也是不一样的,因此通过分辨率设定选项来指定不同的参数。`define Resolution_480x272 1      //时钟为9MHz
//`define Resolution_640x480 1      //时钟为25.175MHz
//`define Resolution_800x480 1      //时钟为33MHz
//`define Resolution_800x600 1      //时钟为40MHz
//`define Resolution_1024x768 1      //时钟为65MHz
//`define Resolution_1280x720 1      //时钟为74.25MHz
//`define Resolution_1920x1080 1      //时钟为148.5MHz

4.3寸屏就使能Resolution_480x272、5寸屏就使能Resolution_800x480、VGA就使能Resolution_640x480。该参数有多个地方生效
第1个地方就是在本文件中,根据不同的分辨率选择,定义每个分辨率对应的时序参数,代码如下//定义不同分辨率的时序参数
`ifdef Resolution_480x272
      `define H_Total_Time12'd525
      `define H_Right_Border12'd0
      `define H_Front_Porch12'd2
      `define H_Sync_Time12'd41
      `define H_Back_Porch12'd2
      `define H_Left_Border12'd0

      `define V_Total_Time12'd286
      `define V_Bottom_Border12'd0
      `define V_Front_Porch12'd2
      `define V_Sync_Time12'd10
      `define V_Back_Porch12'd2
      `define V_Top_Border12'd0
      
`elsif Resolution_640x480
      `define H_Total_Time12'd800
      `define H_Right_Border12'd8
      `define H_Front_Porch12'd8
      `define H_Sync_Time12'd96
      `define H_Back_Porch12'd40
      `define H_Left_Border12'd8

      `define V_Total_Time12'd525
      `define V_Bottom_Border12'd8
      `define V_Front_Porch12'd2
      `define V_Sync_Time12'd2
      `define V_Back_Porch12'd25
      `define V_Top_Border12'd8

`elsif Resolution_800x480
      `define H_Total_Time 12'd1056
      `define H_Right_Border 12'd0
      `define H_Front_Porch 12'd40
      `define H_Sync_Time 12'd128
      `define H_Back_Porch 12'd88
      `define H_Left_Border 12'd0

      `define V_Total_Time 12'd525
      `define V_Bottom_Border 12'd8
      `define V_Front_Porch 12'd2
      `define V_Sync_Time 12'd2
      `define V_Back_Porch 12'd25
      `define V_Top_Border 12'd8

`elsif Resolution_800x600
      `define H_Total_Time 12'd1056
      `define H_Right_Border 12'd0
      `define H_Front_Porch 12'd40
      `define H_Sync_Time 12'd128
      `define H_Back_Porch 12'd88
      `define H_Left_Border 12'd0

      `define V_Total_Time 12'd628
      `define V_Bottom_Border 12'd0
      `define V_Front_Porch 12'd1
      `define V_Sync_Time 12'd4
      `define V_Back_Porch 12'd23
      `define V_Top_Border 12'd0

`elsif Resolution_1024x768
      `define H_Total_Time 12'd1344
      `define H_Right_Border 12'd0
      `define H_Front_Porch 12'd24
      `define H_Sync_Time 12'd136
      `define H_Back_Porch 12'd160
      `define H_Left_Border 12'd0

      `define V_Total_Time 12'd806
      `define V_Bottom_Border 12'd0
      `define V_Front_Porch 12'd3
      `define V_Sync_Time 12'd6
      `define V_Back_Porch 12'd29
      `define V_Top_Border 12'd0

`elsif Resolution_1280x720
      `define H_Total_Time 12'd1650
      `define H_Right_Border 12'd0
      `define H_Front_Porch 12'd110
      `define H_Sync_Time 12'd40
      `define H_Back_Porch 12'd220
      `define H_Left_Border 12'd0

      `define V_Total_Time 12'd750
      `define V_Bottom_Border 12'd0
      `define V_Front_Porch 12'd5
      `define V_Sync_Time 12'd5
      `define V_Back_Porch 12'd20
      `define V_Top_Border 12'd0
               
`elsif Resolution_1920x1080
      `define H_Total_Time 12'd2200
      `define H_Right_Border 12'd0
      `define H_Front_Porch 12'd88
      `define H_Sync_Time 12'd44
      `define H_Back_Porch 12'd148
      `define H_Left_Border 12'd0

      `define V_Total_Time 12'd1125
      `define V_Bottom_Border 12'd0
      `define V_Front_Porch 12'd4
      `define V_Sync_Time 12'd5
      `define V_Back_Porch 12'd36
      `define V_Top_Border 12'd0      
      
`endif
第2个地方在“ov7670_sdram_display.v”文件,也就是工程顶层中,大约75~80行,根据不同的分辨率设置写入到SDRAM中的图像的长宽尺寸,代码如下所示:
      `ifdef Resolution_480x272
                parameter IMG_WIDTH = 480;
                parameter IMG_HIGHT = 272;
      `else
                parameter IMG_WIDTH = 640;
                parameter IMG_HIGHT = 480;      
      `endif      



第3个地方也在“ov7670_sdram_display.v”文件,也就是工程顶层中,大约153~165行,进一步参数化设计,指定CMOS图像采集模块输出采集到的整幅图像的那一个区域。该选项主要是考虑到OV7670摄像头输出的图像大小固定为640*480像素,而4.3寸屏的分辨率只有480*272像素,所以通过设置CMOS图像采集模块仅输出640*480图像的正中心的480*272个像素的数据出来存入SDRAM,以实现图像裁剪的功能。该条件编译代码如下所示:

      CMOS_Capture_RGB565      
      #(
                .CMOS_FRAME_WAITCNT                (4'd10),                              //Wait n fps for steady(OmniVision need 10 Frame)
      `ifdef Resolution_480x272
                .OUTIMG_HSTART                (12'd79),                //实际输出图像的宽度起始像素
                .OUTIMG_HSTOP                (12'd559),                //实际输出图像的宽度结束像素
                .OUTIMG_VSTART                (12'd103),                //实际输出图像的高度起始像素
                .OUTIMG_VSTOP                (12'd375)                //实际输出图像的高度结束像素
      `else
                .OUTIMG_HSTART                (12'd0),                        //实际输出图像的宽度起始像素
                .OUTIMG_HSTOP                (12'd640),                //实际输出图像的宽度结束像素
                .OUTIMG_VSTART                (12'd0),                        //实际输出图像的高度起始像素
                .OUTIMG_VSTOP                (12'd480)                //实际输出图像的高度结束像素               
      `endif      
      )



第4个地方还是在“ov7670_sdram_display.v”文件中,大约273~290行
因为OV7670的输出分辨率为640*480,而5寸显示屏的分辨率为800*480,也就是说,5寸屏的行像素比OV7670的输出图像行像素多160个像素,因此,根据像素一一对应的关系,显示屏必然有160*480个像素区域没有实际图像像素与之对应,为了正常显示,可以将这个区域分成两部分,左右各80*480个像素,采用黑色填充,这样640*480的图像就会显示在5寸屏的正中心位置。该部分代码如下所示:

      //定义不同分辨率时输出数据的选择情况
`ifdef Resolution_800x480
      assign Disp_Red = disp_req?Disp_Red_r : 8'd0;
      assign Disp_Green = disp_req? Disp_Green_r : 8'd0;
      assign Disp_Blue = disp_req? Disp_Blue_r : 8'd0;      
      
      always@(posedge ClkDisp)
                disp_req <= (DataReq && (H_Addr > 79) && (H_Addr < 720));
      
      assign RD_Req = disp_req;
      
`else
      assign Disp_Red = Disp_Red_r;
      assign Disp_Green = Disp_Green_r;
      assign Disp_Blue = Disp_Blue_r;      
      
      assign RD_Req = DataReq;      
`endif



基本上几个设计要点就解释清楚了。再有什么内容,后面再补充吧。

2019年4月22日
修改了下,加入了对OV7725摄像头的支持,因此文件名称也改为了通配型的ov7xxx,不再特指某个具体型号,同时,将条件编译开关独立写在sys_cfg.v文件中,不再放在显示屏的参数配置文件里了,体现分层思想。


admin 发表于 2019-4-13 23:22:50

适配VGA模块一定要通过翻转像素时钟来解决吗?不,一定不是这样的,一定是哪里没有做好,比如。。。。。IO的时序约束。

emmmmm,说干就干,看了下GM7123的数据手册,建立时间0.8ns,保持时间1.5ns,emmmm,这个参数非常的常规,根本不用翻转时钟,所以,一定是没加IO约束,让Quartus随心所欲,结果搞砸了导致的。那么,开干,加上约束后,就真的解决了问题耶。以下为时序约束的内容


## Generated SDC file "ov7670_sdram_display.sdc"

## Copyright (C) 1991-2013 Altera Corporation
## Your use of Altera Corporation's design tools, logic functions
## and other software and tools, and its AMPP partner logic
## functions, and any output files from any of the foregoing
## (including device programming or simulation files), and any
## associated documentation or information are expressly subject
## to the terms and conditions of the Altera Program License
## Subscription Agreement, Altera MegaCore Function License
## Agreement, or other applicable license agreement, including,
## without limitation, that your use is for the sole purpose of
## programming logic devices manufactured by Altera and sold by
## Altera or its authorized distributors.Please refer to the
## applicable agreement for further details.


## VENDOR"Altera"
## PROGRAM "Quartus II"
## VERSION "Version 13.0.0 Build 156 04/24/2013 SJ Full Version"

## DATE    "Sat Apr 13 21:27:43 2019"

##
## DEVICE"EP4CE10F17C8"
##


#**************************************************************
# Time Information
#**************************************************************

set_time_format -unit ns -decimal_places 3



#**************************************************************
# Create Clock
#**************************************************************

create_clock -name {clk50} -period 20.000 -waveform { 0.000 10.000 }
create_clock -name {pclk} -period 46.667 -waveform { 0.000 23.333 }


#**************************************************************
# Create Generated Clock
#**************************************************************

create_generated_clock -name {pll|altpll_component|auto_generated|pll1|clk} -source }] -duty_cycle 50.000 -multiply_by 2 -master_clock {clk50} }]
create_generated_clock -name {pll|altpll_component|auto_generated|pll1|clk} -source }] -duty_cycle 50.000 -multiply_by 2 -phase -90.000 -master_clock {clk50} }]
create_generated_clock -name {pll|altpll_component|auto_generated|pll1|clk} -source }] -duty_cycle 50.000 -multiply_by 12 -divide_by 25 -master_clock {clk50} }]
create_generated_clock -name {pll|altpll_component|auto_generated|pll1|clk} -source }] -duty_cycle 50.000 -multiply_by 12 -divide_by 25 -master_clock {clk50} }]
create_generated_clock -name {Clk_TFT} -source }] -master_clock {pll|altpll_component|auto_generated|pll1|clk}


#**************************************************************
# Set Clock Latency
#**************************************************************



#**************************************************************
# Set Clock Uncertainty
#**************************************************************



#**************************************************************
# Set Input Delay
#**************************************************************

set_input_delay -add_delay -max -clock 26.667 }]
set_input_delay -add_delay -min -clock 8.000 }]
set_input_delay -add_delay -max -clock 26.667 }]
set_input_delay -add_delay -min -clock 8.000 }]
set_input_delay -add_delay -max -clock 26.667 }]
set_input_delay -add_delay -min -clock 8.000 }]
set_input_delay -add_delay -max -clock 26.667 }]
set_input_delay -add_delay -min -clock 8.000 }]
set_input_delay -add_delay -max -clock 26.667 }]
set_input_delay -add_delay -min -clock 8.000 }]
set_input_delay -add_delay -max -clock 26.667 }]
set_input_delay -add_delay -min -clock 8.000 }]
set_input_delay -add_delay -max -clock 26.667 }]
set_input_delay -add_delay -min -clock 8.000 }]
set_input_delay -add_delay -max -clock 26.667 }]
set_input_delay -add_delay -min -clock 8.000 }]
set_input_delay -add_delay -max -clock 26.667
set_input_delay -add_delay -min -clock 8.000
set_input_delay -add_delay -max -clock 26.667
set_input_delay -add_delay -min -clock 8.000


#**************************************************************
# Set Output Delay
#**************************************************************

set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200
set_output_delay -add_delay -min -clock -1.500
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200
set_output_delay -add_delay -min -clock -1.500
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200 }]
set_output_delay -add_delay -min -clock -1.500 }]
set_output_delay -add_delay -max -clock 0.200
set_output_delay -add_delay -min -clock -1.500


#**************************************************************
# Set Clock Groups
#**************************************************************



#**************************************************************
# Set False Path
#**************************************************************

set_false_path -from -to
set_false_path -from -to
set_false_path -from -to
set_false_path -from -to


#**************************************************************
# Set Multicycle Path
#**************************************************************



#**************************************************************
# Set Maximum Delay
#**************************************************************



#**************************************************************
# Set Minimum Delay
#**************************************************************



#**************************************************************
# Set Input Transition
#**************************************************************


admin 发表于 2019-4-22 23:08:19


终于把一个大坑填完了,显示屏有好几种规格,摄像头也是,总共有9中硬件搭配,每个搭配都得提供至少一个应用工程,一旦哪天在某个地方有了更优化的设计方案,一次性得改最少9个工程,这还只是针对一个板卡的,如果要同时支持AC620、AC609、Starter的话,任务量再乘以三,一旦有个优化改动,就得修改27个工程文件,太痛苦了,所以直接做了个通杀工程,一个工程通杀所有配置。




/*************【使用说明】***************************

1、本工程可以通过简单的设置适配各种不同的硬件搭配,包括:

        --【OV7670】摄像头 + 【4.3寸/5寸/VGA输出】显示屏
        --【OV7725】摄像头 + 【4.3寸/5寸/VGA输出】显示屏
        --【OV5640】摄像头 + 【4.3寸/5寸/VGA输出】显示屏
---------------------------------------------------

2、具体用户使用哪种硬件,在sys_cfg.v文件中,通过取消代码注
   释的方式使能该选项,总共有两个选项需要选择:

        --使用的的摄像头型号(OV7670、OV7725、OV5640)
        --使用的的显示设备型号(HW_TFT43、HW_TFT50、HW_VGA)
---------------------------------------------------

3、本工程提供了三款FPGA开发板的引脚分配脚本文件,在工程目
   录的tcl文件夹下,支持AC620、AC609、Starter开发板,使
        用时请根据具体使用的FPGA硬件平台,先在引脚分配界面中删
        除所有引脚分配位置后,再在Quartus软件中运行对应板卡和
        对应显示设备的tcl脚本文件以完成引脚分配。每个板卡提供了
        2个脚本文件,分别为使用GM7123模块的VGA输出方式和使用
        4.3/5寸显示屏(两个屏引脚分配完全一样)的引脚分配,用户
        需要根据自己实际使用的硬件,选择相应的tcl脚本运行
*/


萌萌的_X29uk 发表于 2019-6-20 09:58:27

关于2019年4月12日OV7670_SDRAM_Display工程使用中遇到的问题:
1、工程默认为4.3寸TFTLCD显示设备+OV7670,使用时硬件配置使用AC620+OV7670+4.3寸LCD显示屏幕(均为小梅哥店铺产品)
2、编译器为Quartus 17.1
3、压缩文件解压后对工程进行了一次全编译,Quartus提示IP需要升级
4、编译完成后,PLL模块的clock_2,clock_3输出时钟均被设置为24M,(按照工程和代码注释,clock_3为LCD的驱动时钟,TFT模式下应该为9M)
5、下载后LCD显示无图像
6、PLL中无法通过设置分频出9MHZ的时钟
希望小梅哥有时间解答一下

admin 发表于 2019-6-20 10:23:52

萌萌的_X29uk 发表于 2019-6-20 09:58
关于2019年4月12日OV7670_SDRAM_Display工程使用中遇到的问题:
1、工程默认为4.3寸TFTLCD显示设备+OV7670 ...

1、clock2和clock3都是24M,这没问题,因为LCD的时钟即使不准也能显示,不过就是帧率的变化,而VGA的时钟必须是准确的24M,所以为了兼容性统一设置的24M。
2、下载后LCD无法显示,请检查你的引脚分配。使用对应的tcl文件重新执行一次

划破苍穹 发表于 2019-9-6 16:01:43

请问一下,有这方面相关的视频或文档吗
页: [1]
查看完整版本: 【更新0412】小梅哥OV7670摄像头适配的工程实例和使用说明