资讯详情

OV5640摄像头驱动开发讲解

1.引脚

在这里插入图片描述 有的摄像头输出八位像素,有的十位像素。使用时注意筛选。

2.参数

1.最大支持2592x1944像素输出 2.支持8~10位RGB或者RAW输出 3.输入时钟6~27MHZ 4.不同像素的输出速度

像素 刷新率
QSXGA (2592 x 1944) 15FPS
1080p(1920 x 1080) 30FPS
1280 x 960 45FPS
720p(1280 x 720) 60FPS
VGA(640 x 480) 90FPS
QVGA(320 x 240) 120FPS

3.模块划分

3.上电模块

3.1上电过程

DOVDD和AVDD不需要代码控制 使用摄像头时只需要控制PWDN和RESET可以,其他引脚都没有打开。 PWDN在t2时刻拉低,RESETB在t3时拉高,拉高后t四个时间可以开始使用SCCB线传输数据。

3.2上电功能模块和代码

/* 摄像头上电的初始过程 上电时序 初始:pwdn = 1,rst_n = 0;done = 0; 6ms后:pwdn = 0,rst_n = 0; done = 0; 2ms后:pwdn = 0,rst_n = 1; done = 0; 21ms后:pwdn = 0,rst_n = 1; done = 1; */ module power_ctrl(  input wire   clk      , //50MHZ时钟  input wire   rst_n      , ///复位信号   output wire   ov5640_pwdn    , //ov5640的pwdn信号线最初是高的,6ms后拉低   output wire   ov5640_rst_n,    //ov5640的rst_n复位信号线,低电平有效   output wire   power_done      ///标志位上电后一直很高 );  localparam DELAY_6MS  =  30_0000   ; localparam DELAY_2MS  =  10_0000   ; localparam DELAY_21MS  =  105_0000  ;  reg  [18:0]  cnt_6ms       ; reg  [16:0]  cnt_2ms       ; reg  [20:0]  cnt_21ms      ;  always @(posedge clk) begin  if (rst_n == 1'b0) begin   // reset   cnt_6ms <= 'd0;  end  else if (ov5640_pwdn == 1'b1) begin   cnt_6ms <= cnt_6ms   1'b1;  end end  always @(posedge clk) begin  if (rst_n == 1'b0) begin   // reset   cnt_2ms <= 'd0 end else if (ov5640_rst_n == 1'b0 && ov5640_pwdn == 1'b0) begin cnt_2ms <= cnt_2ms + 1'b1; end end always @(posedge clk) begin if (rst_n == 1'b0) begin // reset cnt_21ms <= 'd0; end else if (ov5640_rst_n == 1'b1 & power_done == 1'b0) begin cnt_21ms <= cnt_21ms + 1'b1; end end assign ov5640_pwdn = (cnt_6ms >= DELAY_6MS) ? 1'b0 : 1'b1; //初始为高,6ms后置低 assign ov5640_rst_n = (cnt_2ms >= DELAY_2MS) ? 1'b1 : 1'b0; //初始为低,pwdn拉低后2ms置高 assign power_done = (cnt_21ms >= DELAY_21MS) ? 1'b1 : 1'b0; //初始为低,上电完成后置高 endmodule 

4.SCCB模块

4.1SCCB协议时序

ID Address(W) = 7’h78(低位补0后),在ov5640众多寄存器中,有些寄存器时可改写的,有些是只读的,只有可改写的才能正确输入。 关于SCCB协议可以参考其他文章,这里不详细介绍。在本模块中只用到了SCCB写功能。对SCCB协议精简后构建了以下模块

4.2 SCCB协议部分模块和代码

module SCCB_WR
#(
    parameter   CLK_FREQ   		= 	26'd50_000_000, 	//模块输入的时钟频率
    parameter   SCCB_FREQ   	= 	18'd250_000     	//IIC_SCL的时钟频率
)
(
	input	wire				clk 						,	//系统时钟
	input	wire				rst_n 						,	//复位信号
	input	wire				sccb_exec 					,	//sccb协议传输开始
	input	wire				bit_ctrl 					,	//地址位控制
	input	wire	[15:0]		sccb_addr 					,	//寄存器地址
	input	wire	[ 7:0]		sccb_data_wr 				,	//写数据
	input	wire	[ 6:0]		SLAVE_ADDR 					,	//从机地址

	output	reg 				sccb_done 					,	//sccb协议传输完成
	output	reg					sccb_clk 					,	//sccb模块的工作时钟
	output	reg	 				sio_c 						,	//sccb协议传输时钟
	inout	wire 				sio_d 							//sccb协议数据线
);

