资讯详情

【正点原子FPGA连载】第四十三章MT9V034摄像头RGB-LCD显示实验 -摘自【正点原子】新起点之FPGA开发指南_V...

1)实验平台:正点原子新起点V2开发板 2)平台采购地址:https://detail.tmall.com/item.htm?id=609758951113 2)全套实验源码 手册 视频下载地址:http://www.openedv.com/thread-300792-1-1.html 3)正点原子FPGA感兴趣的同学可以加群讨论:99424016 4)关注正点原子微信官方账号,获取最新信息更新 在这里插入图片描述

第四十三章MT9V034摄像头RGB-LCD显示实验

MT9V034是ON Semiconductor(安森美半导体)公司生产的一个CMOS图像传感器,传感器功耗低,可靠性高,采集速度快,主要用于机器视觉、双目视觉、宽温工业场合等领域。我们将在本章中使用它FPGA开发板实现对MT9V034数字图像采集并通过LCD实时显示。 本章包括以下几个部分: 4242.1简介 42.2实验任务 42.3硬件设计 42.4程序设计 42.5下载验证 43.1简介 MT9V034是一种1/3英寸单芯片图像传感器,其最大感光阵列可达752*480,最快60fps VGA图像采集具有全局曝光和高动态范围(HDR)操作。这款CMOS图像传感器具有安森美半导体的突破性功能,实现了CCD低噪声和图像质量CMOS在保持固有尺寸、成本和低光灵敏度的同时,成像技术(基于信噪比和低光灵敏度)CMOS集成优势。下表是几个摄像头的功能对比。

从以上对比可以看出,与其他两个相机相比,MT9V034的优势在于HDR模式和全局曝光。HDR模式的原理是根据不同的曝光时间LDR(Low-Dynamic Range)图像每个曝光时间对应最佳细节的图像LDR图像合成最终HDR与普通图像相比,图像可以提供更多的动态范围和图像细节。下图为线性模式和HDR模式对比图。

图 43.1.1 HDR模式

图 43.1.2 线性模式 通过对比可以发现打开了 HDR,它会使图像亮度高的地方变暗,亮度低的地方变亮。一般来说,它会使图像显示更加平衡。 卷帘曝光的原理是通过Sensor逐行曝光。曝光开始时,Sensor逐行扫描曝光,直到所有像素点都曝光。不同于卷帘曝光。 ,全局曝光整个场景同时曝光,Sensor所有像素点同时收集光和曝光。以下是两种模式的对比图。

图 43.1.3 全局曝光拍摄图

图 43.1.4 卷帘曝光拍摄图 拍摄快速移动动的物体时,整体曝光拍摄的物体相对清晰,不会变形,卷帘曝光拍摄的图片会部分曝光(partial exposure)、斜坡图形(skew)、晃动(wobble) 传说中的果冻等现象。与卷帘曝光相比,这是整体曝光其优势的一面。全局曝光时间长(如大于500μs)当噪声严重时,使用卷帘曝光后,图片噪声更低,帧速更快。 下图为MT9V034功能框图:

图 43.1.5 MT9V034功能框图 从上图可以看出,除了传统的并行逻辑输出,MT9V034还有串行低压差信号(LVDS)输出。传感器可以在立体声相机中操作,当传感器指定为立体声主机时,可以合并自己的立体声,也可以将从属传感器的数据合并为串行LVDS流动。本实验仅采用传统的并行逻辑输出。 MT9V寄存器通过两行串行接口写入MT9V用于配置窗口大小、市场分辨率等寄存器。MT9V034有四种可能性ID(0x90、0x98、0xB0和0xB8)由S_CTRL_ADR0和S_CTRL_ADR1输入引脚确定,本实验使用MT9V034的写器件ID是0x90。下图是器件ID相关内容。

图 43.1.6 器件地址 MT9V034采用两线接口总线,包括SCLK串行时钟输入线和SDATA串行双向数据线相当于IIC协议的SCL信号线和SDA信号线。本实验使用的两线接口总线兼容IIC协议,是所以不对相关协议详细介绍,有关IIC详细介绍协议请参考EEPROM读写实验章节。 如下图所示:

