[X]关闭
2

(非AXI4)S02-CH03_OV7725_HDMI(4 片 DDR 三缓存)

摘要: 3.1 概述 在前面的章节,笔者非常详细的提供了一种数据缓存的构架,并且提供了完善的测试例子,对构架的设计做了充分的测试验证。本章内容只要把OV7725 摄像头的图像数据,作为数据源,替换上一章节用代码参数的测 ...

3.1 概述

      在前面的章节,笔者非常详细的提供了一种数据缓存的构架,并且提供了完善的测试例子,对 构架的设计做了充分的测试验证。本章内容只要把 OV7725 摄像头的图像数据,作为数据源,替换上 一章节用代码参数的测试数据就可以。当然说起来简单做起来也不容易,各种小问题,经常会导致开发进度延误,所以读者必须自己学会克服困难的办法。 

3.2 构架设计

       对于稍微复杂一点的工程项目必须要有优秀的构架设计,优秀的设计构架的意义比具体写代码 更有价值,所以笔者建议读者在以后自己的项目中要多学习和思考构架的设计。笔者设计了一种基于 消息缓存模式的构架,可以广泛用于图像缓存,数据采集缓存,通信数据缓存等项目中。如下图所示,

摄像头数据经过sensor_decode 模块解码摄像头数据后将RGB时序图像数据输入到MIG_BURTS_IMAGE, 然后再流出来到 vga_lcd_driver 模块,vga_lcd_driver 模块输出的是 RGB 时序,进过 HDMI IP模块 后接到 HDMI显示器显示输出。

    1) 、OV7725摄像头接口:是连接到开发板的物理接口,摄像头模块安装FEP转CEP扩展卡上,默认安装CEP1接口。

    2) 、HDMI 接口:是图形的输出接口,图像数据从 HDMI 接口输出 

    3) 、sensor_decode模块:解码 OV7725 摄像头的图像数据,然后转为 R/G/B 数据,同时需要产生 HS 信号、VS信号、de 信号提供给后续模块使用。如下面一段代码 

assign rgb_o = {rgb565[15:11],3'd0 ,rgb565[10:5] ,2'd0,rgb565[4:0],3'd0};  

//assign rgb_o = {grid_data_2,grid_data_2,grid_data_2};  

assign clk_ce =out_en? byte_flag_r0:1'b0;  

assign vs_o = out_en ? vsync_d[1] : 1'b0;  

assign hs_o = out_en ? href_d[1] : 1'b0;


4)、vga_lcd_driver 模块:产生 RGB(VGA)输出时序 

5)、MIG_BURST_IMAGE 模块:管理图像数据和内存管理,MIG_BURST_IMAGE 模块中包括了 CH0_FIFO 模 块、CH6_FIFO 模块、MIG_DDR 控制器、MSG_FIFO 消息盒、M_S 内存管理状态机,此外还包括 CH0_FIFO 的读请求,以及 CH6_FIFO 的写请求。

3.3 主要模块源码分析

3.3.1 sensor_decode.v

module sensor_decode(  

 input cmos_clk_i,//cmos senseor clock.  

 input rst_n_i,//system reset.active low.  

 input cmos_pclk_i,//input pixel clock.  

 input cmos_href_i,//input pixel hs signal.  

 input cmos_vsync_i,//input pixel vs signal.  

 input  [7:0]cmos_data_i,//data.  

 output cmos_xclk_o,//output clock to cmos sensor.  

 output hs_o,//hs signal.  

 output vs_o,//vs signal.  

 output [23:0] rgb_o,//data output  

 output clk_ce

    );


assign cmos_xclk_o = cmos_clk_i;      

parameter[5:0]CMOS_FRAME_WAITCNT = 4'd15;      

reg[4:0] rst_n_reg = 5'd0;      

reg cmos_href_r;

reg cmos_vsync_r;

reg [7:0]cmos_data_r;


always@(posedge cmos_pclk_i)

begin  

       cmos_data_r <= cmos_data_i;  

       cmos_href_r <= cmos_href_i;  

       cmos_vsync_r<= ~cmos_vsync_i;  

