基于FPGA的DVP协议实现标准图像数据流转换(OV7670摄像头)

目录

一、什么是DVP?

二、OV7670摄像头的DVP协议时序

三、RTL设计


一、什么是DVP?

DVP(Digital Video Port) 是传统的sensor输出接口,采用并行输出方式,d数据位宽有8bit、10bit、12bit、16bit,是CMOS电平信号(重点是非差分信号),PCLK最大速率为96MHz,接口如下图:

DVPæ¥å£

PCLK:pixel clock ,像素时钟,每个时钟对应一个像素数据;
       HSYNC:horizonal synchronization,行同步信号
       VSYNC:vertical synchronization,帧同步信号;
       DATA:像素数据,视频数据,具体位宽要看ISP是否支持;
       XCLK:或者MCLK,ISP芯片输出给驱动sensor的时钟;
       SCLSDA:IIC用来读写sensor的寄存器,配置sensor。

DVP协议是摄像头中常用的协议,除了DVP协议摄像头中还有其他常用的协议如:MIPI、LVDS等协议。其整体协议时序图如图:

基于FPGA的DVP协议实现标准图像数据流转换(OV7670摄像头)_第1张图片

图中PIXCLK信号即是PCLk信号,FV是帧同步信号,LV是行同步信号,输出的P0~Pn就是像素数据。

二、OV7670摄像头的DVP协议时序

(1)水平时序

基于FPGA的DVP协议实现标准图像数据流转换(OV7670摄像头)_第2张图片

(2)和VGA对应的帧时序

DVP协议和VGA接口协议基本一样,只是VSYNC信号高低电平相反了。还有DVP协议的HREF信号是在HERF为高电平是直接输出像素数据,而VGA接口的HSYNC信号在HSYNC为高时先后输出显示后沿、有效图像数据、显示前沿。

基于FPGA的DVP协议实现标准图像数据流转换(OV7670摄像头)_第3张图片

(3)这里对OV7670摄像头配置输出的是RGB565图像数据,其时序为:

基于FPGA的DVP协议实现标准图像数据流转换(OV7670摄像头)_第4张图片

(4)配置成RGB555和RGB444输出时序如图:

基于FPGA的DVP协议实现标准图像数据流转换(OV7670摄像头)_第5张图片 RGB555
基于FPGA的DVP协议实现标准图像数据流转换(OV7670摄像头)_第6张图片 RGB444

三、RTL设计

从上边所看的时序图可以将DVP协议转换成标准的图像的数据流,代码如下:


// Company  : 
// Engineer : 
// -----------------------------------------------------------------------------
// https://blog.csdn.net/qq_33231534    PHF's CSDN blog
// -----------------------------------------------------------------------------
// Create Date    : 2020-09-24 22:17:57
// Revise Data    : 2020-09-24 22:17:57
// File Name      : ov7670_data_16rgb565.v
// Target Devices : XC7Z015-CLG485-2
// Tool Versions  : Vivado 2019.2
// Revision       : V1.1
// Editor         : sublime text3, tab size (4)
// Description    : DVP协议(digital video port)获取ov7670数据并转换成16位RGB565图像数据


