搜索
bottom↓
回复: 5

verilog 语言使用I2C对OV9650摄像头进行初始化

[复制链接]

出0入0汤圆

发表于 2012-10-30 21:29:58 | 显示全部楼层 |阅读模式
    近期做一个小项目,使用的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        [15:0]        iExposure;
//        I2C Side
output                I2C_SCLK;
inout                I2C_SDAT;
//        Internal Registers/Wires
reg        [15:0]        mI2C_CLK_DIV;
reg        [23:0]        mI2C_DATA;
reg                        mI2C_CTRL_CLK;
reg                        mI2C_GO;
wire                mI2C_END;
wire                mI2C_ACK;
reg        [15:0]        LUT_DATA;
reg        [5:0]        LUT_INDEX;
reg        [3:0]        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:[SLAVE_ADDR,SUB_ADDR,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:[SLAVE_ADDR,SUB_ADDR,DATA]
        GO,      //GO transfor
        END,     //END transfor
        W_R,     //W_R
        ACK,      //ACK
        RESET,
        //TEST
        SD_COUNTER,
        SDO
);
        input  CLOCK;
        input  [23:0]I2C_DATA;       
        input  GO;
        input  RESET;       
        input  W_R;
        inout  I2C_SDAT;       
        output I2C_SCLK;
        output END;       
        output ACK;

//TEST
        output [5:0] SD_COUNTER;
        output SDO;


reg SDO;
reg SCLK;
reg END;
reg [23:0]SD;
reg [5:0]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 or  posedge 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[23];
        6'd4  : SDO=SD[22];
        6'd5  : SDO=SD[21];
        6'd6  : SDO=SD[20];
        6'd7  : SDO=SD[19];
        6'd8  : SDO=SD[18];
        6'd9  : SDO=SD[17];
        6'd10 : SDO=SD[16];       
        6'd11 : begin SDO=1'b1;ACK1=I2C_SDAT;end//ACK

        //SUB ADDR
        6'd12  : SDO=SD[15]; //ACK1=I2C_SDAT; end
        6'd13  : SDO=SD[14];
        6'd14  : SDO=SD[13];
        6'd15  : SDO=SD[12];
        6'd16  : SDO=SD[11];
        6'd17  : SDO=SD[10];
        6'd18  : SDO=SD[9];
        6'd19  : SDO=SD[8];
        6'd20  : begin SDO=1'b1;  ACK2=I2C_SDAT;end//ACK

        //DATA
        6'd21  : SDO=SD[7];// ACK2=I2C_SDAT; end
        6'd22  : SDO=SD[6];
        6'd23  : SDO=SD[5];
        6'd24  : SDO=SD[4];
        6'd25  : SDO=SD[3];
        6'd26  : SDO=SD[2];
        6'd27  : SDO=SD[1];
        6'd28  : SDO=SD[0];
        6'd29  : begin  SDO=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

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

 楼主| 发表于 2012-11-3 09:28:17 | 显示全部楼层
    有没有人会啊!求指导啊!

出0入0汤圆

发表于 2012-11-3 20:01:25 | 显示全部楼层

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

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

出0入0汤圆

 楼主| 发表于 2012-11-5 20:07:50 | 显示全部楼层
caizijian 发表于 2012-11-3 20:01
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,即一直输出发送第一发送的寄存器地址和数据,哎!这到底错哪了啊?

出0入0汤圆

发表于 2012-10-30 21:29:59 | 显示全部楼层
那个语句是对的,是你在调用那个模块的时候 .I2C_SDAT(GPIO[xx]);
最好在硬件电路上再加一个1K-10K的上拉电阻
没错就可以不管

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

出0入0汤圆

 楼主| 发表于 2012-11-8 20:37:33 | 显示全部楼层
caizijian 发表于 2012-11-7 10:54
那个语句是对的,是你在调用那个模块的时候 .I2C_SDAT(GPIO[xx]);
最好在硬件电路上再加一个1K-10K的上 ...

    寄存器地址和寄存器数据的位宽都是8位,哎!弄了好久还是不好用,现在改用51单片机做驱动了!但是还是很感谢您的回答。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 07:25

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表