end     

//reset signal deal with.  

always@(posedge cmos_clk_i)

begin  

 rst_n_reg <= {rst_n_reg[3:0],rst_n_i};  

End


reg[1:0]vsync_d;

reg[1:0]href_d;

wire vsync_start;

wire vsync_end;

//vs signal deal with.  

always@(posedge cmos_pclk_i)

begin  

 vsync_d <= {vsync_d[0],cmos_vsync_r};  

 href_d  <= {href_d[0],cmos_href_r};  

end


assign vsync_end  =  vsync_d[1]&(!vsync_d[0]);  assign vsync_start  = (!vsync_d[1])&vsync_d[0];


reg[6:0]cmos_fps;

//frame count.  

always@(posedge cmos_pclk_i)

begin

 if(!rst_n_reg[4])

  begin

  cmos_fps <= 7'd0;

  end

 else if(vsync_start)

  begin  

  cmos_fps <= cmos_fps + 7'd1;  

  end  

 else if(cmos_fps >= CMOS_FRAME_WAITCNT)  

  begin  

  cmos_fps <= CMOS_FRAME_WAITCNT;  

  end

end

//wait frames and output enable.  

reg out_en;

always@(posedge cmos_pclk_i)

begin

 if(!rst_n_reg[4])

  begin

  out_en <= 1'b0;

  end  

 else if(cmos_fps >= CMOS_FRAME_WAITCNT)  

  begin

  out_en <= 1'b1;

end

 else

  begin  

  out_en <= out_en;  

  end

end


//output data 8bit changed into 16bit in rgb565.  

reg [7:0] cmos_data_d0;  

reg [15:0]cmos_rgb565_d0;

reg byte_flag;


always@(posedge cmos_pclk_i)  

begin

 if(!rst_n_reg[4])  

  byte_flag <= 0;  

 else if(cmos_href_r)  

  byte_flag <= ~byte_flag;  

 else

  byte_flag <= 0;

end


reg byte_flag_r0;  

always@(posedge cmos_pclk_i)  

begin

 if(!rst_n_reg[4])  

  byte_flag_r0 <= 0;  

 else   

  byte_flag_r0 <= byte_flag;  

end


always@(posedge cmos_pclk_i)

begin

 if(!rst_n_reg[4])

  cmos_data_d0 <= 8'd0;  

 else if(cmos_href_r)  

  cmos_data_d0 <= cmos_data_r; //MSB -> LSB  

 else if(~cmos_href_r)   

  cmos_data_d0 <= 8'd0;

end


reg [15:0] rgb565;

always@(posedge cmos_pclk_i)

begin

 if(!rst_n_reg[4])

  rgb565 <= 16'd0;

 else if(cmos_href_r&byte_flag)  

  rgb565 <= {cmos_data_d0,cmos_data_r}; //MSB -> LSB

else if(~cmos_href_r)  

  rgb565 <= 8'd0;

End

//以下代码是利用摄像头输出的时序,产生自动定义的测试数据//   

reg [7:0]cnt_test;

reg [8:0]cnt_temp;

reg [11:0]vcounter;

reg [15:0]vcnt=10'd0;

always@(posedge cmos_pclk_i) begin

if(!rst_n_reg[4]) begin

    vcnt<=16'd0;

