基于FPGA的OV7725摄像头的HDMI显示(含源码)

news2024/11/15 11:11:01

1、概述

  本文FPGA通过SCCB接口初始化OV7725摄像头寄存器,然后采集OV7725的摄像头数据,使用DDR3对数据进行暂存,最后将数据输出到HDMI显示器上进行显示。

  该工程对应系统框图如下所示,主要包含OV7725驱动及数据处理模块、DDR3读写控制模块、HDMI控制模块。其中DDR3读写控制模块和HDMI显示控制模块在前文设计中已经进行详细讲解过了,本文直接使用即可,不再对其功能的实现进行赘述,不了解的可以参考前文。

  由于只需要向OV7725的寄存器中写入数据,所以可以直接使用前文编写的I2C驱动模块代替SCCB驱动模块。iic_drive模块是I2C的驱动模块,兼容SCCB的写时序。init_contrl模块主要功能是控制初始化OV7725的哪些寄存器。Capture_data模块将摄像头输出的8位数据拼接为16位数据,然后传输给DDR3读写模块,将数据存入DDR3中。

在这里插入图片描述

图1 系统框图

  后面DDR3控制模块和HDMI显示模块的设计思路与以太网传输图片中两个模块的设计基本一致。

  外部的晶振输入100MHz时钟,通过锁相环进行倍频、分频处理,给OV7725提供12MHz的系统时钟XCLK,给DDR3控制模块提供200MHz的参考时钟和MIG IP工作时钟。由于显示器分辨率为1024*768,所以还需要给HDMI模块提供65MHz时钟和325MHz的参考时钟信号。

  对于异步信号,首先DDR3读写控制模块的读、写两侧都是异步FIFO,相应的数据就能够异步FIFO交换数据,不需要做额外处理。

