搜索
bottom↓
回复: 0

《新起点V2之FPGA开发指南》第四十一章 OV5640摄像头RGB-LCD显示

[复制链接]

出0入234汤圆

发表于 2021-10-14 17:57:07 | 显示全部楼层 |阅读模式
本帖最后由 正点原子 于 2021-10-30 10:47 编辑

1)实验平台:正点原子新起点V2FPGA开发板
2)  章节摘自【正点原子】《新起点之FPGA开发指南 V2.1》
3)购买链接:https://detail.tmall.com/item.htm?id=609758951113
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-328002-1-1.html
5)正点原子官方B站:https://space.bilibili.com/394620890
6)正点原子FPGA技术交流QQ群:712557122
1.png


2.jpg


3.png


第四十一章 OV5640摄像头RGB-LCD显示实验

       OV5640同OV7725一样,都是OmniVision(豪威科技)公司生产的CMOS图像传感器。不同的是,OV5640支持更高的分辨率、采集速率,具有更高的图像处理性能,主要应用在手机、数码相机、电脑多媒体等领域。本章将使用FPGA开发板实现对OV5640的数字图像采集并通过LCD实时显示。
       本章包括以下几个部分:
       1.1简介
       1.2实验任务
       1.3硬件设计
       1.4程序设计
       1.5下载验证

1.1简介
       OV5640是一款1/4英寸单芯片图像传感器,其感光阵列达到2592*1944(即500W像素),能实现最快15fps QSXVGA(2592*1944)或者90fps VGA(640*480)分辨率的图像采集。传感器采用OmniVision推出的OmniBSI(背面照度)技术,使传感器达到更高的性能,如高灵敏度、低串扰和低噪声。传感器内部集成了图像处理的功能,包括自动曝光控制(AEC)、自动白平衡(AWB)等。同时该传感器支持LED补光、MIPI(移动产业处理器接口)输出接口和DVP(数字视频并行)输出接口选择、ISP(图像信号处理)以及AFC(自动聚焦控制)等功能。
       OV5640的功能框图如下图所示:
第四十一章 OV5640摄像头RGB523.png

图 41.1.1 OV5640功能框图

       由上图可知,时序发生器(timing generator)控制着感光阵列(image array)、放大器(AMP)、AD转换以及输出外部时序信号(VSYNC、HREF和PCLK),外部时钟XVCLK经过PLL锁相环后输出的时钟作为系统的控制时钟;感光阵列将光信号转化成模拟信号,经过增益放大器之后进入10位AD转换器;AD转换器将模拟信号转化成数字信号,并且经过ISP进行相关图像处理,最终输出所配置格式的10位视频数据流。增益放大器控制以及ISP等都可以通过寄存器(registers)来配置,配置寄存器的接口就是SCCB接口,该接口协议兼容IIC协议。
       OV5640使用的是两线式SCCB接口总线,有关SCCB总线的详细介绍可以参考“OV7725摄像头RGB-LCD显示实验”中OV7725简介部分。虽然OV5640和OV7725都是采用SCCB接口总线来配置寄存器,但不同的是,OV7725是用8位(1个字节)来表示寄存器地址,而OV5640是用16位(两个字节)表示寄存器地址。
       OV5640 SCCB的写传输协议如下图所示:
1.png

图 41.1.2 SCCB写传输协议

        上图中的ID ADDRESS是由7位器件地址和1位读写控制位构成(0:写 1:读),OV5640的器件地址为7’h3c,所以在写传输协议中,ID Address(W)= 8’h78(器件地址左移1位,低位补0);Sub-address(H)为高8位寄存器地址,Sub-address(L)为低8位寄存器地址,在OV5640众多寄存器中,有些寄存器是可改写的,有些是只读的,只有可改写的寄存器才能正确写入;Write Data为8位写数据,每一个寄存器地址对应8位的配置数据。
       在OV5640正常工作之前,必须先对传感器进行初始化,即通过配置寄存器使其工作在预期的工作模式,以及得到较好画质的图像。因为SCCB的写传输协议和IIC几乎相同,因此我们可以直接使用IIC的驱动程序来配置摄像头。当然这么多寄存器也并非都需要配置,很多寄存器可以采用默认的值。OV公司提供了OV5640的软件应用手册(OV5640 Software Application Note,位于开发板所随附的资料“7_硬件资料/4_OV5640资料/OV5640_camera_module_software_application_notes.pdf”),如果某些寄存器不知道如何配置可以参考此手册,下表是本程序用到的关键寄存器的配置说明。
2 1.png

2 2.png

表 41.1.1 OV5640关键寄存器配置说明


       OV5640的寄存器较多,对于其它寄存器的描述可以参OV5640的数据手册。需要注意的是,OV5640的数据手册并没有提供全部的寄存器描述,而大多数必要的寄存器配置在ov5640的软件应用手册中可以找到,可以结合这两个手册学习如何对OV5640进行配置。
1)输出图像参数设置
       接下来,我们介绍一下OV5640的ISP输入窗口设置、预缩放窗口设置和输出大小窗口设置,这几个设置与我们的正常使用密切相关,有必要了解一下,它们的设置关系如下图所示:
第四十一章 OV5640摄像头RGB3414.png

图 41.1.3 图像窗口设置

       ISP输入窗口设置(ISP Input Size)允许用户设置整个传感器显示区域(physical pixel size,2632*1951,其中2592*1944像素是有效的),开窗范围从0*0~2632*1951都可以任意设置。也就是上图中的X_ADDR_ST(寄存器地址0x3800、0x3801)、Y_ADDR_ST(寄存器地址0x3802、0x3803)、X_ADDR_END(寄存器地址0x3804、0x3805)和Y_ADDR_END(寄存器地址0x3806、0x3807)寄存器。该窗口设置范围中的像素数据将进入ISP进行图像处理。
       预缩放窗口设置(pre-scaling size)允许用户在ISP输入窗口的基础上进行裁剪,用于设置将进行缩放的窗口大小,该设置仅在ISP输入窗口内进行X/Y方向的偏移。可以通过X_OFFSET(寄存器地址0x3810、0x3811)和Y_OFFSET(寄存器地址0x3812、0x3813)进行配置。
       输出大小窗口设置(data output size)是在预缩放窗口的基础上,经过内部DSP进行缩放处理,并将处理后的数据输出给外部的图像窗口,图像窗口控制着最终的图像输出尺寸。可以通过X_OUTPUT_SIZE(寄存器地址0x3808、0x3809)和Y_OUTPUT_SIZE(寄存器地址0x380A、0x380B)进行配置。注意:当输出大小窗口与预缩放窗口比例不一致时,图像将进行缩放处理(图像变形),仅当两者比例一致时,输出比例才是1:1(正常图像)。
       图 41.1.3 图像窗口设置中,右侧data output size区域,才是OV5640输出给外部的图像尺寸,也就是显示在显示器或者液晶屏上面的图像大小。输出大小窗口与预缩放窗口比例不一致时,会进行缩放处理,在显示器上面看到的图像将会变形。