parameter CLK_DIVIDE_MAX = (CLK_FREQ / SCCB_FREQ) >> (1'b1 + 2'd2) - 1'b1;	//(SCCB协议的四分频计数最大值)

parameter	st_idle			=		6'b00_0001			;	//初始状态
parameter	st_addr_wr		=		6'b00_0010 			;	//设备地址写
parameter	st_addr_16		=		6'b00_0100 			;	//寄存器地址高八位写入
parameter	st_addr_8 		=		6'b00_1000 			;	//寄存器地址低八位写入
parameter 	st_data_wr		=		6'b01_0000			;	//写数据传输
parameter	st_stop			=		6'b10_0000 			;	//一次通讯结束

reg		[ 5:0]		cur_state								;	//状态机当前状态
reg		[ 5:0]		next_state								;	//状态机下一状态
reg					st_done									;	//状态完成(数据发送完成)
reg		[ 8:0]		clk_divide								;	//模块驱动时钟的分频系数
reg 	[ 7:0]		cnt 									; 	//sccb_clk 计数
reg 				bit_ctrl_reg 							;	//地址位控制寄存
reg 	[ 7:0]		sccb_data_wr_reg 						;	//写数据寄存
reg 	[15:0]		sccb_addr_reg 							;	//寄存器地址寄存
reg 	[ 7:0]		SLAVE_ADDR_reg 							;	//从机设备地址寄存

reg 				sio_d_dir 								;	//sio输入输出控制 高输出,低输入
reg					sio_d_out								;	//sio_d输出信号
wire				sio_d_in 								;	//sio_d输入信号



parameter CLK_DIVIDE = (CLK_FREQ / SCCB_FREQ) >> (1'b1 + 2'd2)	;	//(SCCB协议的四分频)

