DSP

sccb协议

2019-07-13 16:54发布


1摄像头配置OV7670

摄像头datasheet通过 SCCB 总线控制,可以输出整帧、子采样、取窗口等方式的各种分辨率 8 位影响数据。该产品 VGA 图像最高达到 30 /秒。 640*480分辨率标准的 SCCB 接口 ,采用RGB565格式图像。采用SCCB接口(类似于IIC协议):1SCCB简介SCCB协议有两线也有三线,两线为SIO_CSIO_D,三线为SIO_ESIO_CSIO_D2线的SCCB总线只能是一个主器件对一个从器件控制,但3线SCCB接口可以对多个从器件控制,因此当只有一个从机(slave device)时用两线,有多个从机时用三线。其中SIO_C只能由主机配置(FPGA,SIO_D是一个三态门,双向数据线,既可以由主机控制,也可以由从机控制。 (2)数据传输当写数据到从机被定义为写传输(write transmission),当从机中读数据被定义为读传输 (read transmission),每一个传输都要有开始和结束来释放总线(start + sotp)完整的数据传输包括两个或三个阶段,每一个阶段包含9位数据,其中高8位为所要传输的数据,最低位根据器件所处情况有不同的取值:总结如下:每一个阶段组成:8位数据+don't care/NA如果是主机发送数据,即进行写操作,第九位就为don't care如果是从机发送数据,即为读操作,第九位就为NA.在进行主器件写操作时,全部阶段的最低位均是Dont care bit写操作:三个阶段构成传输的写,每个阶段都为9ID地址(7ID地址+1位读写控制+don't care+ 要写的寄存器地址(8位寄存器地址+don't care+要写入的数据(8位数据+don't care 即写操作有: start + ID地址地址位42寄存器地址 数据 + stop读操作:根据SCCB接口的读操作时序有两个阶段传输组成2个阶段写传输 + 2个阶段读传输,每一相都是9位,具体如下ID地址(8ID地址+1位读写控制+don't care+ FPGA要向从机写入即将要读的寄存器地址(8位寄存器地址+don't careID地址(8ID地址+1位读写控制+don't care+从机向FPGA发送被指定寄存器里面的数据的数据(8位数据+NA)即读操作为:start1+ ID地址(42寄存器地址 +stop1+start 2 +ID地址(43+ 数据 + stop2 (2)数据传输当写数据到从机被定义为写传输(write transmission),当从机中读数据被定义为读传输 (read transmission),每一个传输都要有开始和结束来释放总线(start + sotp)完整的数据传输包括两个或三个阶段,每一个阶段包含9位数据,其中高8位为所要传输的数据,最低位根据器件所处情况有不同的取值:总结如下:每一个阶段组成:8位数据+don't care/NA如果是主机发送数据,即进行写操作,第九位就为don't care如果是从机发送数据,即为读操作,第九位就为NA.在进行主器件写操作时,全部阶段的最低位均是Dont care bitmodule sccb_sender( clk,rst_n,sio_c,sio_d, wr_en,rd_en,write_data,read_data ); input clk,rst_n;//50MH output sio_c; inout sio_d; input wr_en,rd_en; input[7:0]write_data; input[7:0]read_data; reg[7:0]db_r; reg[8:0]cnt_8us;//建立SCCB需要的时钟8us 50*8=400 always@(posedge clk or negedge rst_n) if(!rst_n)cnt_8us<=0; else if(cnt_8us==9'd399)cnt_8us<=0; else cnt_8us<=cnt_8us+1'b1; reg[8:0]cnt; reg[2:0]cnt_delay;//把每个计数周期分为4段,在低电平中间改变数据,在高电平中间采集数据 always@(posedge clk or negedge rst_n) if(!rst_n)cnt_delay<=3'd5; else begin case(cnt) 9'd99 :cnt_delay<=3'd1;//高电平数据中间,用于数据采样 9'd199:cnt_delay<=3'd2;//下降沿 9'd299:cnt_delay<=3'd3;//低电平数据中间,用于数据变化 9'd399:cnt_delay<=3'd0;//上升沿 default:cnt_delay<=3'd5; endcase end `define SIO_C_POS (cnt_delay==3'd0) //SCL上升沿 `define SIO_C_HIG (cnt_delay==3'd1) //SCL高电平中间 `define SIO_C_NEG (cnt_delay==3'd2) //SCL下降沿 `define SIO_C_LOW (cnt_delay==3'd3) //SCL低电平中间 //产生时钟sio_c信号; reg sio_c_r; always@(posedge clk or negedge rst_n) if(!rst_n)sio_c_r<=0; else if(cnt_delay==3'd0)sio_c_r<=1; else if(cnt_delay==3'd2)sio_c_r<=0; assign sio_c=sio_c_r; parameter subaddres=8'h40; parameter WRITE_ADD=8'h42;//写寄存器地址 parameter READ_ADD=8'h43;//读寄存器地址 parameter IDLE=4'd0; parameter START1=4'd1; parameter ADD1=4'd2;//ID addres parameter DC=4'd3;//don`t care 位 parameter ADD2=4'd4;//Subaddres parameter NA=4'd5;//not absolutely位 parameter START2=4'd6; parameter ADD3=4'd7;//WRITE_DATA parameter WDATA_ACK=4'd8;//写DATA 应答位 parameter ADD4=4'd9;//READ_DATA parameter DCB=4'd10;//读DATA 应答位 parameter ADD5=4'd11; parameter RDATA_ACK=4'd12; parameter STOP1=4'd13; parameter STOP2=4'd14; reg[3:0]cstate; reg[3:0]num; reg sio_d_link,sio_d_r; always@(posedge clk or negedge rst_n) if(!rst_n)begin sio_d_link<=0; sio_d_r<=1; cstate<=IDLE; num<=0; end else case(cstate) IDLE:begin sio_d_link<=1'b1; sio_d_r<=1'b1; if(wr_en||rd_en)begin db_r<=WRITE_ADD; cstate<=START1; end else cstate<=IDLE; end START1:begin if(`SIO_C_HIG)begin sio_d_r<=0; sio_d_link<=1'b1; cstate<=ADD1; num<=0; end else cstate<=START1; end ADD1:begin if(`SIO_C_LOW)begin if(num==4'd8)begin sio_d_link<=1'b0;//高阻态 sio_d_r<=1'b1; num<=0; cstate<=DC; end else begin num<=num+1'b1; cstate<=ADD1; case(num) 4'd0:sio_d_r<=db_r[7]; 4'd1:sio_d_r<=db_r[6]; 4'd2:sio_d_r<=db_r[5]; 4'd3:sio_d_r<=db_r[4]; 4'd4:sio_d_r<=db_r[3]; 4'd5:sio_d_r<=db_r[2]; 4'd6:sio_d_r<=db_r[1]; 4'd7:sio_d_r<=db_r[0]; default:; endcase end end else if(`SIO_C_POS)db_r<={db_r[6:0],1'b0};//时序图 器件地址左移一位 else cstate<=ADD1; end DC:begin if(`SIO_C_NEG)begin db_r<=subaddres;//寄存器地址; cstate<=ADD2; end else cstate<=DC; end ADD2:begin if(`SIO_C_LOW)begin if(num==4'd8)begin sio_d_link<=1'b0;//高阻态 sio_d_r<=0; num<=4'd0; cstate<=NA; end else begin sio_d_link<=1'b1; num<=num+1'b1; case(cstate) 4'd0:sio_d_r<=db_r[7]; 4'd1:sio_d_r<=db_r[6]; 4'd2:sio_d_r<=db_r[5]; 4'd3:sio_d_r<=db_r[4]; 4'd4:sio_d_r<=db_r[3]; 4'd5:sio_d_r<=db_r[2]; 4'd6:sio_d_r<=db_r[1]; 4'd7:sio_d_r<=db_r[0]; default:; endcase cstate<=ADD2; end end else if(`SIO_C_POS)db_r<={db_r[6:0],1'b0}; else cstate<=ADD2; end NA:begin if(`SIO_C_NEG)begin if(wr_en)begin cstate<=ADD3; db_r<=write_data; end else if(rd_en)begin cstate<=START2; db_r<=READ_ADD; end end else cstate<=NA; end ADD3:begin if(`SIO_C_LOW)begin if(num==4'd8)begin num<=0; cstate<=WDATA_ACK; sio_d_link<=1'b0; sio_d_r<=1'b1; end else begin num<=num+1'b1; cstate<=ADD3; case(num) 4'd0:sio_d_r<=db_r[7]; 4'd1:sio_d_r<=db_r[6]; 4'd2:sio_d_r<=db_r[5]; 4'd3:sio_d_r<=db_r[4]; 4'd4:sio_d_r<=db_r[3]; 4'd5:sio_d_r<=db_r[2]; 4'd6:sio_d_r<=db_r[1]; 4'd7:sio_d_r<=db_r[0]; default:; endcase end end else if(`SIO_C_POS)db_r<={db_r[6:0],1'b0}; else cstate<=ADD3; end WDATA_ACK:begin if(`SIO_C_NEG)begin cstate<=STOP1; sio_d_link<=1'b0; end else cstate<=WDATA_ACK; end STOP1:begin if(`SIO_C_HIG)begin cstate<=STOP2; sio_d_link<=1'b1; end else if(`SIO_C_LOW)begin sio_d_link<=1'b0; sio_d_r<=1'b0; cstate<=STOP1; end else cstate<=STOP1; end START2:begin if(`SIO_C_HIG)begin sio_d_link<=1'b1; sio_d_r<=1'b0; cstate<=ADD3; end else if(`SIO_C_LOW)begin sio_d_link<=1'b1; sio_d_r<=1'b1; cstate<=START2; end else cstate<=START2; end ADD4:begin if(`SIO_C_LOW)begin if(num==4'd8)begin sio_d_link<=1'b0;//高阻态 sio_d_r<=1'b1; num<=0; cstate<=DCB; end else begin num<=num+1'b1; cstate<=ADD4; case(num) 4'd0:sio_d_r<=db_r[7]; 4'd1:sio_d_r<=db_r[6]; 4'd2:sio_d_r<=db_r[5]; 4'd3:sio_d_r<=db_r[4]; 4'd4:sio_d_r<=db_r[3]; 4'd5:sio_d_r<=db_r[2]; 4'd6:sio_d_r<=db_r[1]; 4'd7:sio_d_r<=db_r[0]; default:; endcase end end else if(`SIO_C_POS)db_r<={db_r[6:0],1'b0};//时序图 器件地址左移一位 else cstate<=ADD4; end DCB:begin if(`SIO_C_NEG)begin db_r<=READ_ADD;//寄存器地址; cstate<=ADD5; end else cstate<=DCB; end ADD5:begin if(`SIO_C_LOW)begin if(num==4'd8)begin sio_d_link<=1'b0;//高阻态 sio_d_r<=1'b1; num<=0; cstate<=RDATA_ACK; end else begin num<=num+1'b1; cstate<=ADD5; case(num) 4'd0:sio_d_r<=db_r[7]; 4'd1:sio_d_r<=db_r[6]; 4'd2:sio_d_r<=db_r[5]; 4'd3:sio_d_r<=db_r[4]; 4'd4:sio_d_r<=db_r[3]; 4'd5:sio_d_r<=db_r[2]; 4'd6:sio_d_r<=db_r[1]; 4'd7:sio_d_r<=db_r[0]; default:; endcase end end else if(`SIO_C_POS)db_r<={db_r[6:0],1'b0};//时序图 器件地址左移一位 else cstate<=ADD5; end RDATA_ACK:begin if(`SIO_C_NEG)begin sio_d_link<=1'b0; cstate<=STOP2; end else cstate<=RDATA_ACK; end STOP2:begin if(`SIO_C_LOW)begin sio_d_link<=1'b0; sio_d_r<=1'b1; end else if(`SIO_C_HIG)begin sio_d_link<=1'b1; end else cstate<=IDLE; end endcase assign sio_d=sio_d_link?sio_d_r:1'bz; endmodule