1)输出像素格式
       OV5640支持多种不同的数据像素格式,包括YUV(亮度参量和色度参量分开表示的像素格式)、RGB(其中RGB格式包含RGB565、RGB555等)以及RAW(原始图像数据),通过寄存器地址0x4300配置成不同的数据像素格式。
       由于摄像头采集的图像最终要通过LCD显示,故我们将OV5640摄像头输出的图像像素数据配置成RGB565格式。由上表(表 41.1.1)可知,将寄存器0x4300寄存器的Bit[7:4]设置成0x6即可。OV5640支持调节RGB565输出格式中各颜色变量的顺序,对于我们常见的应用来说,一般是使用RGB或BGR序列。我们在“OV7725摄像头RGB-LCD显示实验”的章节中介绍过,OV7725摄像头按照RGB的顺序输出,本章我们将OV5640输出的RGB565的颜色顺序和OV7725保持一致,将寄存器0x4300寄存器的Bit[3:0]设置成0x1。因此,“OV7725摄像头RGB-LCD显示实验”章节中的图像采集模块可以直接用来采集OV5640输出的图像。
2)彩条测试模式
       图像传感器配置成彩条测试模式后,会输出彩色的条纹,方便测试图像传感器是否正常工作,通过配置寄存器0x503d的Bit[7]位打开和关闭彩条模式。当需要打开彩条模式时,寄存器0x503d配置成0x80,关闭时配置成0x00,下图为打开彩条模式后图像输出的条纹。
第四十一章 OV5640摄像头RGB4928.png

图 41.1.4 彩条模式下的图像条纹

3)LED闪光灯
       当外界环境光较暗时,传感器采集图像会受到较大影响,此时可以通过打开LED补光灯来弥补光照不足所带来的影响,就像手机在夜晚拍照时也会打开闪光灯来提高图像质量。通过配置寄存器0x3016=0x02,0x301c=0x02来使能LED补光灯功能;配置寄存器0x3019=0x02打开闪光灯,0x3019=0x00关闭闪光灯。
4)图像输出时序
       接下来,我们介绍一下OV5640的图像数据输出时序,首先我们简单介绍一些定义。
       QSXGA,这里指:分辨率为2592*1944的输出格式,类似的还有:QXGA(2048*1536)、UXGA(1600*1200)、SXGA(1280*1024)、WXGA(1440*900)、WXGA(1280*800)、XGA(1024*768)、SVGA(800*600)、VGA(640*480)、QVGA(320*240)和QQVGA(160*120)等。
       PCLK:像素时钟,一个PCLK时钟输出一个像素或者半个像素(像素数据的高8位或者低8位)。
       VSYNC:帧同步信号。
       HREF/HSYNC:行同步信号。
       D[9:0]:像素数据,在RGB565格式中,只有高8位是有效的。
       tPclk:一个时钟周期 。
       tp:一个像素点的周期,在RGB565和YUV422输出格式下,tp=2*tPclk;Raw输出格式下,tp=tPclk。
       下图为OV5640输出图像数据的行时序图。
第四十一章 OV5640摄像头RGB5603.png

图 41.1.5 OV5640行时序图

       从上图可以看出,传感器在HREF为高电平的时候输出图像数据,当HREF变高后,每一个 PCLK时钟,输出一个8位或者10位像素数据。比如我们采用QSXGA时序,RGB565格式输出,tp=2*tPclk,每2个字节组成一个像素的颜色,这样每行总共输出2592*2个PCLK,也就是2592*2个字节。
       再来看看帧时序(QSXGA模式,分辨率2592*1944),如下图所示:
第四十一章 OV5640摄像头RGB5856.png

图 41.1.6 OV5640 QSXGA帧时序

       由上图可知,VSYNC的上升沿作为一帧的开始,高电平同步脉冲的时间为5688tp,紧接着等待48276tp时间后,HREF开始拉高,此时输出有效数据;HREF由2592tp个高电平和252tp个低电平构成;最后一行图像数据输出完成之后等待14544tp时间,一帧数据传输结束。所以输出一帧图像的时间实际上是tFrame = 5596992tp。
       从OV5640的行时序图和帧时序图可以发现,其输出时序和OV7725是非常相似的,只是时间参数不同而已,大家可以参考“OV7725摄像头RGB-LCD显示实验”中帧时序的介绍来学习OV5640的输出时序。
1.2实验任务
       本节实验任务是使用新起点开发板及OV5640摄像头实现图像采集,并通过RGB-LCD接口驱动RGB-LCD液晶屏(支持目前正点原子推出的所有RGB-LCD屏),并实时显示出图像。
1.3硬件设计
       我们的新起点FPGA开发板上有一个摄像头扩展接口,该接口可以用来连接OV7725/OV5640等摄像头模块,摄像头扩展接口原理图如下图所示:
第四十一章 OV5640摄像头RGB6373.png

图 41.3.1 摄像头扩展接口原理图

        ATK-OV5640是正点原子推出的一款高性能500W像素高清摄像头模块。该模块通过2*9排针(2.54mm间距)同外部连接,我们将摄像头的排针直接插在开发板上的摄像头接口即可,模块外观如图 41.3.2所示:
第四十一章 OV5640摄像头RGB6584.png

图 41.3.2 OV5640摄像头连接开发板图

       从图 41.3.2可以看出,模块自带有源晶振,用于产生24MHz时钟作为OV5640的输入时钟。模块的闪光灯(LEDI&LED2)由OV5640的STROBE引脚控制,用户可通过SCCB接口总线控制STROBE引脚输出高低电平,从而控制LED闪光灯的亮灭。用户在使用LED灯时不建议一直点亮或者点亮时间太长。因为LED闪光灯功率较高,发光强度较强,模块温度上升会比较快,会造成器件的可靠性降低,同时注意避免直接照射人眼。
       我们在前面说过,OV5640在RGB565模式下只有高8位数据是有效的即D[9:2],而我们的摄像头排针上数据引脚的个数是8位。实际上,摄像头排针上的8位数据连接的就是OV5640传感器的D[9:2],所以我们直接使用摄像头排针上的8位数据引脚即可。
       由于LCD接口和SDRAM引脚数目较多且在前面相应的章节中已经给出它们的管脚列表,这里只列出摄像头相关管脚分配,如下表所示:
3.png


表 41.3.1 OV5640摄像头管脚分配

       摄像头TCL约束文件如下:
  1. set_location_assignment PIN_T14 -to cam_data[7]
  2. set_location_assignment PIN_R14 -to cam_data[6]
  3. set_location_assignment PIN_N6 -to cam_data[5]
  4. set_location_assignment PIN_P6 -to cam_data[4]
  5. set_location_assignment PIN_M8 -to cam_data[3]
  6. set_location_assignment PIN_N8 -to cam_data[2]
  7. set_location_assignment PIN_P8 -to cam_data[1]
  8. set_location_assignment PIN_K9 -to cam_data[0]
  9. set_location_assignment PIN_M9 -to cam_href
  10. set_location_assignment PIN_R13 -to cam_pclk
  11. set_location_assignment PIN_R12 -to cam_pwdn
  12. set_location_assignment PIN_L9 -to cam_rst_n
  13. set_location_assignment PIN_N9 -to cam_scl
  14. set_location_assignment PIN_L10 -to cam_sda
  15. set_location_assignment PIN_P9 -to cam_vsync