//三态们输出
assign sio_d = (sio_d_dir == 1'b1) ? sio_d_out : 'dz;
assign sio_d_in = sio_d;

//模块驱动时钟计数器
always @(posedge clk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		// reset
		clk_divide <= 'd0;
	end
	else if (clk_divide == CLK_DIVIDE_MAX) begin
		clk_divide <= 'd0;
	end
	else begin
		clk_divide <= clk_divide + 1'b1;
	end
end

//模块驱动时钟
always @(posedge clk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		// reset
		sccb_clk <= 1'b0;
	end
	else if(clk_divide == CLK_DIVIDE_MAX) begin
		sccb_clk <= ~sccb_clk;
	end
end

//三段式状态机,同步时序描述状态转移
always @(posedge sccb_clk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		// reset
		cur_state <= st_idle;
	end
	else begin
		cur_state <= next_state;
	end
end

//组合逻辑判断状态转移条件
always @(*) begin
	next_state = st_idle;
	case(cur_state)
		st_idle		:	begin 			//初始状态,当传输开始时状态跳转
			if(sccb_exec == 1'b1)begin
				next_state = st_addr_wr;
			end
			else begin
				next_state = st_idle;
			end
		end
		st_addr_wr	:	begin 				//发送设备地址加读
			if(st_done == 1'b1)begin
				if (bit_ctrl == 1'b1)begin
					next_state = st_addr_16;
				end
				else begin
					next_state = st_addr_8;
				end
			end
			else begin
				next_state = st_addr_wr;
			end
		end
		st_addr_16	:	begin 				//发送寄存器地址高八位
			if(st_done == 1'b1)begin
				next_state = st_addr_8;
			end
			else begin
				next_state = st_addr_16;
			end
		end
		st_addr_8 	:	begin 				//发送寄存器地址低八位
			if(st_done == 1'b1)begin
					next_state = st_data_wr;
			end
			else begin
				next_state = st_addr_8; 		//未完成,保持
			end
		end
		st_data_wr 	:	begin
			if(st_done == 1'b1)begin
				next_state = st_stop;
			end
			else begin
				next_state = st_data_wr;
			end
		end
		st_stop 	:	begin
			if(st_done == 1'b1)begin
				next_state = st_idle;
			end
			else begin
				next_state = st_stop;
			end
		end
		default 	:	next_state = st_idle;
	endcase
end

//时序电路描述状态输出
always @(posedge sccb_clk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		// reset
		cnt 				<= 	'd0 			;	//传输寄存器
		st_done 			<=	'd0 			;	//传输完成标志位
		sio_c 				<= 	'd1				;	//sio时钟线
		sio_d_out 			<= 	'd1 			; 	//sio_d输出
		sio_d_dir 			<=	'd1 			;	//sio_d输入输出判断
	
		bit_ctrl_reg 		<=	bit_ctrl 		; 	//寄存器地址位寄存
		sccb_addr_reg 		<= 	sccb_addr 		; 	//寄存器地址寄存
		sccb_data_wr_reg 	<=	sccb_data_wr 	;	//写数据寄存
		SLAVE_ADDR_reg 		<=  SLAVE_ADDR 		; 	//从机地址寄存
	end
	else  begin
		st_done <= 1'b0;
		cnt <=	cnt + 1'b1;
		case(cur_state)
		st_idle 	:	begin
			cnt 				<= 	'd0 			;	//传输寄存器
			st_done 			<=	'd0 			;	//传输完成标志位
			sio_c 				<= 	'd1				;	//sio时钟线,默认高电平
			sio_d_out 			<= 	'd1 			; 	//sio_d输出,默认高电平
			sio_d_dir 			<=	'd1 			;	//sio_d输入输出判断
			sccb_done			<=	'd0;
			if(sccb_exec == 1'b1)begin
				bit_ctrl_reg 		<=	bit_ctrl 		; 	//寄存器地址位寄存
				sccb_addr_reg 		<= 	sccb_addr 		; 	//寄存器地址寄存
				sccb_data_wr_reg 	<=	sccb_data_wr 	;	//写数据寄存
				SLAVE_ADDR_reg 		<=  SLAVE_ADDR 		; 	//从机地址寄存 
			end	
		end
		st_addr_wr 	:	begin 							//发送起始信号设备地址加写标志
			cnt <= cnt + 1'b1;
				case(cnt)
				1 :	sio_d_out 	<=  1'b0;				
				3 :sio_c 		<=  1'b0; 
				4 :sio_d_out 	<=  SLAVE_ADDR_reg[7];
				5 :sio_c 		<=  1'b1;
				7 :sio_c		<=  1'b0;
				8 :sio_d_out 	<=  SLAVE_ADDR_reg[6];
				9 :sio_c 		<=  1'b1;
				11:sio_c 		<=  1'b0;
				12:sio_d_out	<=  SLAVE_ADDR_reg[5];
				13:sio_c 		<=  1'b1;
				15:sio_c		<=  1'b0;
				16:sio_d_out 	<=  SLAVE_ADDR_reg[4];
				17:sio_c 		<=  1'b1;
				19:sio_c		<=  1'b0;
				20:sio_d_out 	<=  SLAVE_ADDR_reg[3];
				21:sio_c 		<=  1'b1;
				23:sio_c		<=  1'b0;
				24:sio_d_out 	<=  SLAVE_ADDR_reg[2];
				25:sio_c 		<=  1'b1;
				27:sio_c		<=  1'b0;
				28:sio_d_out 	<=  SLAVE_ADDR_reg[1];
				29:sio_c 		<=  1'b1;
				31:sio_c		<=  1'b0;
				32:sio_d_out 	<=  SLAVE_ADDR_reg[0];
				33:sio_c 		<=  1'b1;
				35:sio_c		<=  1'b0;
				36:	begin
					sio_d_dir 	<=  1'b0;
					sio_d_out   <=  1'b1;
				end 
				37:sio_c 		<=  1'b1;
				38: begin 					//sccb的应答标志位不在乎
					st_done <= 1'b1;
					//if(sccb_d_in == 1'b1)
				end
				39:	begin 
					sio_c		<=  1'b0;
					cnt 		<= 	'd0;
				end	
				default 	: 	;
				endcase							
		end
		st_addr_16 	:	begin
			cnt <= cnt + 1'b1;
				case(cnt)
				0 :	begin
					sio_d_out 	<=	sccb_addr_reg[15];
					sio_d_dir 	<=  1'b1;
				end					
				1 :sio_c 		<=	1'b1;
				3 :sio_c 	 	<=  1'b0;
				4 :sio_d_out 	<=	sccb_addr_reg[14];
				5 :sio_c 		<=  1'b1;
				7 :sio_c 	 	<=  1'b0;
				8 :sio_d_out 	<=	sccb_addr_reg[13];
				9 :sio_c 		<=	1'b1;
				11:sio_c 	 	<=  1'b0;
				12:sio_d_out 	<=	sccb_addr_reg[12];
				13:sio_c 		<=  1'b1;
				15:sio_c 	 	<=  1'b0;
				16:sio_d_out 	<=	sccb_addr_reg[11];
				17:sio_c 		<=	1'b1;
				19:sio_c 	 	<=  1'b0;
				20:sio_d_out 	<=	sccb_addr_reg[10];
				21:sio_c 		<=  1'b1;
				23:sio_c 	 	<=  1'b0;
				24:sio_d_out 	<=	sccb_addr_reg[9];
				25:sio_c 		<=	1'b1;
				27:sio_c 	 	<=  1'b0;
				28:sio_d_out 	<=	sccb_addr_reg[8];
				29:sio_c 		<=  1'b1;
				31:sio_c 	 	<=  1'b0;
				32:begin
					sio_d_dir <= 1'b0;
					sio_d_out <= 1'b1;
				end
				33:sio_c 		<=	1'b1;
				34:st_done 		<= 	1'b1;
				35:	begin
					sio_c 		<= 	1'b0;
					cnt 		<= 'd0;
				end
										
				default 	: 	;
				endcase							
		end
		st_addr_8 	:	begin
			cnt <= cnt + 1'b1;
				case(cnt)
				0 :	begin
					sio_d_out 	<=	sccb_addr_reg[7];
					sio_d_dir 	<= 	1'b1;
				end 
				1 :sio_c 		<=	1'b1;
				3 :sio_c 	 	<=  1'b0;
				4 :sio_d_out 	<=	sccb_addr_reg[6];
				5 :sio_c 		<=  1'b1;
				7 :sio_c 	 	<=  1'b0;
				8 :sio_d_out 	<=	sccb_addr_reg[5];
				9 :sio_c 		<=	1'b1;
				11:sio_c 	 	<=  1'b0;
				12:sio_d_out 	<=	sccb_addr_reg[4];
				13:sio_c 		<=  1'b1;
				15:sio_c 	 	<=  1'b0;
				16:sio_d_out 	<=	sccb_addr_reg[3];
				17:sio_c 		<=	1'b1;
				19:sio_c 	 	<=  1'b0;
				20:sio_d_out 	<=	sccb_addr_reg[2];
				21:sio_c 		<=  1'b1;
				23:sio_c 	 	<=  1'b0;
				24:sio_d_out 	<=	sccb_addr_reg[1];
				25:sio_c 		<=	1'b1;
				27:sio_c 	 	<=  1'b0;
				28:sio_d_out 	<=	sccb_addr_reg[0];
				29:sio_c 		<=  1'b1;
				31:sio_c 	 	<=  1'b0;
				32:begin
					sio_d_dir <= 1'b0;
					sio_d_out <= 1'b1;
				end
				33:sio_c 		<=	1'b1;
				34:st_done 		<= 	1'b1;
				35:	begin
					sio_c 		<= 	1'b0;
					cnt 		<=  'd0;
				end
										
				default 	: 	;
				endcase							
		end
			st_data_wr 	:	begin
			cnt <= cnt + 1'b1;
				case(cnt)
					0 :begin
						sio_d_out 	<=	sccb_data_wr_reg[7];
						sio_d_dir 	<=  1'b1;
					end 
					1 :sio_c 		<=	1'b1;
					3 :sio_c 	 	<=  1'b0;
					4 :sio_d_out 	<=	sccb_data_wr_reg[6];
					5 :sio_c 		<=  1'b1;
					7 :sio_c 	 	<=  1'b0;
					8 :sio_d_out 	<=	sccb_data_wr_reg[5];
					9 :sio_c 		<=	1'b1;
					11:sio_c 	 	<=  1'b0;
					12:sio_d_out 	<=	sccb_data_wr_reg[4];
					13:sio_c 		<=  1'b1;
					15:sio_c 	 	<=  1'b0;
					16:sio_d_out 	<=	sccb_data_wr_reg[3];
					17:sio_c 		<=	1'b1;
					19:sio_c 	 	<=  1'b0;
					20:sio_d_out 	<=	sccb_data_wr_reg[2];
					21:sio_c 		<=  1'b1;
					23:sio_c 	 	<=  1'b0;
					24:sio_d_out 	<=	sccb_data_wr_reg[1];
					25:sio_c 		<=	1'b1;
					27:sio_c 	 	<=  1'b0;
					28:sio_d_out 	<=	sccb_data_wr_reg[0];
					29:sio_c 		<=  1'b1;
					31:sio_c 	 	<=  1'b0;
					32:begin
						sio_d_dir <= 1'b0;
						sio_d_out <= 1'b1;
					end
					33:sio_c 		<=	1'b1;
					34:st_done 		<= 	1'b1;
					35:	begin
						sio_c 		<= 	1'b0;
						cnt 		<= 	'd0;
					end
											
					default 	: 	;
				endcase							
			end
		st_stop 	:	begin
			cnt 	<=	cnt + 1'b1;
			case(cnt)
				0 :	begin
					sio_d_out 	<= 	1'b0;
					sio_d_dir 	<=	1'b1;
				end
				
				1 :sio_c 		<=	1'b1;
				4 :sio_d_out	<=	1'b1;
				14:	begin
					sccb_done 	<=	1'b1;
					st_done 	<=	1'b1;
				end					
				15:	cnt 			<=	'd0;
				default  :	;
			endcase
		end
		endcase
	end
end
endmodule

5.寄存器配置模块

OV5640内部有许多的变量需要配置,如输出格式,像素大小等。 该模块内部有一块rom,用来存储寄存器的地址和参数,当摄像头上电完成时开始通过SCCB模块向ov5640内部寄存器写入参数。 ov5640关键参数和地址 开窗:摄像头物理像素工作区域:水平0-2591,竖直0-1943,地址0x3800到0x3807。两个地址标志一个值。 平移:将开窗平移,在不移动摄像头的前提下改变拍摄位置。地址0x3910到0x3813。这里只的数据代表的是偏移量。偏移量的大小值是基于 ISP 输入窗口的起始地址的增量。 输出窗口的大小:最终输出的像素大小。地址0x3808到0x380B。

module sccb_ov5640_cfg
//========================< 参数 >==========================================
#(
parameter REG_NUM           = 240                   , //寄存器个数
parameter CMOS_H_PIXEL      = 12'd1024              , //CMOS水平方向像素个数
parameter CMOS_V_PIXEL      = 12'd768               , //CMOS垂直方向像素个数
parameter TOTAL_H_PIXEL     = CMOS_H_PIXEL+13'd1216 , //水平总像素大小
parameter TOTAL_V_PIXEL     = CMOS_V_PIXEL+13'd504    //垂直总像素大小
)
//========================< 端口 >==========================================
(
input   wire                clk                     , //时钟,1Mhz
input   wire                rst_n                   , //复位,低电平有效
input   wire                sccb_vld              	, //SCCB配置有效信号
input   wire                sccb_done               , //SCCB寄存器配置完成信号
output  reg                 sccb_en                 , //SCCB触发执行信号 
output  reg     [23:0]      sccb_data               , //SCCB要配置的地址与数据(高16位地址,低8位数据)
output  reg                 sccb_cfg_done             //SCCB全部寄存器配置完成信号
);
//========================< 信号 >==========================================
reg                  

标签: d142对射式光电传感器h60固态继电器

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

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