图 43.1.7写传输协议 上图中的ADDR由7位器件地址和1位读写控制位组成 1:读),MT9V034的设备地址为7’h5c,因此,在写传输协议时,ID Address(W) = 8’hb8(设备地址左移1位,低位补0);R0x09是8位寄存器地址MT9V有些寄存器可以在034数据手册中重写,有些只读,只有可重写的寄存器才能正确写入;Write Data为16位编写数据,每个寄存器地址对应16位配置数据。上图第九位ACK表示从机应答,该位置由从机(此处指MT9V034)发出响应信号响应主机是否传输当前设备地址、寄存器地址和编写数据,但从机器可能不会发出响应信号,因此主机(此处指FPGA)在这里,我们必须判断这里是否有响应。有响应意味着当前传输已完成,无响应意味着传输尚未完成。 我们可以发现,MT9V双线接口总线和034IIC编写传输协议非常相似,但在两线接口总线编写传输协议将16位数据写入寄存器地址IIC只有8位数据写入传输协议的地址。读传输协议和两线接口总线IIC有些差异,在IIC在阅读传输协议中,一个寄存器地址只读取8位数据;在两线接口总线传输协议中,一个寄存器地址只读取16位数据,如下图所示。

图 43.1.8 SCCB读传输协议 从上图可以看出,两线接口总线读传输协议分为两部分。第一部分是编写设备地址和寄存器地址,即首先进行虚写操作。通过这种虚写操作,地址指针指向虚写操作中寄存器地址的位置。当然,虚写操作也可以通过上述写作传输协议来完成。第二部分是读取器件地址和数据。此时读取的数据是寄存器地址对应的数据。ID Address(R) = 8’hB9(设备地址左移1位,低位补1位)。上图中的NACK位于主机(这里指FPGA)产生,由于两线式接口总线不支持连续读写,因此NACK位置必须为高电平。 MT9V034上电后有默认寄存器,即上电后可输出752x对于480分辨率图像,如果您需要其他分辨率或模式,您必须首先初始化传感器。您可以在预期的工作模式下配置寄存器,以获得更好的图像质量。因为两线接口总线的编写传输协议和IIC几相同,因此我们可以直接使用IIC的驱动程序来配置摄像头。当然这么多寄存器也并非都需要配置,很多寄存器可以采用默认的值。ON Semiconductor公司提供了MT9V034的软件使用手册(MT9V034,位于开发板所随附的资料“7_硬件资料/7_MT9V034资料/MT9V034.pdf”),如果某些寄存器不知道如何配置可以参考此手册,下表是本程序用到的关键寄存器的配置说明。

0Xd5 Fine Shutter Width Total 0x0000 细调曝光时间的宽度 MT9V034的寄存器较多,对于其它寄存器的描述可以参MT9V034的数据手册。 下图为MT9V034的一些特性。

图 43.1.9 MT9V034的特性 从上图可以看出,MT9V034的输入时钟频率的范围是13Mhz~27Mhz;本次实验摄像头的输入时钟为24Mhz,是由外部晶振提供的;两线式接口总线的SCLK的时钟频率最大为400KHz。

图 43.1.10 PIXCLK和SYSCLK的关系 结合图 43.1.10和图 43.1.9可知,PIXCLK和SYSCLK是同频不同相的2个时钟,本次实验摄像头的输入时钟为24Mhz,所以摄像头的输出时钟也为24Mhz。 MT9V034在并行逻辑输出的模式下仅支持10bit的YUV(亮度参量和色度参量分开表示的像素格式),不支持其他格式。由于摄像头采集的图像最终要在LCD上显示,且新起点开发板上的数据接口为RGB888格式(详情请参考“LCD彩条显示实验”章节),因此必须将MT9V034摄像头输出的YUV格式的图像像素数据转换为RGB888格式。下图为摄像头输出的行时序图。

图 43.1.11 行时序图 LINE_VALID:数据有效使能。当其为高时,输出的数据为有效数据。 PIXCLK:像素时钟。由MT9V034产生的对外输出的时钟信号。 DOUT:有效数据。摄像头采集得到的像素数据,本次实验取其高8位。

图 43.1.12 场时序图

图 43.1.13 信号含义 LINE_VALID:数据有效使能。当其为高时,输出的数据为有效数据。 FRAME_VALID:帧(场) 同步信号。当此信号有效的时候就表示开始显示新的一帧数据。 43.2实验任务 本节实验任务是使用新起点开发板及MT9V034摄像头实现图像采集,并通过TFT-LCD接口驱动RGB LCD液晶屏(支持目前正点原子推出的所有RGB LCD屏),并实时显示出图像。 43.3硬件设计 新起点FPGA开发板上有一个摄像头扩展接口,该接口可以用来连接MT9V034/OV5640等摄像头模块,摄像头扩展接口原理图如图 43.3.1所示:

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

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