复制代码

1.4程序设计
       图 41.4.1是根据本章实验任务画出的系统框图。PLL时钟模块为I2C驱动模块、LCD顶层模块以及SDRAM控制器模块提供驱动时钟;I2C驱动模块和I2C配置模块、图像尺寸配置模块用于初始化OV5640图像传感器;摄像头采集模块负责采集摄像头图像数据,并且把图像数据写入SDRAM读写控制模块;SDRAM读写控制模块负责将用户数据写入和读出片外SDRAM存储器中;LCD顶层模块负责驱动RGB TFT-LCD显示屏。
       OV5640摄像头RGB TFT-LCD显示系统框图如下图所示:
第四十一章 OV5640摄像头RGB8646.png

图 41.4.1 OV5640摄像头RGB TFT-LCD显示系统框图

       顶层模块的原理图如下图所示:
第四十一章 OV5640摄像头RGB8742.png

图 41.4.2 顶层模块原理图

       由上图可知,I2C配置模块和I2C驱动模块控制着传感器初始化的开始与结束,传感器初始化完成后图像采集模块将采集到的数据写入SDRAM读写控制模块,LCD模块从SDRAM控制模块中读出数据,完成了数据的采集、缓存与显示。其中图像数据采集模块是在SDRAM和传感器都初始化完成之后才开始输出数据的,避免了在SDRAM初始化过程中向里面写入数据。
       FPGA顶层模块(ov5640_rgb565_lcd)例化了以下六个模块:PLL时钟模块(pll_clk)、I2C驱动模块(i2c_dri)、I2C配置模块(i2c_ov5640_rgb565_cfg)、摄像头图像采集模块(cmos_capture_data)、图像尺寸配置模块(picture_size)、SDRAM读写控制模块(sdram_top)和LCD顶层模块(lcd_rgb_top)。
        PLL时钟模块(pll_clk):PLL时钟模块通过调用锁相环(PLL)IP核实现,总共输出3个时钟,频率分别为100Mhz、100Mhz(SDRAM相位偏移时钟)和50Mhz(LCD分频用)时钟。100Mhz时钟和100Mhz相位偏移时钟作为SDRAM读写控制模块的驱动时钟,最后一个50Mhz时钟作为LCD顶层模块的驱动时钟。
       I2C驱动模块(i2c_dri):I2C驱动模块负责驱动OV5640 SCCB接口总线,用户可根据该模块提供的用户接口对OV5640的寄存器进行配置,该模块和“EEPROM读写实验”章节中用到的I2C驱动模块为同一个模块,有关该模块的详细介绍请大家参考“EEPROM读写实验”章节。
       I2C配置模块(i2c_ov5640_rgb565_cfg):I2C配置模块的驱动时钟是由I2C驱动模块输出的时钟提供的,这样方便了I2C驱动模块和I2C配置模块之间的数据交互。该模块寄存需要配置的寄存器地址、数据以及控制初始化的开始与结束,同时该模块输出OV5640的寄存器地址和数据以及控制I2C驱动模块开始执行的控制信号,直接连接到I2C驱动模块的用户接口,从而完成对OV5640传感器的初始化。OV7725和OV5640寄存器配置时序非常相似,有关该模块的详细介绍请大家参考“OV7725摄像头RGB-LCD显示实验”章节。
       摄像头图像采集模块(cmos_capture_data):摄像头采集模块在像素时钟的驱动下将传感器输出的场同步信号、行同步信号以及8位数据转换成SDRAM读写控制模块的写使能信号和16位写数据信号,完成对OV5640传感器图像的采集。OV7725和OV5640图像输出时序非常相似,有关该模块的详细介绍请大家参考“OV7725摄像头RGB-LCD显示实验”章节。
       图像尺寸配置模块(picture_size):图像尺寸配置模块用于配置摄像头输出图像尺寸的大小,以及设置摄像头输出图像的帧率(每秒输出图像的帧数),此外还完成了SDRAM的读写结束地址设置。
SDRAM读写控制模块(sdram_top):SDRAM读写控制器模块负责驱动SDRAM片外存储器,缓存图像传感器输出的图像数据。该模块将SDRAM复杂的读写操作封装成类似FIFO的用户接口,非常方便用户的使用。有关该模块的详细介绍请大家参考“SDRAM读写测试实验”章节,修改部分请大家参考“OV7725摄像头RGB-LCD显示实验”章节。
       LCD顶层模块(lcd_rgb_top):LCD顶层模块下例化了以下三个模块:读ID模块(rd_id)、分频模块(clk_div)、LCD驱动模块(lcd_driver)。
       读ID模块(rd_id):读ID模块用于读取连接到开发板上的LCD的ID。
       分频模块(clk_div):分频模块用于输出驱动LCD所需要的时钟。由于不同尺寸/分辨率RGB LCD的驱动时钟频率是不一样的,该模块实现不同LCD的驱动时钟适配。
       LCD驱动模块(lcd_driver):LCD驱动模块负责驱动LCD液晶屏,该模块通过读取SDRAM读写控制模块来输出像素数据,本次实验将LCD驱动模块的内部信号data_req(数据请求信号)输出至端口,方便从SDRAM控制器中读取数据。有关LCD驱动模块的详细介绍请大家参考“RGB-LCD彩条显示实验”章节。
       下面是顶层模块中参数设置需要注意的地方,顶层模块参数设置代码如下:
  1. 34  //parameter define
  2. 35  parameter SLAVE_ADDR = 7'h3c          ; //OV5640的器件地址7'h3c
  3. 36  parameter BIT_CTRL   = 1'b1           ; //OV5640的字节地址为16位  0:8位 1:16位
  4. 37  parameter CLK_FREQ   = 27'd50_000_000 ; //i2c_dri模块的驱动时钟频率
  5. 38  parameter I2C_FREQ   = 18'd250_000    ; //I2C的SCL时钟频率,不超过400KHz
复制代码

       在代码的第35行定义了OV5640的器件地址,其器件地址为7’h3c;第36行定义了寄存器地址的位宽,BIT_CTRL=0表示地址位宽为8位,BIT_CTRL=1表示地址位宽为16位。因为OV5640的地址位宽为16位,所以BIT_CTRL设置为1。
       下面是顶层模块里锁相环例化部分:
  1. 82  //锁相环
  2. 83  pll u_pll(
  3. 84      .areset             (~sys_rst_n),
  4. 85      .inclk0             (sys_clk),
  5. 86              
  6. 87      .c0                 (clk_100m),
  7. 88      .c1                 (clk_100m_shift),
  8. 89      .c2                 (clk_50m_lcd),
  9. 90      .locked             (locked)
  10. 91      );