module ov7670_data_16rgb565(
	input				clk				,//输入为摄像头输入时钟pclk 25MHz
	input				rst_n			,//系统复位
	input				vsync			,//场同步信号
	input				href			,//行同步信号
	input	[7:0]		din				,//ov7670摄像头数据输入

	input				init_done		,//ov7670摄像头初始化结束标志

	output	reg[15:0]	data_rgb565		,//转换成16位RGB565图像数据
	output	reg			data_rgb565_vld	 //16位RGB565图像数据有效标志
	);

	reg			vsync_r			;
	reg			href_r			;
	reg	[7:0]	din_r			;

	reg			vsync_r_ff0		;
	reg			vsync_r_ff1		;

	reg			data_start		;
	reg	[3:0]	frame_cnt		;
	reg			frame_vaild		;
	wire		vsync_r_pos		;
	reg			data_en			;
	
	//外部信号打一拍
	always @(posedge clk or negedge rst_n) begin
		if (!rst_n) begin
			vsync_r <= 0;
			href_r <= 0;
			din_r <= 8'd0;
		end
		else begin
			vsync_r <= vsync;
			href_r <= href;
			din_r <= din;
		end
	end

	//场同步信号上升沿检测
	always @(posedge clk or negedge rst_n) begin
		if (!rst_n) begin
			vsync_r_ff0 <= 0;
			vsync_r_ff1 <= 0;
		end
		else begin
			vsync_r_ff0 <= vsync_r;
			vsync_r_ff1 <= vsync_r_ff0;
		end
	end
	assign vsync_r_pos = (vsync_r_ff0 && ~vsync_r_ff1);

	always @(posedge clk or negedge rst_n) begin
		if (!rst_n) begin
			data_start <= 0;
		end
		else if (init_done) begin
			data_start <= 1;
		end
		else begin
			data_start <= data_start;
		end
	end

	always @(posedge clk or negedge rst_n) begin
		if (!rst_n) begin
			frame_cnt <= 0;
		end
		else if (data_start && frame_vaild==0 && vsync_r_pos) begin
			frame_cnt <= frame_cnt + 1'b1;
		end
		else begin
			frame_cnt <= frame_cnt;
		end
	end

	always @(posedge clk or negedge rst_n) begin
		if (!rst_n) begin
			frame_vaild <= 0;
		end
		else if (frame_cnt >= 10) begin
			frame_vaild <= 1;
		end
		else begin
			frame_vaild <= frame_vaild;
		end
	end

	always @(posedge clk or negedge rst_n) begin
		if (!rst_n) begin
			data_en <= 0;
		end
		else if (href_r && frame_vaild) begin
			data_en <= ~data_en;
		end
		else begin
			data_en <= 0;
		end
	end
	always @(posedge clk or negedge rst_n) begin
		if (!rst_n) begin
			data_rgb565_vld <= 0;
		end
		else if (data_en) begin
			data_rgb565_vld <= 1;
		end
		else begin
			data_rgb565_vld <= 0;
		end
	end

	always @(posedge clk or negedge rst_n) begin
		if (!rst_n) begin
			data_rgb565 <= 16'd0;
		end
		else if (data_en) begin
			data_rgb565 <= {data_rgb565[15:8],din_r};
		end
		else begin
			data_rgb565 <= {din_r,data_rgb565[7:0]};
		end
	end

endmodule

 测试代码:


`timescale 1ns/1ns

module ov7670_data_16rgb565_tb (); /* this is automatically generated */

	reg rst_n;
	reg clk;

	localparam clk_period = 20;

	reg        vsync;
	reg        href;
	reg  [7:0] din;
	reg        init_done;
	wire [15:0] data_rgb565;
	wire        data_rgb565_vld;

	ov7670_data_16rgb565 inst_ov7670_data_16rgb565
		(
			.clk             (clk),
			.rst_n           (rst_n),
			.vsync           (vsync),
			.href            (href),
			.din             (din),
			.init_done       (init_done),
			.data_rgb565     (data_rgb565),
			.data_rgb565_vld (data_rgb565_vld)
		);

	initial clk = 1;
	always #(clk_period/2) clk = ~clk;

	initial begin
		#2;
		rst_n = 0;
		vsync = 0;
		href = 0;
		din = 0;
		init_done = 0;
		#(clk_period*20);
		rst_n = 1;
		#(clk_period*20);
		init_done = 1;
		#clk_period;
		init_done = 0;
		#(clk_period*20);

		repeat(12)begin
			#(clk_period*500);
			dvp_data();
		end

		#(clk_period*20);
		$stop;
	end

	task dvp_data;
		integer i,j;
		begin
			vsync = 0;
			#(clk_period*10);
			vsync = 1;
			#(clk_period*10);
			vsync = 0;
			#(clk_period*100);
			for(i=0;i<480;i=i+1)begin
				for(j=0;j<640*2;j=j+1)begin
					href = 1;
					#(clk_period);
					din = din + 1'b1;
				end
				href = 0;
				#(clk_period*100);
			end
			din = 0;
		end
	endtask

endmodule

仿真图如图所示:

(1)传输12帧图像数据

基于FPGA的DVP协议实现标准图像数据流转换(OV7670摄像头)_第7张图片

可以看到,data_rgb565_vld数据有效信号在10帧图像数据后才有输出,这是为了在初始化后图像数据可能会有不稳定情况,因此将前十帧图像丢弃。

(2)1帧图像数据(注意看帧同步信号)

基于FPGA的DVP协议实现标准图像数据流转换(OV7670摄像头)_第8张图片

(3)传输数据部分细节

基于FPGA的DVP协议实现标准图像数据流转换(OV7670摄像头)_第9张图片

 

 

你可能感兴趣的:(FPGA学习,#,5,OV7670摄像头显示,fpga,verilog,dvp,ov7670)