图 43.3.3 MT9V034摄像头连接开发板图 前面说过,MT9V034在YUV模式中有效数据是D[9:0],而我们的摄像头排针上数据引脚的个数是8位,而摄像头排针上的8位数据连接的就是MT9V034传感器的D[9:2],所以我们直接使用摄像头排针上的8位数据引脚即可。 需要注意的是,由图 43.3.1可知,摄像头扩展口的第18个引脚定义为CMOS_PWDN,而我们的MT9V034摄像头模块的STB(CMOS_PWDN)引脚固定为低电平,也就是一直处于正常工作模式。MT9V034摄像头接口的第18个引脚定义为EXP,这个引脚是摄像头外部触发脉冲的引脚,只在快照模式下启用它。MT9V034摄像头模块内部自带24M晶振的,所以不需要FPGA输出时钟给摄像头。 由于LCD接口和SDRAM引脚数目较多且在前面相应的章节中已经给出它们的管脚列表,这里只列出摄像头相关管脚分配,如下表所示: 表 43.3.1 MT9V034摄像头管脚分配

摄像头TCL约束文件如下: set_location_assignment PIN_T14 -to cmos_data[7] set_location_assignment PIN_R14 -to cmos_data[6] set_location_assignment PIN_N6 -to cmos_data[5] set_location_assignment PIN_P6 -to cmos_data[4] set_location_assignment PIN_M8 -to cmos_data[3] set_location_assignment PIN_N8 -to cmos_data[2] set_location_assignment PIN_P8 -to cmos_data[1] set_location_assignment PIN_K9 -to cmos_data[0] set_location_assignment PIN_M9 -to cmos_href set_location_assignment PIN_R13 -to cmos_pclk set_location_assignment PIN_R12 -to cmos_pwdn set_location_assignment PIN_L9 -to cmos_reset set_location_assignment PIN_N9 -to cmos_scl set_location_assignment PIN_L10 -to cmos_sda set_location_assignment PIN_P9 -to cmos_vsync 43.4程序设计 图 43.4.1是根据本章实验任务画出的系统框图。

图 43.4.1 顶层系统框图 由上图可知,时钟模块(pll_clk)为LCD顶层模块、SDRAM控制模块以及I2C驱动模块提供驱动时钟。I2C配置模块和I2C驱动模块控制着传感器初始化的开始与结束,传感器初始化完成后图像采集模块将采集到的数据写入SDRAM控制模块,LCD顶层模块从SDRAM控制模块中读出数据,完成了数据的采集、缓存与显示。需要注意的是图像数据采集模块是在SDRAM和传感器都初始化完成之后才开始输出数据的,避免了在SDRAM初始化过程中向里面写入数据。 MT9V034虽然在上电后不配置寄存器也能正常工作,但是此时输出的分辨率可能不是实验需要的分辨率,所以必须通过配置寄存器的值来达到实验所需要的分辨率。配置寄存器的协议和I2C协议在写操作时几乎一样,所以需要一个I2C驱动模块。为了使MT9V034在期望的模式下运行并且提高图像显示效果,需要配置较多的寄存器,这么多寄存器的地址与参数需要单独放在一个模块,因此还需要一个寄存配置信息的I2C配置模块。在摄像头配置完成后,开始输出图像数据,因此需要一个摄像头图像采集模块来采集图像;采集到的图像先进入SDRAM存储器进行缓存,最后LCD顶层模块读取SDRAM缓存的数据以达到最终实时显示的效果。 对比“OV7725摄像头TFT-LCD显示实验”的系统框图可以发现,本次实验只是把外设OV7725模块替换成了MT9V034模块,替换了图像采集模块和IIC配置模块,修改了IIC驱动模块和SDRAM读写模块,其余模块基本相同。替换图像采集模块和修改图像采集顶层模块的原因在于OV7725摄像头输出的是RGB565格式的16bit数据,而MT9V034输出的是YUV格式的8bit数据;替换IIC配置模块和修改IIC驱动模块的原因在于OV7725的一个寄存器地址只写8bit数据,而MT9V034的一个寄存器地址可以写16bit数据;本次实验所采用的摄像头 MT9V034的帧率为62帧,而LCD的屏幕的帧率有的比摄像头低,有的比摄线头高,而之前所采用的摄像头OV5640和OV7725的帧率都比LCD屏的帧率低,因此两帧的乒乓操作足以满足之前的设计需求,但相对于本次实验来说两帧的乒乓操作已经不能满足设计需求,所以需要修改SDRAM读写模块。SDRAM读写模块修改后的帧切换原理如下所示:

