verilog 语言使用I2C对OV9650摄像头进行初始化
近期做一个小项目,使用的FPGA开发箱是EP1C6Q240C8,利用I2C总线对OV9650摄像头进行配置,I2C仿真的波形正常,但一下到硬件中,就出现问题。问题描述如下:只能发送LUT_INDEX=2时的寄存器地址和数据,也就是说SDA上的数据一直是60 11 81,且起始信号,响应信号,终止信号都正常!望各位大神指教啊!这个问题已经困扰小弟多时了!源代码如下:
module I2C( // Host Side
iCLK,
iRST_N,
//iExposure,
// I2C Side
I2C_SCLK,
I2C_SDAT );
// Host Side
input iCLK;
input iRST_N;
//input iExposure;
// I2C Side
output I2C_SCLK;
inout I2C_SDAT;
// Internal Registers/Wires
reg mI2C_CLK_DIV;
reg mI2C_DATA;
reg mI2C_CTRL_CLK;
reg mI2C_GO;
wire mI2C_END;
wire mI2C_ACK;
reg LUT_DATA;
reg LUT_INDEX;
reg mSetup_ST;
// Clock Setting
parameter CLK_Freq = 48000000; // 50 MHz
parameter I2C_Freq = 20000; // 20 KHz
// LUT Data Number
parameter LUT_SIZE = 5;
///////////////////// I2C Control Clock ////////////////////////
always@(posedge iCLK or negedge iRST_N)
begin
if(!iRST_N)
begin
mI2C_CTRL_CLK <= 0;
mI2C_CLK_DIV <= 0;
end
else
begin
if( mI2C_CLK_DIV < (CLK_Freq/I2C_Freq) )
mI2C_CLK_DIV <= mI2C_CLK_DIV+1;
else
begin
mI2C_CLK_DIV <= 0;
mI2C_CTRL_CLK <= ~mI2C_CTRL_CLK;
end
end
end
////////////////////////////////////////////////////////////////////
I2C_Controller u0 ( .CLOCK(mI2C_CTRL_CLK), // Controller Work Clock
.I2C_SCLK(I2C_SCLK), // I2C CLOCK
.I2C_SDAT(I2C_SDAT), // I2C DATA
.I2C_DATA(mI2C_DATA), // DATA:
.GO(mI2C_GO), // GO transfor
.END(mI2C_END), // END transfor
.ACK(mI2C_ACK), // ACK
.RESET(iRST_N) );
////////////////////////////////////////////////////////////////////
////////////////////// Config Control ////////////////////////////
always@(posedge mI2C_CTRL_CLK or negedge iRST_N)
begin
if(!iRST_N)
begin
LUT_INDEX <= 0;
mSetup_ST <= 0;
mI2C_GO <= 0;
end
else
begin
if(LUT_INDEX<LUT_SIZE)
begin
case(mSetup_ST)
0: begin
mI2C_DATA <= {8'h60,LUT_DATA};
mI2C_GO <= 1;
mSetup_ST <= 1;
end
1: begin
if(mI2C_END)
begin
if(!mI2C_ACK)
mSetup_ST <= 2;
else
mSetup_ST <= 0;
mI2C_GO <= 0;
end
end
2: begin
LUT_INDEX <= LUT_INDEX+1;
mSetup_ST <= 0;
end
endcase
end
end
end
////////////////////////////////////////////////////////////////////
///////////////////// Config Data LUT //////////////////////////
always
begin
case(LUT_INDEX)
0 : LUT_DATA <= 16'h1280;
1 : LUT_DATA <= 16'h1280;
2 : LUT_DATA <= 16'h1181; // Mirror Row and Columns
3 : LUT_DATA <= 16'h6b0a;// Exposure
4 : LUT_DATA <= 16'h3b01;
default:LUT_DATA <= 16'h0000;
endcase
end
////////////////////////////////////////////////////////////////////
endmodule
module I2C_Controller (
CLOCK,
I2C_SCLK,//I2C CLOCK
I2C_SDAT,//I2C DATA
I2C_DATA,//DATA:
GO, //GO transfor
END, //END transfor
W_R, //W_R
ACK, //ACK
RESET,
//TEST
SD_COUNTER,
SDO
);
inputCLOCK;
inputI2C_DATA;
inputGO;
inputRESET;
inputW_R;
inoutI2C_SDAT;
output I2C_SCLK;
output END;
output ACK;
//TEST
output SD_COUNTER;
output SDO;
reg SDO;
reg SCLK;
reg END;
reg SD;
reg SD_COUNTER;
wire I2C_SCLK=SCLK | ( ((SD_COUNTER >= 4) & (SD_COUNTER <=30))? ~CLOCK :0 );
wire I2C_SDAT=SDO?1'bz:0 ;
reg ACK1,ACK2,ACK3;
wire ACK=ACK1 | ACK2 |ACK3;
//--I2C COUNTER
always @(negedge RESET or posedge CLOCK ) begin
if (!RESET) SD_COUNTER=6'b111111;
else begin
if (GO==0)
SD_COUNTER=0;
else
if (SD_COUNTER < 6'b111111) SD_COUNTER=SD_COUNTER+1;
end
end
//----
always @(negedge RESET orposedge CLOCK ) begin
if (!RESET) begin SCLK=1;SDO=1; ACK1=0;ACK2=0;ACK3=0; END=1; end
else
case (SD_COUNTER)
6'd0: begin ACK1=0 ;ACK2=0 ;ACK3=0 ; END=0; SDO=1; SCLK=1;end
//start
6'd1: begin SD=I2C_DATA;SDO=0;end
6'd2: SCLK=0;
//SLAVE ADDR
6'd3: SDO=SD;
6'd4: SDO=SD;
6'd5: SDO=SD;
6'd6: SDO=SD;
6'd7: SDO=SD;
6'd8: SDO=SD;
6'd9: SDO=SD;
6'd10 : SDO=SD;
6'd11 : begin SDO=1'b1;ACK1=I2C_SDAT;end//ACK
//SUB ADDR
6'd12: SDO=SD; //ACK1=I2C_SDAT; end
6'd13: SDO=SD;
6'd14: SDO=SD;
6'd15: SDO=SD;
6'd16: SDO=SD;
6'd17: SDO=SD;
6'd18: SDO=SD;
6'd19: SDO=SD;
6'd20: begin SDO=1'b1;ACK2=I2C_SDAT;end//ACK
//DATA
6'd21: SDO=SD;// ACK2=I2C_SDAT; end
6'd22: SDO=SD;
6'd23: SDO=SD;
6'd24: SDO=SD;
6'd25: SDO=SD;
6'd26: SDO=SD;
6'd27: SDO=SD;
6'd28: SDO=SD;
6'd29: beginSDO=1'b1; ACK3=I2C_SDAT;end//ACK
//stop
6'd30 : begin SDO=1'b0; SCLK=1'b0;end
6'd31 : SCLK=1'b1;
6'd32 : begin SDO=1'b1; END=1; end
endcase
end
endmodule
{:cry:}{:cry:}{:cry:} 有没有人会啊!求指导啊!
I2C_SDAT 这个信号在模块外要直接连到芯片的IO上去,不能用assign语句赋值,因为它是inout型的
检查一下这个信号有没有上拉电阻;
检查一下IIC的地址有没有错;
把这个信号拉高,CMOS去掉,看一下你这个模块是不是可以完部走完 caizijian 发表于 2012-11-3 20:01 static/image/common/back.gif
I2C_SDAT 这个信号在模块外要直接连到芯片的IO上去,不能用assign语句赋值,因为它是inout型的
检查一下这 ...
您好,非常感谢您的回答。可我还是有几个地方不明白!
您说“I2C_SDAT 这个信号在模块外要直接连到芯片的IO上去,不能用assign语句赋值,因为它是inout型的”是指wire I2C_SDAT=SDO?1'bz:0 ;这个语句不对是吗?可不这么写,该如何写啊?
您说“检查一下这个信号有没有上拉电阻;”我们使用的是OV9650摄像头,其内部是有上拉电阻的,我想问一下FPGA端还用加上拉吗?我们使用的FPGA的型号是Cyclone系列的EP1C6Q240C8。
您说“检查一下IIC的地址有没有错;”,IIC地址没有错,OV9650的写地址就是0x60;
您说“把这个信号拉高,CMOS去掉,看一下你这个模块是不是可以完部走完”,我把I2C_SDAT信号拉高了,去掉摄像头,使用示波器观察 I2C_SCLK,其为低电平。当把I2C_SDAT信号拉低,即直接接地,则可以看到 I2C_SCLK输出正常的脉冲,我想这是正常的,因为反应信号就是低电平。
连好摄像头,使用示波器观察I2C_SDAT,I2C_SDAT,看到I2C_SDAT上一直输出60,12,80,即一直输出发送第一发送的寄存器地址和数据,哎!这到底错哪了啊? 那个语句是对的,是你在调用那个模块的时候 .I2C_SDAT(GPIO);
最好在硬件电路上再加一个1K-10K的上拉电阻
没错就可以不管
这些要是没有错 就要看你的寄存器地址和寄存器数据的位宽是16还是8,你是不是有写对
caizijian 发表于 2012-11-7 10:54 static/image/common/back.gif
那个语句是对的,是你在调用那个模块的时候 .I2C_SDAT(GPIO);
最好在硬件电路上再加一个1K-10K的上 ...
寄存器地址和寄存器数据的位宽都是8位,哎!弄了好久还是不好用,现在改用51单片机做驱动了!但是还是很感谢您的回答。
页:
[1]