复制代码

       在代码的第89行输出了一个50Mhz的时钟clk_50m_lcd,作为LCD顶层模块和I2C驱动模块(i2c_dri)的驱动时钟。
       为了适配现有的RGB LCD屏幕,我们对I2C配置模块的端口部分进行了修改:
  1. 104 //I2C配置模块
  2. 105 i2c_ov5640_rgb565_cfg u_i2c_cfg(
  3. 106     .clk                (i2c_dri_clk),
  4. 107     .rst_n              (rst_n),
  5. 108            
  6. 109     .i2c_exec           (i2c_exec),
  7. 110     .i2c_data           (i2c_data),
  8. 111     .i2c_rh_wl          (i2c_rh_wl),        //I2C读写控制信号
  9. 112     .i2c_done           (i2c_done),
  10. 113     .i2c_data_r         (i2c_data_r),   
  11. 114                 
  12. 115     .cmos_h_pixel       (cmos_h_pixel),     //CMOS水平方向像素个数
  13. 116     .cmos_v_pixel       (cmos_v_pixel) ,    //CMOS垂直方向像素个数
  14. 117     .total_h_pixel      (total_h_pixel),    //水平总像素大小
  15. 118     .total_v_pixel      (total_v_pixel),    //垂直总像素大小
  16. 119         
  17. 120     .init_done          (cam_init_done)
  18. 121     );   
复制代码

       在本实验中,cmos_h_pixel、cmos_v_pixel这两个配置需要依据LCD尺寸的大小而改变。此外,total_h_pixel及total_v_pixel的参数也需要进行配置,它们会影响到输出图像的帧率。
       在顶层模块中例化了图像尺寸配置模块(picture_size),它输出了上一段提到的四个变量的具体数值:
  1. 93  //摄像头图像分辨率设置模块
  2. 94  picture_size u_picture_size (
  3. 95      .clk                (clk_50m_lcd   ),
  4. 96      .rst_n              (rst_n         ),
  5. 97      .id_lcd             (lcd_id        ),   //LCD的ID,用于配置摄像头的图像大小                        
  6. 98      .cmos_h_pixel       (cmos_h_pixel  ),   //摄像头水平方向分辨率
  7. 99      .cmos_v_pixel       (cmos_v_pixel  ),   //摄像头垂直方向分辨率  
  8. 100     .total_h_pixel      (total_h_pixel ),   //用于配置HTS寄存器
  9. 101     .total_v_pixel      (total_v_pixel ),   //用于配置VTS寄存器
  10. 102     .sdram_max_addr     (sdram_max_addr)    //sdram读写的最大地址
  11. 103     );
复制代码

      模块内部的代码如下:
  1. 1   module picture_size (
  2. 2       input              rst_n         ,
  3. 3       input              clk           ,         
  4. 4       input       [15:0] id_lcd        ,
  5. 5               
  6. 6       output reg  [12:0] cmos_h_pixel  ,
  7. 7       output reg  [12:0] cmos_v_pixel  ,   
  8. 8       output reg  [12:0] total_h_pixel ,
  9. 9       output reg  [12:0] total_v_pixel ,
  10. 10      output reg  [23:0] sdram_max_addr
  11. 11  );
  12. 12  
  13. 13  //parameter define
  14. 14  parameter  ID_4342 =   16'h4342;
  15. 15  parameter  ID_7084 =   16'h7084;
  16. 16  parameter  ID_7016 =   16'h7016;
  17. 17  parameter  ID_1018 =   16'h1018;
  18. 18  
  19. 19  //*****************************************************
  20. 20  //**                    main code                     
  21. 21  //*****************************************************
  22. 22  
  23. 23  //配置摄像头输出尺寸的大小
  24. 24  always @(posedge clk or negedge rst_n) begin
  25. 25      if(!rst_n) begin
  26. 26          cmos_h_pixel <= 13'b0;
  27. 27          cmos_v_pixel <= 13'd0;
  28. 28          sdram_max_addr <= 23'd0;        
  29. 29      end
  30. 30      else begin   
  31. 31          case(id_lcd )
  32. 32              16'h4342 : begin
  33. 33                  cmos_h_pixel   = 13'd480;   
  34. 34                  cmos_v_pixel   = 13'd272;
  35. 35                  sdram_max_addr = 23'd130560;
  36. 36              end
  37. 37              16'h7084 : begin
  38. 38                  cmos_h_pixel   = 13'd800;   
  39. 39                  cmos_v_pixel   = 13'd480;           
  40. 40                  sdram_max_addr = 23'd384000;
  41. 41              end
  42. 42              16'h7016 : begin
  43. 43                  cmos_h_pixel   = 13'd1024;   
  44. 44                  cmos_v_pixel   = 13'd600;           
  45. 45                  sdram_max_addr = 23'd614400;
  46. 46              end   
  47. 47              16'h1018 : begin
  48. 48                  cmos_h_pixel   = 13'd1280;   
  49. 49                  cmos_v_pixel   = 13'd800;           
  50. 50                  sdram_max_addr = 23'd1024000;
  51. 51              end
  52. 52          default : begin
  53. 53                  cmos_h_pixel   = 13'd800;   
  54. 54                  cmos_v_pixel   = 13'd480;           
  55. 55                  sdram_max_addr = 23'd384000;
  56. 56          end
  57. 57          endcase
  58. 58      end   
  59. 59  end
  60. 60  
  61. 61  //对HTS及VTS的配置会影响摄像头输出图像的帧率
  62. 62  always @(*) begin
  63. 63      case(id_lcd)
  64. 64          ID_4342 : begin
  65. 65              total_h_pixel = 13'd1800;
  66. 66              total_v_pixel = 13'd1000;
  67. 67          end
  68. 68          ID_7084 : begin  
  69. 69              total_h_pixel = 13'd1800;
  70. 70              total_v_pixel = 13'd1000;
  71. 71          end
  72. 72          ID_7016 : begin  
  73. 73              total_h_pixel = 13'd2200;
  74. 74              total_v_pixel = 13'd1000;
  75. 75          end
  76. 76          ID_1018 : begin
  77. 77              total_h_pixel = 13'd2570;
  78. 78              total_v_pixel = 13'd980;
  79. 79          end
  80. 80      default : begin
  81. 81              total_h_pixel = 13'd1800;
  82. 82              total_v_pixel = 13'd1000;
  83. 83      end
  84. 84      endcase
  85. 85  end
  86. 86  
  87. 87  endmodule  