end else begin

    if(vsync_start)  

            vcounter <=12'd0;

            if(!vcnt[15])vcnt <= vcnt+1'b1;  

     else if({href_d[0],cmos_href_r}==2'b01)  

             vcounter <= vcounter + 12'd1;

 end

end

reg [11:0]hcounter;

always@(posedge cmos_pclk_i) begin

  if(!cmos_href_r)  

    hcounter <=12'd0;

  else  

    hcounter <= hcounter + 12'd1;

end

reg[7:0] grid_data_1;

reg[7:0] grid_data_2;

always @(posedge cmos_pclk_i)//格子图像 

begin

 if((hcounter[2]==1'b1)^(vcounter[4]==1'b1))

 grid_data_1 <= 8'h00;

 else

 grid_data_1 <= 8'hff;

 if((hcounter[6]==1'b1)^(vcounter[6]==1'b1))

 grid_data_2 <= 8'h00;

 else

 grid_data_2 <= 8'hff;

End

assign rgb_o = {grid_data_2,grid_data_2,grid_data_2};  

//以上代码是利用摄像头输出的时序,产生自动定义的测试数据//   

//assign rgb_o = {rgb565[15:11],3'd0 ,rgb565[10:5] ,2'd0,rgb565[4:0],3'd0};  assign clk_ce =out_en? byte_flag_r0:1'b0;  

assign vs_o = out_en ? vsync_d[1] : 1'b0;  

assign hs_o = out_en ? href_d[1] : 1'b0;

/*

ila_2 sensor_sg (

 .clk(cmos_pclk_i), // input wire clk

.probe0(vs_o), // input wire [0:0]  probe0    

 .probe1(hs_o), // input wire [0:0]  probe1   

 .probe2(clk_ce), // input wire [0:0]  probe2   

 .probe3(vcounter[8:0]), // input wire [0:0]  probe3   

 .probe4(grid_data_2) // input wire [0:0]  probe4   );*/


      OV7725输入的图像是 640X480 分辨率的图形,为了观察数据的方便,未来观察行场信号是否正 确,笔者先利用上一课中用到的测试图形方案数据代码 OV7725 产生的 RGB数据,而行场信号继续使 用 OV7725 产生的行场信号。这么做的目的,主要是我们在对 OV7725 解码的时候可能采样的颜色时序会出问题,但是一开始又不能定位问题,这样可以循序渐进式解决问题。 

3.3.2 vga_lcd_driver.v

module vga_lcd_driver(

    input  clk,

    input  [7:0]  r_i,

    input  [7:0]  g_i,

    input  [7:0]  b_i,

    output [7:0]  r_o,

    output [7:0]  g_o,

    output [7:0]  b_o,

    output de,

    output vsync,

    output hsync

    );


   reg  [11:0] hcounter;

   reg  [11:0] vcounter;

    

// Colours converted using The RGB


// -- Set the video mode to 1920x1080x60Hz (150MHz pixel clock needed)

 /*    parameter hVisible  = 1920;

   parameter hStartSync = 1920+88;

   parameter hEndSync   = 1920+88+44;

   parameter hMax       = 1920+88+44+148; //2200

   

   parameter vVisible    = 1080;

   parameter vStartSync  = 1080+4;

   parameter vEndSync    = 1080+4+5;

   parameter vMax        = 1080+4+5+36; //1125

*/


// -- Set the video mode to 1440x900x60Hz (106.47MHz pixel clock needed)

/*   parameter hVisible   = 1440;

   parameter hStartSync = 1440+80;

   parameter hEndSync   = 1440+80+152;

   parameter hMax       = 1440+80+152+232; //1904

   

   parameter vVisible    = 900;

   parameter vStartSync  = 900+1;

   parameter vEndSync    = 900+1+3;

   parameter vMax        = 900+1+3+28; //932

   */

  /*   

// -- Set the video mode to 1280x720x60Hz (75MHz pixel clock needed)

   parameter hVisible   = 1280;

   parameter hStartSync = 1280+72;

   parameter hEndSync   = 1280+72+80;

   parameter hMax       = 1280+72+80+216; //1647

   

   parameter vVisible    = 720;

   parameter vStartSync  = 720+3;

   parameter vEndSync    = 720+3+5;

   parameter vMax        = 720+3+5+22; //749


// -- Set the video mode to 800x600x60Hz (40MHz pixel clock needed)

  parameter hVisible   = 800;

   parameter hStartSync = 840; //800+40

   parameter hEndSync   = 968; //800+40+128

   parameter hMax       = 1056; //800+40+128+88

   

   parameter vVisible    = 600;

   parameter vStartSync  = 601; //600+1

   parameter vEndSync    = 605; //600+1+4

   parameter vMax        = 628; //600+1+4+23      


*/


// -- Set the video mode to 640x480x60Hz (25MHz pixel clock needed)


   parameter hVisible   = 640;

   parameter hStartSync = 656; //640+16

   parameter hEndSync   = 752; //640+16+96

   parameter hMax       = 800; //640+16+96+48

   

   parameter vVisible    = 480;

   parameter vStartSync  = 490; //480+10

   parameter vEndSync    = 492; //480+10+2

   parameter vMax        = 525; //480+10+2+33

//------------------------------------------

//v_sync counter & generator


always@(posedge clk) begin

if(hcounter < hMax - 12'd1)        //line over

hcounter <= hcounter + 12'd1;

else

hcounter <= 12'd0;

end


always@(posedge clk) begin

if(hcounter == hMax - 12'd1) begin

if(vcounter < vMax - 12'd1)  //frame over

vcounter <= vcounter + 12'd1;

else

vcounter <= 12'd0;

end

end


assign hsync = ((hcounter >= (hStartSync - 2'd2))&&(hcounter < (hEndSync - 2'd2)))? 1'b0:1'b1;  //Generate the hSync Pulses

assign vsync = ((vcounter >= (vStartSync - 1'b1))&&(vcounter < (vEndSync - 1'b1)))? 1'b0:1'b1; //Generate the vSync Pulses

  

  assign de = (vcounter >= vVisible || hcounter >= hVisible) ? 1'b0 : 1'b1;

  assign r_o = r_i;

  assign g_o = g_i;

  assign b_o = b_i;  

endmodule

       vga_lcd_driver模块的作用是产生一副 640X480 分辨率的RGB使出时序,RGB 的数据来源来自 CH6_FIFO。读者可以修改不同分辨率输出不同的测试图形。 

3.3.3 CH0_FIFO FIFO IP 设置

Step1:设置 Native 和 Independent Clocks Block RAM

Step2:设置 FIFO 采用 Firt Word Fall Through 模式,FIFO 的写是 64bit 2048 深度 FIFO 的读是 512bit 256 深度

Step3:默认设置

Step4:设置计数器


   wire CH0_empty;

    CH0_FIFO CH0_FIFO_INST (

    .rst(CH0_FIFO_RST),  // input wire rst

    .wr_clk(CH0_wclk_i), // input wire wr_clk

    .rd_clk(CH0_rclk_i),// input wire rd_clk

    .din(CH0_data_i), // input wire [63 : 0] din

    .wr_en(CH0_wren_i), // input wire wr_en

    .rd_en(CH0_rden_i), // input wire rd_en

    .dout(CH0_data_o),  // output wire [512 : 0] dout

    .full(),  // output wire full

    .empty(CH0_empty), // output wire empty

    .rd_data_count(CH0_rusdw_o)  // output wire [7 : 0] rd_data_count

    );

3.3.4 CH6_FIFO FIFO IP 设置

Step1:设置 Native 和 Common Clocks Block RAM

Step2:设置 FIFO 采用 Firt Word Fall Through 模式,FIFO 的写是 32bit 32 深度 FIFO 的读是 64bit 16 深度

Step3:这一页设置默认

Step4:设置读FIFO 的 counter 计数器宽度是6bit


    //----------------CH6 fifo


路过

雷人

握手

鲜花

鸡蛋
发表评论

最新评论

引用 uisrc 2019-10-28 01:02
购买开发板的可以获取下载地址
引用 陌路不知 2019-10-17 08:34
亲  请问,这些课程有没有例程和电子板资料可以下载呀?
  我工作的电脑没有网络!!在网页上看不是那么方便。  谢谢

查看全部评论(2)

本文作者
2019-10-16 11:42
  • 1
    粉丝
  • 2982
    阅读
  • 2
    回复

米联客UIsrc

独家课程 硬核科技

销售电话:18921033576
EMAIL:tjy@uisrc.com
地址:常州溧阳市天目云谷3号楼北楼
热门评论
排行榜