图 43.4.2 写比读快的示意图 图 43.4.3 读比写快的示意图 在图 43.4.2中的图2是写操作完成了一帧的存储,换了一个存储空间继续写,而读操作还没有读完一帧数据,继续读原来的存储空间;因为读帧率和写帧率的帧率比没有2倍,所以写操作端的第二帧还没有写完,读操作端已经读完了第一帧,换了一个存储空间继续读,如图3所示; 图4中写操作端完成了第二帧的存储,而读操作还没有读完第二帧数据;同理图5中写操作端完成了第三帧的存储,开始第四帧的写入,而读操作将要读完第二帧数据;图6表示读操作读完第二帧数据,而写操作端没有完成第四帧的存储,这里将存储空间跳转了2个,就是为了防止写操作追上读操作,出现画面撕裂的现象。 在图 43.4.3中图2是读操作读出了一帧的数据,而本次实验是根据写存储空间来判断读存储空间的,所以继续读之前的存储空间;图3是写操作端完成了第一帧的存储,而读操作还没有读完第二帧数据;图4是读操作端读完第二帧数据,而写操作还没有完成了第二帧的存储。 顶层模块的原理图如下图所示:

图 43.4.4 顶层模块原理图 FPGA顶层模块(mt9v034_rgb565_lcd)例化了以下六个模块:时钟模块(pll_clk)、I2C驱动模块(i2c_dri)、I2C配置模块(i2c_cfg)、图像采集顶层模块(cmos_data_top)、SDRAM控制模块(sdram_top)和LCD顶层模块(lcd_rgb_top)。 时钟模块(pll_clk):时钟模块通过调用PLL IP核实现,共输出3个时钟,频率分别为100Mhz(SDRAM参考时钟)、100Mhz偏移负75度时钟(用于SDRAM输出采样的偏移时钟)和50Mhz时钟,50Mhz时钟作为I2C驱动模块和LCD顶层模块的驱动时钟。 I2C驱动模块(i2c_dri):I2C驱动模块负责驱动MT9V034的两线式接口总线,用户可根据该模块提供的用户接口可以很方便的对MT9V034的寄存器进行配置,该模块和“EEPROM读写实验”章节中用到的I2C驱动模块为同一个模块,有关该模块的详细介绍请大家参考“EEPROM读写实验”章节。 I2C配置模块(i2c_cfg):I2C配置模块的驱动时钟是由I2C驱动模块输出的时钟提供的,这样方便了I2C驱动模块和I2C配置模块之间的数据交互。该模块寄存需要配置的寄存器地址和数据,同时该模块输出MT9V034的寄存器地址和数据以及控制I2C驱动模块开始执行的控制信号,直接连接到I2C驱动模块的用户接口,从而完成对MT9V034传感器的配置。 图像采集顶层模块(top_cmos_data):摄像头采集模块在像素时钟的驱动下将传感器输出的场同步信号、行同步信号以及8位数据转换成SDRAM控制模块的写使能信号和16位写数据信号,完成对MT9V034传感器图像的采集。如果LCD屏的分辨率小于MT9V034的分辨率,还要对MT9V034采集的数据进行裁剪,以匹配LCD屏的分辨率。 SDRAM控制模块(sdram_top):SDRAM读写控制器模块负责驱动SDRAM片外存储器,缓存图像传感器输出的图像数据。该模块将复杂的读写操作封装成类似FIFO的用户接口,非常方便用户的使用。有关SDRAM控制模块的详细介绍请大家参考“SDRAM读写实验”章节。 LCD顶层模块(lcd_rgb_top):LCD顶层模块负责驱动LCD屏的驱动信号的输出,同时为其他模块提供屏体参数、场同步信号和数据请求信号。有关LCD驱动模块的详细介绍请大家参考“OV7725摄像头RGB-LCD显示实验”章节。 顶层模块大部分的代码在介绍“OV7725摄像头RGB-LCD显示实验”章节时已经介绍过了,这里不再详述,但还有部分代码做了改动,改动的代码如下:

41  //parameter define 
42  parameter  SLAVE_ADD = 7'b1001_000     ;  //slave address 
43  parameter  BIT_CTRL   = 1'b0           ;  //MT9V034的字节地址为8位 0:8位 1:16位
44  parameter  DATA_CTRL  = 1'b1           ;  //MT9V034的数据为16位 0:8位 1:16位
45  parameter  CLK_FREQ   = 26'd50_000_000 ;  //i2c_dri模块的驱动时钟频率 50.0MHz
46  parameter  I2C_FREQ   = 18'd250_000    ;  //I2C的SCL时钟频率,不超过400KHz

程序的第42行,修改了器件的地址。 程序的第44行,添加了参数DATA_CTRL,用以区分一个寄存器地址是写16位数据还是8位数据。

135 //图像采集顶层模块
136 cmos_data_top u_cmos_data_top(
137     .rst_n                 (sys_init_done),         //系统初始化完成之后再开始采集数据 
138     .clk_cmos              (clk_24m),               //24MHz CMOS Driver clock input 
139     .cam_pclk              (cmos_pclk),             
140     .cmos_xclk             (cmos_xclk),             //24MHz drive clock 
141     .cam_vsync             (cmos_vsync),
142     .cam_href              (cmos_href),
143     .cam_data              (cmos_data),
144     .lcd_id                (lcd_id),  
145     .h_disp                (h_disp),
146     .v_disp                (v_disp),  
147     .h_pixel               (h_pixel),
148     .v_pixel               (v_pixel),
149     .sdram_addr_max        (sdram_addr_max),    
150     .cmos_frame_vsync      (cmos_frame_vsync),
151     .cmos_frame_href       (cmos_frame_href),
152     .cmos_frame_valid      (cmos_frame_valid),      //数据有效使能信号
153     .cmos_frame_data       (wr_data)                //有效数据 
154     );

在程序的第139行,信号cmos_pclk是摄像头产生的输入时钟,即摄像头数据的采样时钟。 在程序的第140行,信号cmos_xclk是摄像头的输入时钟,但本次实验的摄像头采用的是外接24M时钟的晶振,所以不需要cmos_xclk,但这里还是将这个信号保留下来。 I2C配置模块寄存需要配置的寄存器地址、数据以及控制初始化的开始与结束,代码如下所示:

1  module i2c_cfg(
2                 input                clk         ,
3                 input                rst_n       ,
4                 input                i2c_done    ,
5                 output  reg          i2c_exec    ,
6                 output  reg   [7:0]  i2c_addr    ,
7                 output  reg  [15:0]  i2c_wr_data , 
8                 output  reg          cfg_done       //配置寄存器结束
9                 );
10 //parameter define 
11 parameter  DELAY_MAX = 8'hff ;
12 parameter  ROW_NUM = 16'd480;  //行数
13 parameter  COL_NUM = 16'd640;  //列数
14 
15 //reg define 
16 reg   [7:0]  delay_cnt   ;
17 reg          delay_done  ;
18 reg   [3:0]  cfg_cnt     ;
19 
20 //*****************************************************
21 //** main code
22 //***************************************************** 
23 
24 always @(posedge clk or negedge rst_n)
25   begin
26      if(rst_n==1'b0) begin
27          delay_cnt <= 1'b0 ;
28          delay_done <= 1'b0 ;
29      end
30      else begin
31          delay_done <= 1'b0 ;
32          if(i2c_done) begin
33              delay_cnt <= 1'b0 ;
34          end 
35          else if(delay_cnt<DELAY_MAX) begin
36              delay_cnt <= delay_cnt +1'b1 ;
37              if(delay_cnt==DELAY_MAX-1'b1) begin
38                  delay_done <= 1'b1 ;
39              end 
40          end
41      end
42   end            
43 
44 always @(posedge clk or negedge rst_n)
45   begin
46      if(rst_n==1'b0) begin
47          i2c_exec <= 1'b0;
48          i2c_addr <= 1'b0;
49          i2c_wr_data <= 1'b0;
50          cfg_cnt <= 1'b0;
51      end
52      else begin
53          i2c_exec <= 1'b0;
54          if(cfg_done==1'b0) begin
55              if(delay_done) begin
56                  cfg_cnt <= cfg_cnt + 1'b1;
57                  case(cfg_cnt)
58                      4'd0 : begin
59                                 i2c_exec <= 1'b1;
60                                 i2c_addr <= 8'h03;//03
61                                 i2c_wr_data <= ROW_NUM;
62                               end
63                      4'd1 : begin
64                                 i2c_exec <= 1'b1;
65                                 i2c_addr <= 8'h04;
66                                 i2c_wr_data <= COL_NUM;
67                               end                                                                                                                     
68                      default : ;
69                  endcase          
70              end 
71          end 
72      end
73   end
74   
75 always @(posedge clk or negedge rst_n)begin
76      if(rst_n==1'b0) 
77          cfg_done <= 1'b0 ;
78      else if(cfg_cnt=='d2 && i2c_done)
79          cfg_done <= 1'b1 ;
80      else
81          cfg_done <= cfg_done ;          
82 end                                                        
83                                       
84 endmodule

在程序的第11行,定义了一个DELAY_MAX参数,用以保证在上电的时候不会立即配置寄存器,而是等待一段时间后再配置。 在程序的第12和13行定义了2个参数,即本次实验所需要的摄像头的分辨率。 在程序的第24至第42行,是用来对延时的计数器进行计数和清零。 在程序的第44行和73行,是对摄像头的行场分辨率进行配置。在第58行是设置需要配置寄存器的个数。 在程序的第75行和82行,是产生寄存器配置结束信号。 I2C驱动模块做了以下修改:

116         st_addr8: begin                         //8位字地址
117             if(st_done) begin
118                 if(wr_flag==1'b0)               //读写判断
119                     if(!data_ctrl)
120                          next_state = st_data_wr_8;
121                     else 
122                          next_state = st_data_wr_16;                         
123                 else
124                     next_state = st_addr_rd;
125             end
126             else begin
127                 next_state = st_addr8;
128             end
129         end
130         st_data_wr_16: begin                       //写数据(8 bit)
131             if(st_done)
132                 next_state = st_data_wr_8;
133             else
134                 next_state = st_data_wr_16;
135         end          
136         st_data_wr_8: begin                       //写数据(8 bit)
137             if(st_done)
138                 next_state = st_stop;                 
139             else
140                 next_state = st_data_wr_8;
141         end  

代码116行至129行表示当状态发生跳转并且data_ctrl为1的时候,将状态跳转到st_data_wr_16,进行16位数据的读写,否则跳转到其他状态。 代码130行至135行表示当st_data_wr_16状态完成时,将状态跳转到st_data_wr_8,因为我们的16位数据读写其实是分两部分完成的st_data_wr_16只进行了高8位的读写,剩下低8位的数据还是在st_data_wr_8状态完成的。

337             st_data_wr_16: begin                      //写高数据(8 bit)
338                 case(cnt)                            
339                     7'd0: begin                      
340                         sda_out <= data_wr_t[15];     //I2C写高8位数据
341                         sda_dir <= 1'b1;             
342                     end                              
343                     7'd1 : scl <= 1'b1;              
344                     7'd3 : scl <= 1'b0;              
345                     7'd4 : sda_out <= data_wr_t[14];  
346                     7'd5 : scl <= 1'b1;              
347                     7'd7 : scl <= 1'b0;              
348                     7'd8 : sda_out <= data_wr_t[13];  
349                     7'd9 : scl <= 1'b1;              
350                     7'd11: scl <= 1'b0;              
351                     7'd12: sda_out <= data_wr_t[12];  
352                     7'd13: scl <= 1'b1;              
353                     7'd15: scl <= 1'b0;              
354                     7'd16: sda_out <= data_wr_t[11];  
355                     7'd17: scl <= 1'b1;              
356                     7'd19: scl <= 1'b0;              
357                     7'd20: sda_out <= data_wr_t[10];  
358                     7'd21: scl <= 1'b1;              
359                     7'd23: scl <= 1'b0;              
360                     7'd24: sda_out <= data_wr_t[9];  
361                     7'd25: scl <= 1'b1;              
362                     7'd27: scl <= 1'b0;              
363                     7'd28: sda_out <= data_wr_t[8];  
364                     7'd29: scl <= 1'b1;              
365                     7'd31: scl <= 1'b0;              
366                     7'd32: begin                     
367                         sda_dir <= 1'b0;           
368                         sda_out <= 1'b1;                              
369                     end                              
370                     7'd33: scl <= 1'b1;              
371                     7'd34: begin                     //从机应答
372                         st_done <= 1'b1;     
373                         if(sda_in == 1'b1)           //高电平表示未应答
374                             i2c_ack <= 1'b1;         //拉高应答标志位 
375                     end          
376                     7'd35: begin                     
377                         scl  <= 1'b0;                
378                         cnt  <= 1'b0;                
379                     end                              
380                     default  :  ;                    
381                 endcase                              
382             end                                                  
383             st_data_wr_8: begin                      //写数据(8 bit)
384                 case(cnt)                            
385                     7'd0: begin                      
386                         sda_out <= data_wr_t[7];     //I2C写低8位数据
387                         sda_dir <= 1'b1;             
388                     end                              
389                     7'd1 : scl <= 1'b1;              
390                     7'd3 : scl <= 1'b0;              
391                     7'd4 : sda_out <= data_wr_t[6];  
392                     7'd5 : scl <= 1'b1;              
393                     7'd7 : scl <= 1'b0;              
394                     7'd8 : sda_out <= data_wr_t[5];  
395                     7'd9 : scl <= 1'b1;              
396                     7'd11: scl <= 1'b0;              
397                     7'd12: sda_out <= data_wr_t[4];  
398                     7'd13: scl <= 1'b1;              
399                     7'd15: scl <= 1'b0;              
400                     7'd16: sda_out <= data_wr_t[3];  
401                     7'd17: scl <= 1'b1;              
402                     7'd19: scl <= 1'b0;              
403                     7'd20: sda_out <= data_wr_t[2];  
404                     7'd21: scl <= 1'b1;              
405                     7'd23: scl <= 1'b0;              
406                     7'd24: sda_out <= data_wr_t[1];  
407                     7'd25: scl <= 1'b1;              
408                     7'd27: scl <= 1'b0;              
409                     7'd28: sda_out <= data_wr_t[0];  
410                     7'd29: scl <= 1'b1;              
411                     7'd31: scl <= 1'b0;              
412                     7'd32: begin                     
413                         sda_dir <= 1'b0;           
414                         sda_out <= 1'b1;                              
415                     end                              
416                     7'd33: scl <= 1'b1;              
417                     7'd34: begin                     //从机应答
418                         st_done <= 1'b1;     
419                         if(sda_in == 1'b1)           //高电平表示未应答
420                             i2c_ack <= 1'b1;         //拉高应答标志位 
421                     end          
422                     7'd35: begin                     
423                         scl  <= 1'b0;                
424                         cnt  <= 1'b0;                
425                     end                              
426                     default  :  ;                    
427                 endcase                              
428             end 

代码337行至382行,表示写入数据的高8位。 代码383行至428行,表示写入数据的低8位。 图像采集顶层模块的原理图如下图所示:

图 43.4.5 图像采集顶层模块原理图(局部) 图像采集顶层模块(top_cmos_data)例化了以下二个模块:图像采集模块(cmos_capture_raw_gray)、图像裁剪模块(cmos_tailor)。有关图像采集顶层模块的详细介绍请大家参考“OV7725摄像头TFT-LCD显示实验”章节。 由上图可知,图像采集模块(cmos_capture_raw_gray)为其他模块提供摄像头8bit输入数据和数据使能以及摄像头稳定后的行场信号。图像裁剪模块(cmos_tailor)只有在LCD的器件ID为16’h4342时起作用,即摄像头的分辨率大于LCD屏的分辨率,起到裁剪图像数据,使图像的有效数据达到匹配LCD屏的尺寸。有关图像裁剪模块的详细介绍请大家参考“OV7725摄像头TFT-LCD显示实验”章节。 图像采集模块的代码如下:

1   module cmos_capture_raw_gray
2   #(
3       parameter   CMOS_FRAME_WAITCNT  =   4'd10  //等待数据稳定所需要的帧数
4                                                               
5   )
6   (
7       //global clock
8       input       clk_cmos,                      //相环分频时钟
9       input       rst_n,                         
        标签: 21pin翻盖连接器fpc补强连接器mt系列传感器mt1260

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台