2、OV7725初始化控制模块

  根据官方提供的初始化参数,对70个寄存器进行初始化,最终输出PCLK时钟频率为24MHz,640*480分辨率的RGB565像素数据。根据前文时序的介绍,首先对8’h12寄存器进行设置,使所有寄存器复位,发出该命令之后,需要等待1ms才能开始配置其余寄存器。

  因此通过一个复位计数器和复位标志信号来对复位状态进行指示,为了简化电路,此处使用的计数器依靠溢出清零。

  如下代码所示,复位指示信号初始值为0,wdata_cnt计数器用于表示已经初始化的寄存器个数。因为最先初始化的是复位计数器,因此当wdata_cnt等于1并且I2C驱动模块空闲的时候,证明复位寄存器已经被写入数据了,此时复位指示信号拉高,当复位计数器所有位均为高电平时,表示复位的持续时间大于1ms,此时可以配置后续寄存器了。

    //生成复位指示信号,初始为低电平,当复位寄存器且等待1ms之后拉低,表示复位完成;
    always@(posedge clk)begin
        if(rst_n==1'b0)begin//初始值为0;
            rst_flag <= 1'b0;
        end//当延时计数器全为1时,表示延时1.3ms,复位完成。
        else if(&delay_cnt)begin
            rst_flag <= 1'b0;
        end//当配置第0个数据之后,如果I2C驱动模块空闲,表示复位寄存器初始化完成,之后需要延时1ms才能继续配置其他寄存器。
        else if(wdata_cnt == 7'd1 && rdy)begin
            rst_flag <= 1'b1;
        end
    end

  下面代码就是复位的延时计数器,当复位指示信号有效时,对系统时钟进行计数,当溢出时清零,系统时钟周期为10ns,17位计数器从0计数到最大值需要131071个时钟,即1.31ms。

    //为了便于计数,直接使用一个17位计数器对100MHz时钟进行计数。
    always@(posedge clk)begin
        if(rst_n==1'b0)begin//初始值为0;
            delay_cnt <= 17'd0;
        end
        else if(rst_flag)begin//处于复位状态下,对系统时钟进行计数。
            delay_cnt <= delay_cnt + 17'd1;
        end
    end

  之后就是计数器wdata_cnt,对初始化的寄存器个数进行计数。初始值为0,当初始化复位计数器时,要等延时计数器计数结束才能加一,如果初始化的不是复位寄存器,且已配置寄存器个数小于需要配置的寄存器个数,且I2C驱动模块处于空闲时加1。

    //wdata_cnt计数器用于记录配置的寄存器个数;
    always@(posedge clk)begin
        if(rst_n==1'b0)begin//
            wdata_cnt <= 0;
        end
        else if(add_wdata_cnt)begin
            wdata_cnt <= wdata_cnt + 1;
        end
    end
    
    //记录初始化寄存器的个数,由于第0个寄存器初始化之后需要延时1ms,所以当计数器等于1时,需要等待延时计数器计数结束才能加1。
    //其余时间只需要等待I2C驱动模块空闲,就可以发送数据。
    assign add_wdata_cnt = (((wdata_cnt == 7'd1) && (&delay_cnt)) || ((wdata_cnt != 7'd1) && rdy && (wdata_cnt < REG_NUM)));

  将计数器加一条件延时一个时钟周期作为I2C驱动模块的开始信号,由于只需要向寄存器写入数据,所以读写标志信号一直拉低即可。根据计数器的数值生成需要写入寄存器的地址和数据。

    //写开始信号,当计数器加一条件有效且没有配置完所有寄存器时拉高;
    always@(posedge clk)begin
        if(rst_n==1'b0)begin//初始值为0;
            start <= 1'b0;
        end
        else begin
            start <= add_wdata_cnt;
        end
    end

    assign rw_flag = 1'b0;//读写控制信号置为低电平,因为只需要对寄存器进行初始化,不会有读操作。

    //设置寄存器的地址和数据;
    always@(posedge clk)begin
        if(rst_n==1'b0)begin//初始值为0;
            {reg_addr,wdata} <=	{8'h1C, 8'h7F}; //MIDH 制造商ID 高8位;
        end
        else if(add_wdata_cnt)begin
            case(wdata_cnt)
                //先对寄存器进行软件复位,使寄存器恢复初始值;
                //寄存器软件复位后,需要延时1ms才能配置其它寄存器;
                7'd0  : {reg_addr,wdata} <= {8'h12, 8'h80}; //COM7 BIT[7]:复位所有的寄存器;
                7'd1  : {reg_addr,wdata} <= {8'h3d, 8'h03}; //COM12 模拟过程直流补偿;
                7'd2  : {reg_addr,wdata} <= {8'h15, 8'h02}; //COM10 href/vsync/pclk/data信号控制;
                7'd3  : {reg_addr,wdata} <= {8'h17, 8'h23}; //HSTART 水平起始位置;
                7'd4  : {reg_addr,wdata} <= {8'h18, 8'ha0}; //HSIZE 水平尺寸;
                7'd5  : {reg_addr,wdata} <= {8'h19, 8'h07}; //VSTRT 垂直起始位置;
                7'd6  : {reg_addr,wdata} <= {8'h1a, 8'hf0}; //VSIZE 垂直尺寸;
                7'd7  : {reg_addr,wdata} <= {8'h32, 8'h00}; //HREF 图像开始和尺寸控制,控制低位;
                7'd8  : {reg_addr,wdata} <= {8'h29, 8'ha0}; //HOutSize 水平输出尺寸;
                7'd9  : {reg_addr,wdata} <= {8'h2a, 8'h00}; //EXHCH 虚拟像素MSB;
                7'd10 : {reg_addr,wdata} <= {8'h2b, 8'h00}; //EXHCL 虚拟像素LSB;
                7'd11 : {reg_addr,wdata} <= {8'h2c, 8'hf0}; //VOutSize 垂直输出尺寸;
                7'd12 : {reg_addr,wdata} <= {8'h0d, 8'h41}; //COM4 PLL倍频设置(multiplier);                                   
                7'd13 : {reg_addr,wdata} <= {8'h11, 8'h00}; //CLKRC 内部时钟配置;
                7'd14 : {reg_addr,wdata} <= {8'h12, 8'h06}; //COM7 输出VGA RGB565格式;
                7'd15 : {reg_addr,wdata} <= {8'h0c, 8'h10}; //COM3 Bit[0]: 0:图像数据 1:彩条测试;
                //DSP 控制
                7'd16 : {reg_addr,wdata} <= {8'h42, 8'h7f}; //TGT_B 黑电平校准蓝色通道目标值;
                7'd17 : {reg_addr,wdata} <= {8'h4d, 8'h09}; //FixGain 模拟增益放大器;
                7'd18 : {reg_addr,wdata} <= {8'h63, 8'hf0}; //AWB_Ctrl0 自动白平衡控制字节0;
                7'd19 : {reg_addr,wdata} <= {8'h64, 8'hff}; //DSP_Ctrl1 DSP控制字节1;
                7'd20 : {reg_addr,wdata} <= {8'h65, 8'h00}; //DSP_Ctrl2 DSP控制字节2;
                7'd21 : {reg_addr,wdata} <= {8'h66, 8'h00}; //DSP_Ctrl3 DSP控制字节3;
                7'd22 : {reg_addr,wdata} <= {8'h67, 8'h00}; //DSP_Ctrl4 DSP控制字节4;
                //AGC AEC AWB        
                //COM8 Bit[2]:自动增益使能 Bit[1]:自动白平衡使能 Bit[0]:自动曝光功能;
                7'd23 : {reg_addr,wdata} <= {8'h13, 8'hff}; //COM8;
                7'd24 : {reg_addr,wdata} <= {8'h0f, 8'hc5}; //COM6;
                7'd25 : {reg_addr,wdata} <= {8'h14, 8'h11};  
                7'd26 : {reg_addr,wdata} <= {8'h22, 8'h98}; 
                7'd27 : {reg_addr,wdata} <= {8'h23, 8'h03};  
                7'd28 : {reg_addr,wdata} <= {8'h24, 8'h40}; 
                7'd29 : {reg_addr,wdata} <= {8'h25, 8'h30};  
                7'd30 : {reg_addr,wdata} <= {8'h26, 8'ha1};      
                7'd31 : {reg_addr,wdata} <= {8'h6b, 8'haa}; 
                7'd32 : {reg_addr,wdata} <= {8'h13, 8'hff};  
                //matrix sharpness brightness contrast UV
                7'd33 : {reg_addr,wdata} <= {8'h90, 8'h0a}; //EDGE1 边缘增强控制1;
                //DNSOff 降噪阈值下限,仅在自动模式下有效
                7'd34 : {reg_addr,wdata} <= {8'h91, 8'h01}; //DNSOff;
                7'd35 : {reg_addr,wdata} <= {8'h92, 8'h01}; //EDGE2 锐度(边缘增强)强度上限;
                7'd36 : {reg_addr,wdata} <= {8'h93, 8'h01}; //EDGE3 锐度(边缘增强)强度下限;
                7'd37 : {reg_addr,wdata} <= {8'h94, 8'h5f}; //MTX1 矩阵系数1;
                7'd38 : {reg_addr,wdata} <= {8'h95, 8'h53}; //MTX1 矩阵系数2;
                7'd39 : {reg_addr,wdata} <= {8'h96, 8'h11}; //MTX1 矩阵系数3;
                7'd40 : {reg_addr,wdata} <= {8'h97, 8'h1a}; //MTX1 矩阵系数4;
                7'd41 : {reg_addr,wdata} <= {8'h98, 8'h3d}; //MTX1 矩阵系数5;
                7'd42 : {reg_addr,wdata} <= {8'h99, 8'h5a}; //MTX1 矩阵系数6;
                7'd43 : {reg_addr,wdata} <= {8'h9a, 8'h1e}; //MTX_Ctrl 矩阵控制;
                7'd44 : {reg_addr,wdata} <= {8'h9b, 8'h3f}; //BRIGHT 亮度;
                7'd45 : {reg_addr,wdata} <= {8'h9c, 8'h25}; //CNST 对比度;
                7'd46 : {reg_addr,wdata} <= {8'h9e, 8'h81}; 
                7'd47 : {reg_addr,wdata} <= {8'ha6, 8'h06}; //SDE 特殊数字效果控制;
                7'd48 : {reg_addr,wdata} <= {8'ha7, 8'h65}; //USAT "U"饱和增益;
                7'd49 : {reg_addr,wdata} <= {8'ha8, 8'h65}; //VSAT "V"饱和增益;     
                7'd50 : {reg_addr,wdata} <= {8'ha9, 8'h80}; //VSAT "V"饱和增益;
                7'd51 : {reg_addr,wdata} <= {8'haa, 8'h80}; //VSAT "V"饱和增益;
                //伽马控制 
                7'd52 : {reg_addr,wdata} <= {8'h7e, 8'h0c}; 
                7'd53 : {reg_addr,wdata} <= {8'h7f, 8'h16}; 
                7'd54 : {reg_addr,wdata} <= {8'h80, 8'h2a}; 
                7'd55 : {reg_addr,wdata} <= {8'h81, 8'h4e}; 
                7'd56 : {reg_addr,wdata} <= {8'h82, 8'h61}; 
                7'd57 : {reg_addr,wdata} <= {8'h83, 8'h6f}; 
                7'd58 : {reg_addr,wdata} <= {8'h84, 8'h7b}; 
                7'd59 : {reg_addr,wdata} <= {8'h85, 8'h86};   
                7'd60 : {reg_addr,wdata} <= {8'h86, 8'h8e}; 
                7'd61 : {reg_addr,wdata} <= {8'h87, 8'h97}; 
                7'd62 : {reg_addr,wdata} <= {8'h88, 8'ha4}; 
                7'd63 : {reg_addr,wdata} <= {8'h89, 8'haf}; 
                7'd64 : {reg_addr,wdata} <= {8'h8a, 8'hc5}; 
                7'd65 : {reg_addr,wdata} <= {8'h8b, 8'hd7}; 
                7'd66 : {reg_addr,wdata} <= {8'h8c, 8'he8}; 
                7'd67 : {reg_addr,wdata} <= {8'h8d, 8'h20};             
                7'd68 : {reg_addr,wdata} <= {8'h0e, 8'h65}; //COM5;
                7'd69 : {reg_addr,wdata} <= {8'h09, 8'h00}; //COM2  Bit[1:0] 输出电流驱动能力;
                //只读存储器,防止在case中没有列举的情况,之前的寄存器被重复改写;
                default:{reg_addr,wdata} <=	{8'h1C, 8'h7F}; //MIDH 制造商ID 高8位;
            endcase
        end
    end

  当所有寄存器配置完成后,将配置完成信号拉高。

    //初始化完成信号;
    always@(posedge clk)begin
        if(rst_n==1'b0)begin//初始值为0;
            init_done <= 1'b0;
        end//当所有寄存器写入数据,且I2C驱动模块处于空闲状态时,表示初始化完成;
        else if((wdata_cnt == REG_NUM) && rdy)begin
            init_done <= 1'b1;
        end
    end

  由于该模块的逻辑比较简单,因此没有进行仿真,后续直接上板即可,参考代码如下:

3、摄像头数据处理模块

  由于配置摄像头寄存器之后,需要10帧图像数据的时间,才能正常传输数据。当寄存器初始化完成之后,对场同步信号的上升沿进行检测,直到检测到10个为止。

    //将场同步信号延迟两个时钟周期,用于检测其上升沿;
    always@(posedge cam_pclk)begin
        cam_vsync_r <= {cam_vsync_r[0],cam_vsync};
        cam_href_r <= {cam_href_r[0],cam_href};
    end

    //检测场同步信号上升沿;
    assign cam_vsync_pos = cam_vsync_r[0] & (~cam_vsync_r[1]);
    assign cam_href_neg = (~cam_href_r[0]) & cam_href_r[1];

    //延时计数器,用于记录复位后,前几帧数据;
    always@(posedge cam_pclk)begin
        if(rst_n==1'b0)begin//
            delay_cnt <= 0;
        end//当寄存器初始化完成,且检测到场同步上升沿,且小于10帧时加1;
        else if(ov7725_init_done && cam_vsync_pos && (delay_cnt < WAIT_FRAME - 1))begin
            delay_cnt <= delay_cnt + 1;
        end
    end

    //等待完成信号;
    always@(posedge cam_pclk)begin
        if(rst_n==1'b0)begin//初始值为0;
            delay_done <= 1'b0;
        end//
        else if(ov7725_init_done && cam_vsync_pos && (delay_cnt >= WAIT_FRAME - 1))begin
            delay_done <= 1'b1;
        end
    end

  由于需要把输入的8位像素数据拼接为16位像素数据输出,需要一个标志信号byte_flag,每行结束或者每帧数据开始时清零该信号,当像素有效信号HREF为高电平时,byte_flag翻转。

    //相当于一个计数器,用于记录采集数据的个数,当数据有效时翻转,为1时表示采集了两个数据;
    always@(posedge cam_pclk)begin
        if(rst_n==1'b0)begin//初始值为0;
            byte_flag <= 1'b0;
        end
        else if(cam_href_neg | cam_vsync_pos)begin//在一帧数据开始或者一行数据接收结束时清零,便于下次计数的正确;
            byte_flag <= 1'b0;
        end
        else if(cam_href)begin
            byte_flag <= ~byte_flag;
        end
    end

  当输入像素有效(HREF位高电平),如果byte_flag为低电平,表示输入高字节数据,如果byte_flag为高电平,表示输入低字节数据。之后将像素输出有效指示信号拉高。最后可以把场同步信号输出,作为DDR3读、写控制模块写FIFO的复位信号,每帧数据开始时会对写FIFO进行复位,保证下一帧数据正确存储。

    //将8位数据转换为16位数据输出,摄像头先传输高字节数据,后传输低字节数据;
    always@(posedge cam_pclk)begin
        if(rst_n==1'b0)begin//初始值为0;
            cmos_frame_data <= 16'd0;
        end
        else if(cam_href)begin
            if(byte_flag)//采集低字节数据;
                cmos_frame_data[7:0] <= cam_data;
            else//采集高字节数据;
                cmos_frame_data[15:8] <= cam_data;
        end
    end

    //输出像素有效指示信号,当采集完两次数据后输出一次有效数据;
    always@(posedge cam_pclk)begin
        if(rst_n==1'b0)begin//初始值为0;
            cmos_frame_valid <= 1'b0;
        end
        else begin//当采集完两次数据且已经过了延时时输出一次有效数据
            cmos_frame_valid <= cam_href & byte_flag & delay_done;
        end
    end

    //输出场同步信号,延时完成后,将行同步信号延时一个时钟输出;
    assign cmos_frame_vsync = delay_done ? cam_vsync_r[0] : 1'b0;

  该模块的设计就这么简单,起始可以不用关心前10帧图像数据,可以继续简化模块设计。

4、顶层模块

  本次设计由于生成的时钟比较多,需要例化两个锁相环模块才能完成。另外摄像头采集的场同步信号作为DDR3读写控制模块的写FIFO复位,由于场同步信号拉高会提前有效像素几千个时钟,这段时间完成FIFO的复位完全没问题。

  DDR3读写控制模块使用乒乓模式,因为读速率比较快,所以始终读与写地址相反的地址区域即可。

  另外需要对HDMI数据请求信号修改,由于显示器的像素为1024*768,而摄像头采集数据的像素是640*480,需要把图像显示在显示器的中心区域。

  则水平像素显示区域为191831,垂直像素显示区域为143623,这段时间才能把DDR3读写控制模块的读使能信号拉高,一个时钟后得到像素数据。

在这里插入图片描述

图2 数据请求信号的范围进行更改

  将HDMI的场同步信号作为DDR3读写控制模块的读FIFO的复位信号,每读取一帧数据就对读FIFO的数据清零,确保下一帧图像正确显示。

  由于摄像头采集的数据一行包含640个像素点,为了DDR3读侧FIFO不溢出,FIFO深度设置为2048。

  整个模块的RTL视图如下所示:

在这里插入图片描述

图3 RTL系统视图

  参考代码如下:

    assign power_en = 1'b1;//使能模块电源,仅对此模块有用;
    
    //例化锁相环,输出200MHZ时钟,作为DDR的参考时钟;
    //生成65MHz时钟作为HDMI的参考时钟信号;
    clk_wiz_0 u_clk_wiz_0(
        .clk_out1   ( clk_200m      ),//output clk_out1
        .clk_out2   ( dvi_clk       ),//output clk_out2
        .clk_out3   ( dvi_clk_5x    ),//output clk_out3
        .resetn     ( rst_n         ),//input resetn
        .locked     ( sys_rst_n     ),//output locked
        .clk_in1    ( clk           ) //input clk_in1
    );

    //还要生成一路频率位12MHz的时钟输出给摄像头模块;
    clk_wiz_1 u_clk_wiz_1(
        .clk_out1   ( cam_xclk      ),//output clk_out1
        .resetn     ( rst_n         ),//input resetn
        .clk_in1    ( clk           ) //input clk_in1
    );      

    //例化OV7725摄像头采集模块;
    ov7725_top u_ov7725_top (
        .clk                ( clk               ),//系统时钟信号,100MHz;
        .rst_n              ( sys_rst_n         ),//系统复位信号,低电平有效;
        .cam_pclk           ( cam_pclk          ),//摄像头数据像素时钟;
        .cam_vsync          ( cam_vsync         ),//摄像头场同步信号;
        .cam_href           ( cam_href          ),//摄像头行同步信号;
        .cam_data           ( cam_data          ),//摄像头输入数据信号;
        .cmos_frame_vsync   ( cmos_frame_vsync  ),//帧有效信号;
        .cmos_frame_valid   ( cmos_frame_valid  ),//数据有效使能信号;
        .cmos_frame_data    ( cmos_frame_data   ),//有效数据;
        .scl                ( scl               ),//SCCB串行时钟信号;
        .sda                ( sda               ) //SCCB双向串行数据信号;
    );

    //例化DDR3顶层模块
    ddr3_top u_ddr3_top (
        .sys_clk_i          ( clk_200m          ),//MIG IP核输入时钟,200MHz;
        .rst_n              ( sys_rst_n         ),//复位,低有效;
        .ddr3_init_done     ( ddr3_init_done    ),//ddr3初始化完成信号;
        //DDR3接口信号
        .ddr3_addr          ( ddr3_addr         ),//ddr3 地址;
        .ddr3_ba            ( ddr3_ba           ),//ddr3 banck地址;
        .ddr3_ras_n         ( ddr3_ras_n        ),//ddr3 行选择;
        .ddr3_cas_n         ( ddr3_cas_n        ),//ddr3 列选择;
        .ddr3_we_n          ( ddr3_we_n         ),//ddr3 读写选择;
        .ddr3_reset_n       ( ddr3_reset_n      ),//ddr3 复位;
        .ddr3_ck_p          ( ddr3_ck_p         ),//ddr3 时钟正;
        .ddr3_ck_n          ( ddr3_ck_n         ),//ddr3 时钟负;
        .ddr3_cke           ( ddr3_cke          ),//ddr3 时钟使能;
        .ddr3_cs_n          ( ddr3_cs_n         ),//ddr3 片选;
        .ddr3_dm            ( ddr3_dm           ),//ddr3_dm;
        .ddr3_odt           ( ddr3_odt          ),//ddr3_odt;
        .ddr3_dq            ( ddr3_dq           ),//ddr3 数据;
        .ddr3_dqs_n         ( ddr3_dqs_n        ),//ddr3 dqs负;
        .ddr3_dqs_p         ( ddr3_dqs_p        ),//ddr3 dqs正;
        //复位及突发读写长度设置信号;
        .app_addr_wr_min    ( 29'd0             ),//读ddr3的起始地址;
        .app_addr_wr_max    ( 29'd307200        ),//读ddr3的结束地址;
        .app_wr_bust_len    ( 8'd80             ),//从ddr3中读数据时的突发长度;
        .app_addr_rd_min    ( 29'd0             ),//读ddr3的起始地址;
        .app_addr_rd_max    ( 29'd307200        ),//读ddr3的结束地址;
        .app_rd_bust_len    ( 8'd80             ),//从ddr3中读数据时的突发长度;
        .wr_rst             ( cmos_frame_vsync  ),//写复位信号,上升沿有效,持续时间必须大于ui_clk的周期;
        .rd_rst             ( video_vs          ),//读复位信号,上升沿有效,持续时间必须大于ui_clk周期;
        //写数据相关信号;
        .wfifo_wclk         ( cam_pclk          ),//写FIFO写时钟信号;
        .wfifo_wren         ( cmos_frame_valid  ),//写FIFO写使能信号;
        .wfifo_wdata        ( cmos_frame_data   ),//写FIFO写数据信号;
        .wfifo_wcount       (                   ),//写FIFO中的数据个数;
        .wfifo_full         ( wfifo_full        ),//写FIFO满指示信号;
        .wfifo_wrst_busy    ( wfifo_wrst_busy   ),//写FIFO复位完成指示信号,低电平表示复位完成;
        //读数据相关信号
        .rfifo_rclk         ( dvi_clk           ),//读FIFO读时钟;
        .rfifo_rden         ( data_req          ),//读FIFO读使能信号;
        .rfifo_rdata        ( pixel_data        ),//读FIFO读数据;
        .rfifo_rcount       ( rfifo_rcount      ),//读FIFO中的数据个数;
        .rfifo_empty        (                   ),//读FIFO空指示信号;
        .rfifo_rrst_busy    ( rfifo_rrst_busy   ) //读FIFO复位状态指示信号,高电平表示处于复位过程中。
    );

    //例化DVI接口驱动模块
    dvi_top  u_dvi_top (
        .dvi_clk            ( dvi_clk           ),//DVI时钟信号,1024*768分辨率时为65MHz
        .dvi_clk_5x         ( dvi_clk_5x        ),//DVI的5倍参考时钟信号,325MHz.
        .rst_n              ( sys_rst_n         ),//复位信号,低电平有效。
        .ddr3_init_done     ( ddr3_init_done    ),//DDR3初始化完成;
        .rfifo_rrst_busy    ( rfifo_rrst_busy   ),//读FIFO的复位状态指示信号;
        .pixel_data         ( pixel_data        ),
        .data_req           ( data_req          ),
        .video_vs           ( video_vs          ),
        //HDMI接口信号
        .tmds_oen           ( tmds_oen          ),
        .tmds_clk_p         ( tmds_clk_p        ),
        .tmds_clk_n         ( tmds_clk_n        ),
        .tmds_data_p        ( tmds_data_p       ),
        .tmds_data_n        ( tmds_data_n       )
    );

5、上板测试

  综合工程之后,下载到开发板实测结果如下图所示;

在这里插入图片描述

图4 开发板测试平台

  由于我手里这颗摄像头年代太过久远,且镜头上有一些杂质,导致摄像头成像比较差。

图5 显示器显示摄像头数据

  可以通过修改配置寄存器的数值,如下图所示,将摄像头改成输出彩条图像。即寄存器8’h0c的最低位改为1,摄像头被设置为输出彩条测试模式。

在这里插入图片描述

图6 修改测试程序

  最终得到的彩条显示结果如下图所示,证明FPGA整个工程的数据处理是没有问题的,后续更换一个摄像头就好了。

在这里插入图片描述

图7 显示器显示摄像头输出的彩条测试图像

  本次工程设计到此结束了,有前文的DDR3设计和HDMI设计作为保障,摄像头采集数据通过HDMI显示在显示器上的工程其实并不复杂。

  积少成多,量变终究引发质变,对于每个细节都要找到问题原因,一起加油!!!

  本工程可以在公众号后台回复“基于OV7725摄像头的HDMI显示”(不包括引号)获取,工程项目使用vivado2021.1在zynq7030上进行开发。


  如果对文章内容理解有疑惑或者对代码不理解,可以在评论区或者后台留言,看到后均会回复!

  如果本文对您有帮助,还请多多点赞👍、评论💬和收藏⭐!您的支持是我更新的最大动力!将持续更新工程!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1515838.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构(二)——线性表(双链表)

2.3.3 双链表 单链表&#xff1a;单链表结点中只有一个指向其后继的指针&#xff0c;使得单链表只能从前往后依次遍历,无法逆向检索&#xff0c;有时候不太方便 双链表的定义&#xff1a;双链表结点中有两个指针prior和next&#xff0c;分别指向其直接前驱和直接后继 表头结点…

5分钟搞懂MySQL存储引擎

文章目录 什么是存储引擎&#x1f44b;&#xff1f;指定存储引擎✅查看mysql提供什么存储引擎查看mysql当前默认的存储引擎修改mysql默认的存储引擎设置表的存储引擎 常用存储引擎&#x1f9f0;InnoDBMyISAMMemoryInnoDB 和 MyISAM的区别 什么是存储引擎&#x1f44b;&#xff…

23万条数据集,可以用来区分钓鱼网站!

文章目录 一、何为钓鱼网站&#xff1f;二、数据集介绍引用数据集数据展示字段解释 三、数据分析数据读取使用ucimlrepo读取数据 四、下载地址 一、何为钓鱼网站&#xff1f; 在数字化时代&#xff0c;网络安全问题日益严重&#xff0c;其中钓鱼网站是一种常见的网络威胁。钓鱼…

基于Java (spring-boot)的进销存管理系统

一、项目介绍 首页&#xff0c;基础信息管理&#xff0c;备忘录&#xff0c;进销管理&#xff0c;仓库管理&#xff0c;系统管理 二、作品包含 三、项目技术 后端语言&#xff1a;Java 项目架构&#xff1a;B/S架构 数据库&#xff1a;MySQL 前端技术&#xff1a;Vue 后端技术&…

【C语言】比较两个字符串大小,strcmp函数

目录 一&#xff0c;strcmp函数 1&#xff0c;strcmp函数 2&#xff0c;函数头文件&#xff1a; 3&#xff0c;函数原型&#xff1a; 4&#xff0c;返回取值&#xff1a; 二&#xff0c;代码实现 三&#xff0c;小结 一&#xff0c;strcmp函数 1&#xff0c;strcmp函数 …

信道模拟器广泛应用于通信产业 我国企业竞争力不断提高

信道模拟器广泛应用于通信产业 我国企业竞争力不断提高 信道模拟器&#xff0c;模拟通信信道受环境因素影响产生各种特征的仪器&#xff0c;主要由接收电路、发射电路、模拟器、主控CPU等组成&#xff0c;可用于外场环境或者实验室环境中。 根据新思界产业研究中心发布的《202…

线性代数 --- 特征值与特征向量(下)

特征值与特征向量 Eigen Values & Eigen Vectors Part III:如何求解特征向量与特征值 The Key Equation 对于一般矩阵A&#xff0c;如何找到他的特征值与特征向量&#xff1f; Step I: Find λ first! 首先&#xff0c;我们有方程&#xff1a; 但这里有两个未知数&…

短视频解析接口分发系统

宝塔面板&#xff1a;Nginx系统 php7.2 Mysql 5.6-5.7 伪静态Thinkphp 上传文件直接访问域名安装即可 可以自备 听说后边要出saas去水印小程序 下载地址&#xff1a;https://pan.xunlei.com/s/VNskSEelfRVIzoSm5P5Rcw34A1?pwdqzhh# 接口演示&#xff1a; 前端演示…

前端入职配置新电脑!!!

前端岗位入职第一天到底应该做些什么呢&#xff1f;又该怎样高效的认识、融入团队&#xff1f;并快速进入工作状态呢&#xff1f;这篇文章就来分享一下&#xff0c;希望对即将走向或初入前端职场的你&#xff0c;能够有所帮助。内含大量链接&#xff0c;欢迎点赞收藏&#xff0…

GPU性能测试中的张量和矩阵运算

正文共&#xff1a;888 字 7 图&#xff0c;预估阅读时间&#xff1a;1 分钟 前面我们使用PyTorch将Tesla M4跑起来之后&#xff08;成了&#xff01;Tesla M4Windows 10AnacondaCUDA 11.8cuDNNPython 3.11&#xff09;&#xff0c;一直有个问题&#xff0c;那就是显存容量的问…

Springboot的配置文件及其优先级

配置文件 内置配置文件 配置文件的作用&#xff1a;修改SpringBoot自动配置的默认值&#xff1b;SpringBoot在底层都给我们自动配置好&#xff1b;SpringBoot使用一个全局的配置文件&#xff0c;配置文件名是固定的&#xff1a; application.propertiesapplication.yml 以上…

javaweb篇请求与相应的参数问题

目录 前言 简单传参设置 get请求无法识别 post请求 简单传参问题无法识别的解决问题 注意事项 改法 实体参数 代码展示 今日分享 前言 友友们&#xff0c;大家好&#xff0c;今天来开荒了,今天介绍的是在进行数据请求以及相应的时候&#xff0c;我们不仅仅只是进入一…

Java SE 抽象类与接口(二):接口(下)

2.5 实现多个接口 在Java语言中&#xff0c;类和类之间是单继承关系&#xff0c;一个类只可以有一个父类&#xff0c;即Java中不支持多继承关系&#xff0c;但是一个类可以实现多个接口&#xff0c;下面通过Animal类来具体说明 class Animal {protected String name;public A…

phpcms上传漏洞

原始漏洞 漏洞原理&#xff1a;我们上传一个zip的压缩包&#xff0c;它会解压然后删除其中不是.jpg .gig .png的文件 function check_dir($dir)&#xff1a;这是一个PHP函数的定义&#xff0c;它接受一个参数 $dir&#xff0c;代表要检查的目录路径。 $handle opendir($dir)…

MySQL学习Day32——数据库备份与恢复

在任何数据库环境中&#xff0c;总会有不确定的意外情况发生&#xff0c;比如例外的停电、计算机系统中的各种软硬件故障、人为破坏、管理员误操作等是不可避免的&#xff0c;这些情况可能会导致数据的丢失、 服务器瘫痪等严重的后果。存在多个服务器时&#xff0c;会出现主从服…

C语言程序环境和预处理Pt.1 - 预处理指令|预处理操作符

电脑所能识别的语言为二进制指令&#xff0c;而我们所写的C语言代码是文本信息。为了能使计算机识别并执行C语言代码&#xff0c;就需要翻译环境&#xff0c;使C语言代码翻译为二进制的指令。 1.按下编译按钮的幕后 - 程序的翻译环境 从C语言源代码到计算机可识别的二进制文件…

【前端】 响应式布局

目录 1.媒体查询 2.BootStrap 2.1BootStrap引入 2.2BootStrap栅格系统 2.3BootStrap手册查询 1.媒体查询 响应式布局&#xff1a;显示区域改变&#xff0c;布局随之改变&#xff0c;即同一套代码适配不同大小的显示器 媒体查询&#xff1a;检测视口宽度&#xff0c;设置差…

案例分析篇12:可靠性设计考点(2024年软考高级系统架构设计师冲刺知识点总结系列文章)

专栏系列文章推荐: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12593400.html 【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例分析篇-…

信号与系统学习笔记——信号的分类

目录 一、确定与随机 二、连续与离散 三、周期与非周期 判断是否为周期函数 离散信号的周期 结论 四、能量与功率 定义 结论 五、因果与反因果 六、阶跃函数 定义 性质 七、冲激函数 定义 重要关系 作用 一、确定与随机 确定信号&#xff1a;可以确定时间函数…

【AIGC】重磅消息,GPT-4.5 Turbo将在6月发布?

2024 年 AI 辅助研发趋势 文章目录 强烈推荐GPT-4.5 Turbo竞争对手Anthropic的Claude 3谷歌的Gemini 1.5 Pro 总结强烈推荐专栏集锦写在最后 强烈推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击…