本帖最后由 正点原子运营 于 2023-12-23 15:43 编辑
第四十四章 MT9V034摄像头HDMI显示实验
1)实验平台:正点原子 ATK-DFPGL22G开发板
2) 章节摘自【正点原子】ATK-DFPGL22G之FPGA开发指南_V1.0
6)FPGA技术交流QQ群:435699340
在MT9V034摄像头LCD显示实验中,成功的在LCD屏上实时显示出了摄像头采集的图像。本章将使用ATK-DFPGL22G开发板实现对MT9V034的数字图像采集并在HDMI显示器上实时显示。 本章包括以下几个部分: 1.1 简介 1.2 实验任务 1.3 硬件设计 1.4 软件设计 1.5 下载验证
1.1 简介在“MT9V034摄像头RGB-LCD显示实验”中对MT9V034的视频传输时序、两线式接口总线协议以及寄存器的配置信息等内容作了详细的介绍,如果大家对这部分内容不是很熟悉的话,请参考“MT9V034摄像头RGB-LCD显示实验”中的简介部分。
1.2 实验任务本节实验任务是使用ATK-DFPGL22G开发板及MT9V034摄像头实现图像采集,通过HDMI接口驱动HDMI显示器,并实时显示出图像。
1.3 硬件设计摄像头扩展接口原理图及MT9V034模块说明与“MT9V034摄像头RGB-LCD显示实验”完全相同,请参考“MT9V034摄像头RGB-LCD显示实验”硬件设计部分。HDMI接口部分的硬件设计请参考“HDMI彩条显示实验”中的硬件设计部分。 由于MT9V034、HDMI接口和DDR3引脚数目较多且在前面相应的章节中已经给出它们的管脚列表,这里不再列出管脚分配。
1.4 软件设计图 44.4.1是根据本章实验任务画出的系统框图。对比“MT9V034摄像头RGB-LCD显示实验”的系统框图可以发现,本次实验只是把LCD顶层模块替换成了HDMI顶层模块,并将图像采集模块中的图片裁剪模块去掉了,其余模块(除时钟模块外)完全相同。之所以本节实验将图片裁剪模块去掉是因为本次实验所用HDMI显示器的分辨率是大于摄像头分辨率的,所以只需要在HDMI驱动模块中稍微改下数据请求即可,改动部分和OV7725摄像头HDMI显示实验一模一样,这里就不再详细讲解了。时钟模块用于为I2C驱动模块、HDMI顶层模块以及DDR3控制模块提供驱动时钟;I2C驱动模块和I2C配置模块用于初始化MT9V034图像传感器;摄像头采集模块负责采集摄像头图像数据,并且把图像数据写入DDR3控制模块中;DDR3控制模块负责将用户数据写入和读出片外DDR3存储器;HDMI顶层模块负责驱动HDMI显示器。本章使用的HDMI显示器其分辨率为1280*720,而MT9V034传感器的本次实验所配置的分辨率为640*480,所以HDMI显示器需要填充黑色的像素点。 由上图可知,时钟模块为HDMI顶层模块、DDR3控制模块以及I2C驱动模块提供驱动时钟。I2C配置模块和I2C驱动模块控制着传感器初始化的开始与结束,传感器初始化完成后图像采集模块将采集到的数据写入DDR3控制模块,HDMI顶层模块从DDR3控制模块中读出数据并驱动显示器显示,这时整个系统才完成了数据的采集、缓存与显示。需要注意的是图像数据采集模块是在DDR3和传感器都初始化完成之后才开始输出数据的,避免了在DDR3初始化过程中向里面写入数据。 顶层代码如下所示: - 1 module mt9v034_hdmi(
- 2 input sys_clk ,
- 3 input sys_rst_n ,
- 4
- 5 output tmds_clk_p , // TMDS 时钟通道
- 6 output tmds_clk_n ,
- 7 output [2:0 tmds_data_p , // TMDS 数据通道
- 8 output [2:0 tmds_data_n ,
- 9 //摄像头接口
- 10 input cam_pclk , //cmos 数据像素时钟
- 11 input cam_vsync , //cmos 场同步信号
- 12 input cam_href , //cmos 行同步信号
- 13 input [7:0 cam_data , //cmos 数据
- 14 output cam_rst_n , //cmos 复位信号,低电平有效
- 15 output cam_stb , //cmos pwer down
- 16 output cam_scl , //cmos SCCB_SCL线
- 17 inout cam_sda , //cmos SCCB_SDA线
- 18 //DDR3接口
- 19 input pad_loop_in , //低位温度补偿输入
- 20 input pad_loop_in_h , //高位温度补偿输入
- 21 output pad_rstn_ch0 , //Memory复位
- 22 output pad_ddr_clk_w , //Memory差分时钟正
- 23 output pad_ddr_clkn_w , //Memory差分时钟负
- 24 output pad_csn_ch0 , //Memory片选
- 25 output [15:0 pad_addr_ch0 , //Memory地址总线
- 26 inout [16-1:0 pad_dq_ch0 , //数据总线
- 27 inout [16/8-1:0 pad_dqs_ch0 , //数据时钟正端
- 28 inout [16/8-1:0 pad_dqsn_ch0 , //数据时钟负端
- 29 output [16/8-1:0 pad_dm_rdqs_ch0 , //数据Mask
- 30 output pad_cke_ch0 , //Memory差分时钟使
- 31 output pad_odt_ch0 , //On Die Terminati
- 32 output pad_rasn_ch0 , //行地址strobe
- 33 output pad_casn_ch0 , //列地址strobe
- 34 output pad_wen_ch0 , //写使能
- 35 output [2:0 pad_ba_ch0 , //Bank地址总线
- 36 output pad_loop_out , //低位温度补偿输出
- 37 output pad_loop_out_h //高位温度补偿输出
- 38 );
- 39
- 40 //parameter define
- 41 parameter SLAVE_ADDR = 7'b1001_000 ;//mt9v034的器件地址7'h90
- 42 parameter BIT_CTRL =1'b0 ; //mt9v034的字节地址为8位 0:8位 1:16位
- 43 parameter DATA_CTRL = 1'b1 ; //mt9v034的数据为8位 0:8位 1:16位
- 44 parameter CLK_FREQ =27'd50_000_000; //i2c_dri模块的驱动时钟频率
- 45 parameter I2C_FREQ =18'd250_000 ;//I2C的SCL时钟频率,不超过400KHz
- 46 parameter APP_ADDR_MIN = 28'd0 ; //ddr3读写起始地址,以一个16bit的数据为一个单位
- 47 parameter APP_ADDR_MAX = 28'd307200 ; //ddr3读写结束地址,以一个16bit的数据为一个单位
- 48 parameter BURST_LENGTH = 8'd80 ; //ddr3读写突发长度,80个128bit的数据
- 49
- 50 //wire define
- 51 //PLL
- 52 wire pixel_clk ; //像素时钟75M
- 53 wire pixel_clk_5x ; //5倍像素时钟375M
- 54 wire clk_50m ; //output 50M
- 55 wire clk_locked ;
- 56 //MT9V034
- 57 wire i2c_dri_clk ; //I2C操作时钟
- 58 wire i2c_done ; //I2C寄存器配置完成信号
- 59 wire i2c_exec ; //I2C触发执行信号
- 60 wire [7:0 i2c_addr ; //I2C要配置的地址
- 61 wire [15:0 i2c_wr_data ; //I2C要配置的数据
- 62 wire cam_init_done ; //摄像头初始化完成
- 63
- 64 wire cmos_frame_vsync; //帧有效信号
- 65 wire cmos_frame_href ; //行有效信号
- 66 wire cmos_frame_valid; //数据有效使能信号
- 67 wire [15:0 wr_data ; //OV7725写入DDR3控制器模块的数据
- 68 //HDMI
- 69 wire video_vs ; //场同步信号
- 70 wire [15:0 rd_data ; //DDR3控制器模块读数据给HDMI
- 71 wire rdata_req ; //DDR3控制器模块读使能
- 72 //DDR3
- 73 wire fram_done ; //DDR中已经存入一帧画面标志
- 74 wire ddr_init_done ;//ddr3初始化完成
- 75
- 76 //*****************************************************
- 77 //** main code
- 78 //*****************************************************
- 79 assign cam_stb = 1'b0;
- 80 assign cam_rst_n = 1'b1;
- 81
- 82 //例化PLL IP核
- 83 pll_clk u_pll_clk(
- 84 .pll_rst (~sys_rst_n ),
- 85 .clkin1 (sys_clk ),
- 86 .clkout0 (pixel_clk ), //像素时钟75M
- 87 .clkout1 (pixel_clk_5x), //5倍像素时钟375M
- 88 .clkout2 (clk_50m ), //output50M
- 89 .pll_lock (clk_locked )
- 90 );
- 91
- 92 //I2C驱配置模块
- 93 i2c_cfg u_i2c_cfg(
- 94 .clk (i2c_dri_clk ),
- 95 .rst_n (sys_rst_n ),
- 96 .i2c_done (i2c_done ),
- 97 .i2c_exec (i2c_exec ),
- 98 .i2c_addr (i2c_addr ),
- 99 .i2c_wr_data (i2c_wr_data ),
- 100 .cfg_done (cam_init_done)
- 101 );
- 102
- 103 //I2C驱动模块
- 104 i2c_dri
- 105 #(
- 106 .SLAVE_ADDR (SLAVE_ADDR), //参数传递
- 107 .CLK_FREQ (CLK_FREQ ),
- 108 .I2C_FREQ (I2C_FREQ )
- 109 )
- 110 u_i2c_dr(
- 111 .clk (clk_50m ),
- 112 .rst_n (sys_rst_n ),
- 113 .i2c_exec (i2c_exec ),
- 114 .bit_ctrl (BIT_CTRL ),
- 115 .data_ctrl (DATA_CTRL ),
- 116 .i2c_rh_wl (0 ), //固定为0,只用到了IIC驱动的写操作
- 117 .i2c_addr ({8'b0,i2c_addr}),
- 118 .i2c_data_w (i2c_wr_data ),
- 119 .i2c_data_r ( ),
- 120 .i2c_done (i2c_done ),
- 121 .scl (cam_scl ),
- 122 .sda (cam_sda ),
- 123 .dri_clk (i2c_dri_clk ) //I2C操作时钟
- 124 );
- 125
- 126 //图像采集模块
- 127 cmos_capture_raw_gray
- 128 #(
- 129 .CMOS_FRAME_WAITCNT (4'd10) //Wait n fps for steady(OmniVision need 10Frame)
- 130 )
- 131 u_cmos_capture_raw_gray
- 132 (
- 133 //global clock
- 134 .clk_cmos (1'b0 ), //24MHzCMOS Driver clock input
- 135 .rst_n (sys_rst_n & ddr_init_done), //global reset
- 136 //CMOS Sensor Interface
- 137 .cmos_pclk (cam_pclk ), //24MHz CMOS Pixelclock input
- 138 .cmos_xclk ( ), //24MHzdrive clock
- 139 .cmos_data (cam_data ), //8 bits cmos datainput
- 140 .cmos_vsync (cam_vsync ), //L: vaild, H: invalid
- 141 .cmos_href (cam_href ), //H:vaild, L: invalid
- 142 //CMOS SYNC Data output
- 143 .cmos_frame_vsync (cmos_frame_vsync ), //cmos frame datavsync valid signal
- 144 .cmos_frame_href (cmos_frame_href ), //cmos frame data hrefvaild signal
- 145 .wr_data (wr_data ), //cmos frame grayoutput
- 146 .cmos_frame_clken (cmos_frame_valid ), //cmos frame dataoutput/capture enable clock
- 147 //user interface
- 148 .cmos_fps_rate ( ) //cmos image output rate
- 149 );
- 150
- 151 //ddr3
- 152 ddr3_top u_ddr3_top(
- 153 .refclk_in (clk_50m ),
- 154 .rst_n (sys_rst_n ),
- 155 .app_addr_rd_min (APP_ADDR_MIN ),
- 156 .app_addr_rd_max (APP_ADDR_MAX ),
- 157 .rd_bust_len (BURST_LENGTH ),
- 158 .app_addr_wr_min (APP_ADDR_MIN ),
- 159 .app_addr_wr_max (APP_ADDR_MAX ),
- 160 .wr_bust_len (BURST_LENGTH ),
- 161 .ddr3_read_valid (1'b1 ),
- 162 .ddr3_pingpang_en (1'b1 ),
- 163 .wr_clk (cam_pclk ),
- 164 .rd_clk (pixel_clk ),
- 165 .datain_valid (cmos_frame_valid),
- 166 .datain (wr_data ),
- 167 .rdata_req (rdata_req ),
- 168 .rd_load (video_vs ),
- 169 .wr_load (cmos_frame_vsync),
- 170 .fram_done (fram_done ),
- 171 .dataout (rd_data ),
- 172 .pll_lock (pll_lock ),
- 173 .ddr_init_done (ddr_init_done ),
- 174 .ddrphy_rst_done ( ),
- 175 .pad_loop_in (pad_loop_in ),
- 176 .pad_loop_in_h (pad_loop_in_h ),
- 177 .pad_rstn_ch0 (pad_rstn_ch0 ),
- 178 .pad_ddr_clk_w (pad_ddr_clk_w ),
- 179 .pad_ddr_clkn_w (pad_ddr_clkn_w ),
- 180 .pad_csn_ch0 (pad_csn_ch0 ),
- 181 .pad_addr_ch0 (pad_addr_ch0 ),
- 182 .pad_dq_ch0 (pad_dq_ch0 ),
- 183 .pad_dqs_ch0 (pad_dqs_ch0 ),
- 184 .pad_dqsn_ch0 (pad_dqsn_ch0 ),
- 185 .pad_dm_rdqs_ch0 (pad_dm_rdqs_ch0 ),
- 186 .pad_cke_ch0 (pad_cke_ch0 ),
- 187 .pad_odt_ch0 (pad_odt_ch0 ),
- 188 .pad_rasn_ch0 (pad_rasn_ch0 ),
- 189 .pad_casn_ch0 (pad_casn_ch0 ),
- 190 .pad_wen_ch0 (pad_wen_ch0 ),
- 191 .pad_ba_ch0 (pad_ba_ch0 ),
- 192 .pad_loop_out (pad_loop_out ),
- 193 .pad_loop_out_h (pad_loop_out_h )
- 194
- 195 );
- 196
- 197 //HDMI顶层模块
- 198 hdmi_top u_hdmi_top(
- 199 .hdmi_clk (pixel_clk ),
- 200 .hdmi_clk_5 (pixel_clk_5x ),
- 201 .sys_rst_n (sys_rst_n ),
- 202 .fram_done (fram_done ),
- 203 .clk_locked (clk_locked ),
- 204 .rd_data (rd_data ),
- 205 .rd_en (rdata_req ),
- 206 .video_vs (video_vs ),
- 207 .h_disp ( ),
- 208 .v_disp ( ),
- 209 .pixel_xpos ( ),
- 210 .pixel_ypos ( ),
- 211 .tmds_clk_p (tmds_clk_p ),
- 212 .tmds_clk_n (tmds_clk_n ),
- 213 .tmds_data_p (tmds_data_p ),
- 214 .tmds_data_n (tmds_data_n )
- 215 );
- 216
- 217 endmodule
复制代码FPGA顶层模块(mt9v034_hdmi)例化了以下6个模块:时钟模块(pll_clk)、I2C驱动模块(i2c_dri)、I2C配置模块(i2c_cfg)、图像采集模块(cmos_capture_raw_gray)、DDR3控制模块(ddr3_top)和HDMI顶层模块(hdmi_top)。 时钟模块(pll_clk):时钟模块通过调用PLL IP核实现,为DDR3控制模块以及I2C驱动模块提供驱动时钟,为HDMI模块提供像素时钟和5倍像素时钟(频率分别是75Mhz和375Mhz)。 I2C驱动模块(i2c_dri):I2C驱动模块负责驱动MT9V034的两线式接口总线,用户根据该模块提供的用户接口可以很方便的对MT9V034的寄存器进行配置,该模块和“EEPROM读写实验”章节中用到的I2C驱动模块为同一个模块,有关该模块的详细介绍请大家参考“EEPROM读写实验”章节;其中代码改动部分的详细介绍请大家参考“MT9V034摄像头RGB-LCD显示实验”章节。 I2C配置模块(i2c_cfg):I2C配置模块的驱动时钟是由I2C驱动模块输出的时钟提供的,这样方便了I2C驱动模块和I2C配置模块之间的数据交互。该模块寄存需要配置的寄存器地址和数据,同时该模块输出MT9V034的寄存器地址和数据以及控制I2C驱动模块开始执行的控制信号,直接连接到I2C驱动模块的用户接口,从而完成对MT9V034传感器的配置。 图像采集模块(cmos_capture_raw_gray):在摄像头像素时钟的驱动下将传感器输出的场同步信号、行同步信号以及8位数据信号进行采集,在摄像头数据稳定后输出场同步信号、行同步信号以及8位数据信号,以提供给DDR3控制模块所使用。 DDR3控制模块(ddr3_top):DDR3读写控制器模块负责驱动DDR3片外存储器,缓存图像传感器输出的图像数据。该模块将DDR3复杂的读写操作封装成类似FIFO的用户接口,非常方便用户的使用。有关DDR3控制模块的详细介绍请大家参考“DDR3读写测试实验”章节。 HDMI顶层模块(hdmi_top):HDMI顶层模块负责驱动HDMI显示器的驱动信号的输出,同时为其他模块提供场同步信号和数据请求信号。HDMI顶层模块例化了HDMI视频显示模块(video_display)、HDMI视频显示驱动模块(video_driver)和HDMI驱动模块(dvi_transmitter_top)。 HDMI视频显示驱动模块负责产生行场信号和数据有效使能信号和像素点的横纵坐标。HDMI视频显示模块负责产生显示的像素点数据,并将内部信号data_req(数据请求信号)输出至端口,方便从DD3控制器中读取数据。HDMI驱动模块负责将RGB565格式的视频图像转换成TMDS数据输出。有关HDMI视频显示驱动模块、HDMI驱动模块的详细介绍请大家参考“HDMI彩条显示实验”章节,HDMI视频显示模块详细介绍请大家参考“OV7725摄像头HDMI显示实验”章节。
1.5 下载验证编译完工程之后就可以开始下载程序了。将MT9V034摄像头模块插在ATK-DFPGL22G开发板的“OLED/CAMERA”插座上,并将HDMI电缆一端连接到开发板上的HDMI插座、另一端连接到显示器。将下载器一端连电脑,另一端与开发板上的JTAG端口连接,连接电源线并打开电源开关。接下来我们下载程序,验证MT9V034 HDMI实时显示功能。下载完成后观察HDMI显示器显示的图案如下图所示,说明MT9V034 HDMI实时显示程序下载验证成功。 |