凌云壮志 发表于 2012-10-30 21:29:58

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

凌云壮志 发表于 2012-11-3 09:28:17

{:cry:}{:cry:}{:cry:}    有没有人会啊!求指导啊!

caizijian 发表于 2012-11-3 20:01:25


I2C_SDAT 这个信号在模块外要直接连到芯片的IO上去,不能用assign语句赋值,因为它是inout型的
检查一下这个信号有没有上拉电阻;
检查一下IIC的地址有没有错;

把这个信号拉高,CMOS去掉,看一下你这个模块是不是可以完部走完

凌云壮志 发表于 2012-11-5 20:07:50

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,即一直输出发送第一发送的寄存器地址和数据,哎!这到底错哪了啊?

caizijian 发表于 2012-10-30 21:29:59

那个语句是对的,是你在调用那个模块的时候 .I2C_SDAT(GPIO);
最好在硬件电路上再加一个1K-10K的上拉电阻
没错就可以不管

这些要是没有错 就要看你的寄存器地址和寄存器数据的位宽是16还是8,你是不是有写对

凌云壮志 发表于 2012-11-8 20:37:33

caizijian 发表于 2012-11-7 10:54 static/image/common/back.gif
那个语句是对的,是你在调用那个模块的时候 .I2C_SDAT(GPIO);
最好在硬件电路上再加一个1K-10K的上 ...

    寄存器地址和寄存器数据的位宽都是8位,哎!弄了好久还是不好用,现在改用51单片机做驱动了!但是还是很感谢您的回答。
页: [1]
查看完整版本: verilog 语言使用I2C对OV9650摄像头进行初始化