复制代码

       我们通过组合逻辑对变量进行赋值,在代码的第31至第59行,对摄像头输出图像尺寸相关的参数(cmos_h_pixel、cmos_v_pixel)进行了配置。同时还配置了一帧图像在SDRAM里的结束缓存地址sdram_max_addr,它是cmos_h_pixel、cmos_v_pixel的乘积。
       在代码的61至85行,对影响帧率的参数total_h_pixel、total_v_pixel进行了配置。
       在顶层代码例化SDRAM顶层模块的170和179行,我们进行了修改。如下所示,SDRAM顶层模块的wr_max_addr与rd_max_addr端口和sdram_max_addr信号直连。
  1. 158  //SDRAM 控制器顶层模块,封装成FIFO接口
  2. 159  //SDRAM 控制器地址组成: {bank_addr[1:0],row_addr[12:0],col_addr[8:0]}
  3. 160  sdram_top u_sdram_top(
  4. 161  .ref_clk      (clk_100m),                   //sdram 控制器参考时钟
  5. 162  .out_clk      (clk_100m_shift),             //用于输出的相位偏移时钟
  6. 163  .rst_n        (rst_n),                      //系统复位
  7. 164                                             
  8. 165   //用户写端口                                 
  9. 166  .wr_clk       (cam_pclk),                   //写端口FIFO: 写时钟
  10. 167  .wr_en        (wr_en),                      //写端口FIFO: 写使能
  11. 168  .wr_data      (wr_data),                    //写端口FIFO: 写数据
  12. 169  .wr_min_addr  (24'd0),                      //写SDRAM的起始地址
  13. 170  .wr_max_addr  (sdram_max_addr),             //写SDRAM的结束地址
  14. 171  .wr_len       (10'd512),                    //写SDRAM时的数据突发长度
  15. 172  .wr_load      (~rst_n),                     //写端口复位: 复位写地址,清空写FIFO
  16. 173                                             
  17. 174   //用户读端口                                 
  18. 175  .rd_clk       (clk_lcd),                    //读端口FIFO: 读时钟
  19. 176  .rd_en        (rd_en),                      //读端口FIFO: 读使能
  20. 177  .rd_data      (rd_data),                    //读端口FIFO: 读数据
  21. 178  .rd_min_addr  (24'd0),                      //读SDRAM的起始地址
  22. 179  .rd_max_addr  (sdram_max_addr),             //读SDRAM的结束地址
  23. 180  .rd_len       (10'd512),                    //从SDRAM中读数据时的突发长度
  24. 181  .rd_load      (~rst_n),                     //读端口复位: 复位读地址,清空读FIFO
复制代码

       在顶层模块代码的最后,例化了LCD顶层模块(lcd),如下所示:
  1. 207 //LCD顶层模块
  2. 208 lcd_rgb_top  u_lcd_rgb_top(
  3. 209     .sys_clk                (clk_50m_lcd  ),
  4. 210     .sys_rst_n             (rst_n ),
  5. 211     .sys_init_done          (sys_init_done),        
  6. 212                        
  7. 213     //lcd接口                           
  8. 214     .lcd_id                (lcd_id),                //LCD屏的ID号
  9. 215     .lcd_hs                (lcd_hs),                //LCD 行同步信号
  10. 216     .lcd_vs                (lcd_vs),                //LCD 场同步信号
  11. 217     .lcd_de                (lcd_de),                //LCD 数据输入使能
  12. 218     .lcd_rgb               (lcd_rgb),               //LCD 颜色数据
  13. 219     .lcd_bl                (lcd_bl),                //LCD 背光控制信号
  14. 220     .lcd_rst               (lcd_rst),               //LCD 复位信号
  15. 221     .lcd_pclk              (lcd_pclk),              //LCD 采样时钟
  16. 222     .lcd_clk               (lcd_clk),               //LCD 驱动时钟
  17. 223     //用户接口                     
  18. 224     .out_vsync             (rd_vsync),              //lcd场信号
  19. 225     .h_disp                (),                      //行分辨率  
  20. 226     .v_disp                (),                      //场分辨率  
  21. 227     .pixel_xpos            (),
  22. 228     .pixel_ypos            (),      
  23. 229     .data_in               (rd_data),               //rfifo输出数据
  24. 230     .data_req              (rd_en)                  //请求数据输入
  25. 231     );   
复制代码

      LCD顶层模块里例化了读ID模块(rd_id)、分频模块(clk_div)、LCD驱动模块(lcd_driver),如下所示:
  1. 1   module lcd_rgb_top(
  2. 2       input           sys_clk      ,  //系统时钟
  3. 3       input           sys_rst_n,      //复位信号  
  4. 4       input           sys_init_done,
  5. 5       //lcd接口  
  6. 6       output          lcd_clk,        //LCD驱动时钟   
  7. 7       output          lcd_hs,         //LCD 行同步信号
  8. 8       output          lcd_vs,         //LCD 场同步信号
  9. 9       output          lcd_de,         //LCD 数据输入使能
  10. 10      inout  [15:0]   lcd_rgb,        //LCD RGB颜色数据
  11. 11      output          lcd_bl,         //LCD 背光控制信号
  12. 12      output          lcd_rst,        //LCD 复位信号
  13. 13      output          lcd_pclk,       //LCD 采样时钟
  14. 14      output  [15:0]  lcd_id,         //LCD屏ID  
  15. 15      output          out_vsync,      //lcd场信号
  16. 16      output  [10:0]  pixel_xpos,     //像素点横坐标
  17. 17      output  [10:0]  pixel_ypos,     //像素点纵坐标        
  18. 18      output  [10:0]  h_disp,         //LCD屏水平分辨率
  19. 19      output  [10:0]  v_disp,         //LCD屏垂直分辨率         
  20. 20      input   [15:0]  data_in,        //数据输入   
  21. 21      output          data_req        //请求数据输入
  22. 22      
  23. 23      );
  24. 24  
  25. 25  //wire define
  26. 26  wire  [15:0] lcd_rgb_565;           //输出的16位lcd数据
  27. 27  wire  [15:0] lcd_rgb_o ;            //LCD 输出颜色数据
  28. 28  wire  [15:0] lcd_rgb_i ;            //LCD 输入颜色数据
  29. 29  //*****************************************************
  30. 30  //**                    main code
  31. 31  //*****************************************************
  32. 32  //将摄像头16bit数据输出
  33. 33  assign lcd_rgb_o =lcd_rgb_565 ;         
  34. 34  
  35. 35  //像素数据方向切换
  36. 36  assign lcd_rgb = lcd_de ?  lcd_rgb_o :  {16{1'bz}};
  37. 37  assign lcd_rgb_i = lcd_rgb;
  38. 38              
  39. 39  //时钟分频模块   
  40. 40  clk_div u_clk_div(
  41. 41      .clk                    (sys_clk  ),
  42. 42      .rst_n                  (sys_rst_n),
  43. 43      .lcd_id                 (lcd_id   ),
  44. 44      .lcd_pclk               (lcd_clk  )
  45. 45      );  
  46. 46  
  47. 47  //读LCD ID模块
  48. 48  rd_id u_rd_id(
  49. 49      .clk                    (sys_clk  ),
  50. 50      .rst_n                  (sys_rst_n),
  51. 51      .lcd_rgb                (lcd_rgb_i),
  52. 52      .lcd_id                 (lcd_id   )
  53. 53      );  
  54. 54  
  55. 55  //lcd驱动模块
  56. 56  lcd_driver u_lcd_driver(           
  57. 57      .lcd_clk        (lcd_clk),   
  58. 58      .sys_rst_n      (sys_rst_n & sys_init_done),
  59. 59      .lcd_id         (lcd_id),   
  60. 60  
  61. 61      .lcd_hs         (lcd_hs),      
  62. 62      .lcd_vs         (lcd_vs),      
  63. 63      .lcd_de         (lcd_de),      
  64. 64      .lcd_rgb        (lcd_rgb_565),
  65. 65      .lcd_bl         (lcd_bl),
  66. 66      .lcd_rst        (lcd_rst),
  67. 67      .lcd_pclk       (lcd_pclk),
  68. 68      
  69. 69      .pixel_data     (data_in),
  70. 70      .data_req       (data_req),
  71. 71      .out_vsync      (out_vsync),
  72. 72      .h_disp         (h_disp),
  73. 73      .v_disp         (v_disp),
  74. 74      .pixel_xpos     (pixel_xpos),
  75. 75      .pixel_ypos     (pixel_ypos)
  76. 76      );
  77. 77                  
  78. 78  endmodule
复制代码

       在代码的第36行,当lcd_de信号为高电平时,即像素数据有效的时候,输出lcd_rgb_o信号给lcd_rgb。当lcd_de信号为低电平时,给lcd_rgb信号赋值为高阻态。我们就是在当lcd_rgb信号高阻态的时候,读取LCD的ID。读ID模块的代码如下:
  1. 1   module rd_id(
  2. 2       input                   clk    ,    //时钟
  3. 3       input                   rst_n  ,    //复位,低电平有效
  4. 4       input           [15:0]  lcd_rgb,    //RGB LCD像素数据,用于读取ID
  5. 5       output   reg    [15:0]  lcd_id      //LCD屏ID
  6. 6       );
  7. 7   
  8. 8   //reg define
  9. 9   reg            rd_flag;  //读ID标志
  10. 10  //*****************************************************
  11. 11  //**                    main code
  12. 12  //*****************************************************
  13. 13  
  14. 14  //获取LCD ID   M2:B4  M1:G5  M0:R4
  15. 15  always @(posedge clk or negedge rst_n) begin
  16. 16      if(!rst_n) begin
  17. 17          rd_flag <= 1'b0;
  18. 18          lcd_id <= 16'd0;
  19. 19      end   
  20. 20      else begin
  21. 21          if(rd_flag == 1'b0) begin
  22. 22              rd_flag <= 1'b1;
  23. 23              case({lcd_rgb[4],lcd_rgb[10],lcd_rgb[15]})
  24. 24                  3'b000 : lcd_id <= 16'h4342;    //4.3' RGB LCD  RES:480x272
  25. 25                  3'b001 : lcd_id <= 16'h7084;    //7'   RGB LCD  RES:800x480
  26. 26                  3'b010 : lcd_id <= 16'h7016;    //7'   RGB LCD  RES:1024x600
  27. 27                  3'b100 : lcd_id <= 16'h4384;    //4.3' RGB LCD  RES:800x480
  28. 28                  3'b101 : lcd_id <= 16'h1018;    //10'  RGB LCD  RES:1280x800
  29. 29                  default : lcd_id <= 16'd0;
  30. 30              endcase   
  31. 31          end
  32. 32      end   
  33. 33  end
  34. 34  
  35. 35  endmodule
复制代码

       代码的第15行至33行实现了读取LCD ID的操作,在复位信号拉高后读取一次ID。
       在前面,我们提到过不同尺寸的LCD所需的驱动时钟频率是不一样的。比如4.3寸LCD需要12.5MHz的时钟,7寸800*480分辨率(其中ID号为4384的虽然是4.3寸的,但是它的分辨率也是800*480的所以时钟跟7084是一样的)的LCD需要25MHz的时钟,7寸1024*600分辨率的LCD需要50MHz的时钟,10.1寸LCD也需要50MHz的时钟(注意:这里所给出的五款屏幕工作时钟并非屏幕所支持的最大时钟)。为了适配不同尺寸/分辨率的LCD,就需要输出相应的驱动时钟。分频模块的代码如下:
  1. 1   module clk_div(
  2. 2       input               clk,          //50Mhz
  3. 3       input               rst_n,
  4. 4       input       [15:0]  lcd_id,
  5. 5       output  reg         lcd_pclk
  6. 6       );
  7. 7   
  8. 8   reg          clk_25m;
  9. 9   reg          clk_12_5m;
  10. 10  reg          div_4_cnt;
  11. 11  
  12. 12  //时钟2分频 输出25MHz时钟
  13. 13  always @(posedge clk or negedge rst_n) begin
  14. 14      if(!rst_n)
  15. 15          clk_25m <= 1'b0;
  16. 16      else
  17. 17          clk_25m <= ~clk_25m;
  18. 18  end
  19. 19  
  20. 20  //时钟4分频 输出12.5MHz时钟
  21. 21  always @(posedge clk or negedge rst_n) begin
  22. 22      if(!rst_n) begin
  23. 23          div_4_cnt <= 1'b0;
  24. 24          clk_12_5m <= 1'b0;
  25. 25      end   
  26. 26      else begin
  27. 27          div_4_cnt <= div_4_cnt + 1'b1;
  28. 28          if(div_4_cnt == 1'b1)
  29. 29              clk_12_5m <= ~clk_12_5m;
  30. 30      end        
  31. 31  end
  32. 32  
  33. 33  always @(*) begin
  34. 34      case(lcd_id)
  35. 35          16'h4342 : lcd_pclk = clk_12_5m;
  36. 36          16'h7084 : lcd_pclk = clk_25m;      
  37. 37          16'h7016 : lcd_pclk = clk;
  38. 38          16'h4384 : lcd_pclk = clk_25m;
  39. 39          16'h1018 : lcd_pclk = clk;
  40. 40          default :  lcd_pclk = 1'b0;
  41. 41      endcase      
  42. 42  end
  43. 43  
  44. 44  endmodule
复制代码

       我们决定把50MHz的输入时钟分频为12.5MHz、25MHz、50Mhz这三个频率的时钟。7寸1024*600分辨率的LCD和10.1寸的LCD共用50MHz的时钟。
       为了能够驱动不同的LCD,LCD驱动模块也需要进行适当的修改,其代码如下:
  1. 1   module lcd_driver(
  2. 2       input              lcd_clk,      //lcd模块驱动时钟
  3. 3       input              sys_rst_n,    //复位信号
  4. 4       input      [15:0]  lcd_id,       //LCD屏ID
  5. 5       input      [15:0]  pixel_data,   //像素点数据
  6. 6       output             data_req  ,   //请求像素点颜色数据输入
  7. 7       output     [10:0]  pixel_xpos,   //像素点横坐标
  8. 8       output     [10:0]  pixel_ypos,   //像素点纵坐标
  9. 9       output reg [10:0]  h_disp,       //LCD屏水平分辨率
  10. 10      output reg [10:0]  v_disp,       //LCD屏垂直分辨率
  11. 11      output             out_vsync,    //帧复位,高有效   
  12. 12      //RGB LCD接口                          
  13. 13      output             lcd_hs,       //LCD 行同步信号
  14. 14      output             lcd_vs,       //LCD 场同步信号
  15. 15      output reg         lcd_de,       //LCD 数据输入使能
  16. 16      output reg [15:0]  lcd_rgb,      //LCD RGB565颜色数据
  17. 17      output             lcd_bl,       //LCD 背光控制信号
  18. 18      output          lcd_rst,      //LCD 复位信号
  19. 19      output          lcd_pclk      //LCD 采样时钟   
  20. 20      );                             
  21. 21                                                         
  22. 22  //parameter define  
  23. 23  // 4.3' 480*272
  24. 24  parameter  H_SYNC_4342   =  11'd41;     //行同步
  25. 25  parameter  H_BACK_4342   =  11'd2;      //行显示后沿
  26. 26  parameter  H_DISP_4342   =  11'd480;    //行有效数据
  27. 27  parameter  H_FRONT_4342  =  11'd2;      //行显示前沿
  28. 28  parameter  H_TOTAL_4342  =  11'd525;    //行扫描周期
  29. 29  
  30. 30  parameter  V_SYNC_4342   =  11'd10;     //场同步
  31. 31  parameter  V_BACK_4342   =  11'd2;      //场显示后沿
  32. 32  parameter  V_DISP_4342   =  11'd272;    //场有效数据
  33. 33  parameter  V_FRONT_4342  =  11'd2;      //场显示前沿
  34. 34  parameter  V_TOTAL_4342  =  11'd286;    //场扫描周期
  35. 35  
  36. 36  // 7' 800*480   
  37. 37  parameter  H_SYNC_7084   =  11'd128;    //行同步
  38. 38  parameter  H_BACK_7084   =  11'd88;     //行显示后沿
  39. 39  parameter  H_DISP_7084   =  11'd800;    //行有效数据
  40. 40  parameter  H_FRONT_7084  =  11'd40;     //行显示前沿
  41. 41  parameter  H_TOTAL_7084  =  11'd1056;   //行扫描周期
  42. 42  
  43. 43  parameter  V_SYNC_7084   =  11'd2;      //场同步
  44. 44  parameter  V_BACK_7084   =  11'd33;     //场显示后沿
  45. 45  parameter  V_DISP_7084   =  11'd480;    //场有效数据
  46. 46  parameter  V_FRONT_7084  =  11'd10;     //场显示前沿
  47. 47  parameter  V_TOTAL_7084  =  11'd525;    //场扫描周期      
  48. 48  
  49. 49  // 7' 1024*600   
  50. 50  parameter  H_SYNC_7016   =  11'd20;     //行同步
  51. 51  parameter  H_BACK_7016   =  11'd140;    //行显示后沿
  52. 52  parameter  H_DISP_7016   =  11'd1024;   //行有效数据
  53. 53  parameter  H_FRONT_7016  =  11'd160;    //行显示前沿
  54. 54  parameter  H_TOTAL_7016  =  11'd1344;   //行扫描周期
  55. 55  
  56. 56  parameter  V_SYNC_7016   =  11'd3;      //场同步
  57. 57  parameter  V_BACK_7016   =  11'd20;     //场显示后沿
  58. 58  parameter  V_DISP_7016   =  11'd600;    //场有效数据
  59. 59  parameter  V_FRONT_7016  =  11'd12;     //场显示前沿
  60. 60  parameter  V_TOTAL_7016  =  11'd635;    //场扫描周期
  61. 61  
  62. 62  // 10.1' 1280*800   
  63. 63  parameter  H_SYNC_1018   =  11'd10;     //行同步
  64. 64  parameter  H_BACK_1018   =  11'd80;     //行显示后沿
  65. 65  parameter  H_DISP_1018   =  11'd1280;   //行有效数据
  66. 66  parameter  H_FRONT_1018  =  11'd70;     //行显示前沿
  67. 67  parameter  H_TOTAL_1018  =  11'd1440;   //行扫描周期
  68. 68  
  69. 69  parameter  V_SYNC_1018   =  11'd3;      //场同步
  70. 70  parameter  V_BACK_1018   =  11'd10;     //场显示后沿
  71. 71  parameter  V_DISP_1018   =  11'd800;    //场有效数据
  72. 72  parameter  V_FRONT_1018  =  11'd10;     //场显示前沿
  73. 73  parameter  V_TOTAL_1018  =  11'd823;    //场扫描周期
  74. 74  
  75. 75  // 4.3' 800*480   
  76. 76  parameter  H_SYNC_4384   =  11'd128;    //行同步
  77. 77  parameter  H_BACK_4384   =  11'd88;     //行显示后沿
  78. 78  parameter  H_DISP_4384   =  11'd800;    //行有效数据
  79. 79  parameter  H_FRONT_4384  =  11'd40;     //行显示前沿
  80. 80  parameter  H_TOTAL_4384  =  11'd1056;   //行扫描周期
  81. 81  
  82. 82  parameter  V_SYNC_4384   =  11'd2;      //场同步
  83. 83  parameter  V_BACK_4384   =  11'd33;     //场显示后沿
  84. 84  parameter  V_DISP_4384   =  11'd480;    //场有效数据
  85. 85  parameter  V_FRONT_4384  =  11'd10;     //场显示前沿
  86. 86  parameter  V_TOTAL_4384  =  11'd525;    //场扫描周期   
  87. 87  
  88. 88  //reg define
  89. 89  reg  [10:0] h_sync ;
  90. 90  reg  [10:0] h_back ;
  91. 91  reg  [10:0] h_total;
  92. 92  reg  [10:0] v_sync ;
  93. 93  reg  [10:0] v_back ;
  94. 94  reg  [10:0] v_total;
  95. 95  reg  [10:0] h_cnt  ;
  96. 96  reg  [10:0] v_cnt  ;
  97. 97  
  98. 98  //wire define
  99. 99  wire       lcd_en;
  100. 100
  101. 101 //*****************************************************
  102. 102 //**                    main code
  103. 103 //*****************************************************
  104. 104 assign lcd_bl   = 1'b1;           //RGB LCD显示模块背光控制信号
  105. 105 assign lcd_rst  = 1'b1;           //RGB LCD显示模块系统复位信号
  106. 106 assign lcd_pclk = lcd_clk;        //RGB LCD显示模块采样时钟
  107. 107
  108. 108 //RGB LCD 采用数据输入使能信号同步时,行场同步信号需要拉高
  109. 109
  110. 110 assign lcd_hs  = 1'b1;
  111. 111 assign lcd_vs  = 1'b1;
  112. 112
  113. 113 //使能RGB565数据输出
  114. 114 assign  lcd_en = ((h_cnt >= h_sync + h_back) && (h_cnt < h_sync + h_back + h_disp)
  115. 115                 && (v_cnt >= v_sync + v_back) && (v_cnt < v_sync + v_back + v_disp))
  116. 116                 ? 1'b1 : 1'b0;
  117. 117
  118. 118 //帧复位,高有效               
  119. 119 assign out_vsync = ((h_cnt <= 100) && (v_cnt == 1)) ? 1'b1 : 1'b0;
  120. 120                 
  121. 121 //请求像素点颜色数据输入  
  122. 122 assign data_req =((h_cnt>=h_sync + h_back - 1'b1) && (h_cnt < h_sync + h_back + h_disp - 1'b1)
  123. 123                 && (v_cnt >= v_sync + v_back) && (v_cnt < v_sync + v_back + v_disp))
  124. 124                 ? 1'b1 : 1'b0;
  125. 125
  126. 126 //像素点坐标  
  127. 127 assign pixel_xpos = data_req ? (h_cnt - (h_sync + h_back - 1'b1)) : 11'd0;
  128. 128 assign pixel_ypos = data_req ? (v_cnt - (v_sync + v_back - 1'b1)) : 11'd0;
  129. 129
  130. 130
  131. 131 //LCD输入的颜色数据采用数据输入使能信号同步
  132. 132 always@ (posedge lcd_clk or negedge sys_rst_n) begin
  133. 133     if(!sys_rst_n)
  134. 134         lcd_de <= 11'd0;
  135. 135     else begin
  136. 136         lcd_de <= lcd_en;  
  137. 137     end   
  138. 138 end
  139. 139
  140. 140 //RGB565数据输出
  141. 141 always@ (posedge lcd_clk or negedge sys_rst_n) begin
  142. 142     if(!sys_rst_n)
  143. 143         lcd_rgb <= 16'd0;
  144. 144     else begin
  145. 145         if(lcd_en)
  146. 146             lcd_rgb <= pixel_data;  
  147. 147         else
  148. 148             lcd_rgb <= 16'd0;      
  149. 149     end   
  150. 150 end
  151. 151
  152. 152 //行场时序参数
  153. 153 always @(posedge lcd_clk) begin
  154. 154     case(lcd_id)
  155. 155         16'h4342 : begin
  156. 156             h_sync  <= H_SYNC_4342;
  157. 157             h_back  <= H_BACK_4342;
  158. 158             h_disp  <= H_DISP_4342;
  159. 159             h_total <= H_TOTAL_4342;
  160. 160             v_sync  <= V_SYNC_4342;
  161. 161             v_back  <= V_BACK_4342;
  162. 162             v_disp  <= V_DISP_4342;
  163. 163             v_total <= V_TOTAL_4342;            
  164. 164         end
  165. 165         16'h7084 : begin
  166. 166             h_sync  <= H_SYNC_7084;
  167. 167             h_back  <= H_BACK_7084;
  168. 168             h_disp  <= H_DISP_7084;
  169. 169             h_total <= H_TOTAL_7084;
  170. 170             v_sync  <= V_SYNC_7084;
  171. 171             v_back  <= V_BACK_7084;
  172. 172             v_disp  <= V_DISP_7084;
  173. 173             v_total <= V_TOTAL_7084;        
  174. 174         end
  175. 175         16'h7016 : begin
  176. 176             h_sync  <= H_SYNC_7016;
  177. 177             h_back  <= H_BACK_7016;
  178. 178             h_disp  <= H_DISP_7016;
  179. 179             h_total <= H_TOTAL_7016;
  180. 180             v_sync  <= V_SYNC_7016;
  181. 181             v_back  <= V_BACK_7016;
  182. 182             v_disp  <= V_DISP_7016;
  183. 183             v_total <= V_TOTAL_7016;            
  184. 184         end
  185. 185         16'h4384 : begin
  186. 186             h_sync  <= H_SYNC_4384;
  187. 187             h_back  <= H_BACK_4384;
  188. 188             h_disp  <= H_DISP_4384;
  189. 189             h_total <= H_TOTAL_4384;
  190. 190             v_sync  <= V_SYNC_4384;
  191. 191             v_back  <= V_BACK_4384;
  192. 192             v_disp  <= V_DISP_4384;
  193. 193             v_total <= V_TOTAL_4384;            
  194. 194         end        
  195. 195         16'h1018 : begin
  196. 196             h_sync  <= H_SYNC_1018;
  197. 197             h_back  <= H_BACK_1018;
  198. 198             h_disp  <= H_DISP_1018;
  199. 199             h_total <= H_TOTAL_1018;
  200. 200             v_sync  <= V_SYNC_1018;
  201. 201             v_back  <= V_BACK_1018;
  202. 202             v_disp  <= V_DISP_1018;
  203. 203             v_total <= V_TOTAL_1018;        
  204. 204         end
  205. 205         default : begin
  206. 206             h_sync  <= H_SYNC_4342;
  207. 207             h_back  <= H_BACK_4342;
  208. 208             h_disp  <= H_DISP_4342;
  209. 209             h_total <= H_TOTAL_4342;
  210. 210             v_sync  <= V_SYNC_4342;
  211. 211             v_back  <= V_BACK_4342;
  212. 212             v_disp  <= V_DISP_4342;
  213. 213             v_total <= V_TOTAL_4342;         
  214. 214         end
  215. 215     endcase
  216. 216 end
  217. 217
  218. 218 //行计数器对像素时钟计数
  219. 219 always@ (posedge lcd_pclk or negedge sys_rst_n) begin
  220. 220     if(!sys_rst_n)
  221. 221         h_cnt <= 11'd0;
  222. 222     else begin
  223. 223         if(h_cnt == h_total - 1'b1)
  224. 224             h_cnt <= 11'd0;
  225. 225         else
  226. 226             h_cnt <= h_cnt + 1'b1;           
  227. 227     end
  228. 228 end
  229. 229
  230. 230 //场计数器对行计数
  231. 231 always@ (posedge lcd_clk or negedge sys_rst_n) begin
  232. 232     if(!sys_rst_n)
  233. 233         v_cnt <= 11'd0;
  234. 234     else begin
  235. 235         if(h_cnt == h_total - 1'b1) begin
  236. 236             if(v_cnt == v_total - 1'b1)
  237. 237                 v_cnt <= 11'd0;
  238. 238             else
  239. 239                 v_cnt <= v_cnt + 1'b1;   
  240. 240         end
  241. 241     end   
  242. 242 end
  243. 243
  244. 244 endmodule  
复制代码

       在代码的第24至86行,定义了五种RGB LCD屏的时序参数。在代码的第152行至第216行,根据LCD的ID对参数变量进行赋值。到这里程序设计部分就讲解完了,至于SDRAM控制器部分和“ov7725 lcd显示实验”是一样的,这里就不再重复讲解了,大家有不明白的可以去看看前面的例程。
1.5下载验证
       首先将OV5640摄像头插入开发板上的摄像头扩展接口(注意摄像头镜头朝外);将FPC 排线一端与正点原子的RGB接口模块上的J1接口连接,另一端与新起点开发板上的J1接口连接;连接时,先掀开FPC连接器上的黑色翻盖,将FPC排线蓝色面朝上插入连接器,最后将黑色翻盖压下以固定FPC排线,实物连接图如图 41.5.1所示。最后将下载器一端连电脑,另一端与开发板上的JTAG端口连接,连接电源线并打开电源开关。接下来我们下载程序,验证OV5640摄像头RGB TFT-LCD实时显示功能。
下载完成后观察显示器的显示图像如图 41.5.2所示,说明OV5640摄像头LCD显示程序下载验证成功。
第四十一章 OV5640摄像头RGB34231.png

图 41.5.1 实物连接图

第四十一章 OV5640摄像头RGB34291.png

图 41.5.2 RGB TFT-LCD实时显示图像



阿莫论坛20周年了!感谢大家的支持与爱护!!

如果天空是黑暗的,那就摸黑生存;
如果发出声音是危险的,那就保持沉默;
如果自觉无力发光,那就蜷伏于牆角。
但是,不要习惯了黑暗就为黑暗辩护;
也不要为自己的苟且而得意;
不要嘲讽那些比自己更勇敢的人。
我们可以卑微如尘土,但不可扭曲如蛆虫。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-9-27 07:05

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表