您好,欢迎来到61ic! | [登录] [注册] 忘记密码 | 设为首页 帮助
 . 网站首页 . 业界新闻 . 设计中心 . 移动技术 . TI专栏 . ADI专栏 . FPGA专栏 . 代码工厂 . 官方商城 . 
 . 活动专区 . 新品快递 . 解决方案 . 前沿科技 . TI资源 . ADI资源 . FPGA资源 . 下载中心 . 产品展示 . 
加入收藏
付款方式
联系我们
您现在的位置: 61IC电子在线 >> FPGA专栏 >> Altera >> 正文
  [组图]基于FPGA的OV摄像头初始化之SCCB协议的实现           ★★★ 【字体:
基于FPGA的OV摄像头初始化之SCCB协议的实现
作者:佚名    文章来源:本站原创    点击数:    更新时间:2015-4-13    

关于OV系列摄像头的初始化,最主要的还是SCCB协议的编写调试,其实也就是众所周知的IIC协议。下面介绍一下用得最多的SCCB协议2线工作模式。

一.SCCB协议时序

SCCB协议2线工作模式只能工作在只有1个从机挂载下,具有接口SIO_C,SIC_D,也就是IIC的i2c_clk和i2c_sdat。SCCB协议的时序有以下几点需要注意和掌握的:

(1)时钟频率:和业界标准一致,只能工作在400KHz以内。

(2)数据读/写:数据是从高位D7开始到低位D0进行传输的。数据线SIO_D在时钟SIO_C高电平期间读取,在时钟SIO_C低电平期间写入,最佳采样点就是高、低电平期间的中点。换句话说,也就是数据只能在时钟低电平期间变化,在高电平期间不能发生变化。

(3)开始信号:在时钟SIO_C高电平期间,数据线SIO_D由高电平跳变为低电平即表示开始传输,如下图1-1所示:

wps_clip_image-29277

图1-1

(4)结束信号:在时钟SIO_C高电平期间,数据线SIO_D由低电平跳变为高电平即表示开始传输,如下图1-2所示:

wps_clip_image-5884

图1-2

(5)应答信号:在主机(FPGA)发送完8bit数据后,等待从机(OV系列摄像头)应答ACK信号,如正常应答,则主机(FPGA)在第九个时钟SIO_C高电平期间能读回SIO_D低电平信号,即从机(OV系列摄像头)在第九个时钟低电平期间拉低数据线SIO_D。

图1-3就是SCCB传输8bit数据的完整时序图:

wps_clip_image-19739

图1-3

二.OV摄像头的数据传输

首先要说的是,OV的datasheet里规定8bit数据的完整传输过程称为一相,一相包含9bit数据。对OV摄像头寄存器进行配置的写操作需要三相,对其进行读取的读操作需要四相。

先介绍一下配置寄存器的写操作:(最重要也是最有用的)

图2-1就是写操作的三相数据,第一相为OV摄像头设备ID地址0x42,第二相为所要配置的寄存器地址,第三相为所要写入的数据。

wps_clip_image-13307

图2-1

尤其需要重视的是,设备ID地址0x42只占7位,从D7到D1,第一相写设备ID地址的第8位数据是读写控制位R/W,0表示写,1表示读。具体可由下图2-2传输时序图可知:

wps_clip_image-17427

图2-2

第二、第三相数据传输皆和图2-2相似,只是第8位数据为正常数据位。

下面再介绍一下主机读回寄存器数据的读操作:(老实说,此操作对摄像头的初始化没有多大用处,可不毕操作,只是用来测试摄像头是否挂掉)

读操作由二相写操作和二相读操作构成,图2-3为二相写操作,其数据传输时序与三相写操作相同;图2-4为二相读操作,所要注意的是,在读取数据后,主机要在第9个时钟低电平期间拉高数据线SIO_D,发送不应答信号NA,其传输时序图如图2-5所示。

wps_clip_image-25684

图2-3

wps_clip_image-30184 图2-4

wps_clip_image-32343

图2-5

三.Verilog程序的编写

其实SCCB协议的编写还是比较简单的,前提是你十分熟悉它的时序,明白时钟怎么产生,每个时钟需要干什么,数据线什么时候是输入,什么时候是输出。我把像SPI,IIC这样协议的编写划分为2个部分:一个是是时钟及使能信号产生,一个是数据的传输。

(1)SCCB协议时钟及使能信号的产生:时钟信号由计数器分频产生,对主时钟clk = 25MHz进行200分频,时钟i2c_sclk初始为高电平。其中SCCB协议传输启动信号i2c_config_start非常重要,它的开启与闭合能够让每一次的寄存器配置时序都能精准控制,而不至于处于失控造成时钟偏移的状态。由于数据是在高、低电平中点采样最合适,故写使能信号i2c_wen在时钟低电平中点时刻置1使能进行写数据,读使能信号i2c_ren在时钟高电平中点时刻置1使能进行读数据。

此部分代码如下:

//---------------------------i2c_sclk generator--------------------------
reg [11:0] sclk_cnt;
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        begin
            sclk_cnt <= 1'b0;
            i2c_sclk <= 1'b1;   //i2c_clk high level start
        end
    else if(sclk_cnt==12'd99)
        begin
            sclk_cnt <= 1'b0;
            i2c_sclk <= ~i2c_sclk;    //200 frequency division
        end
    else if(i2c_config_start)  //controll the i2c_sclk work
        begin
            sclk_cnt <= sclk_cnt + 1'b1;
            i2c_sclk <= i2c_sclk;
        end
    else
        begin
            sclk_cnt <= 1'b0;
            i2c_sclk <= 1'b1;
        end  
end

//------------------i2c_wen and i2c_ren generator-------------------
wire i2c_wen,i2c_ren;
reg [11:0] en_cnt;
always@(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        en_cnt <= 1'b0;
    else if(en_cnt==12'd199)
        en_cnt <= 1'b0;
    else if(i2c_config_start)   //controll the en_cnt work
        en_cnt <= en_cnt + 1'b1;
    else
        en_cnt <= 1'b0;
end

assign i2c_ren = (en_cnt==12'd49) ? 1'b1:1'b0;  //sclk's high level neutral point: write i2c_config_data
assign i2c_wen = (en_cnt==12'd149) ? 1'b1:1'b0; //sclk's low level neutral point: read i2c_rdata

(2)SCCB协议数据的传输:在时钟i2c_sclk的驱动下,配置数据的传输可用状态机实现,重点在于开始信号,结束信号和等待应答/发出应答这几个状态的实现。其中三态数据线i2c_sdat的控制尤为重要,通过使能信号i2c_en来控制,一定要明白i2c_sdat在主机发送数据给从机的时钟期间是输出,在主机等待从机应答的时钟期间是输入高阻态。

下面给出一相传输的主要代码,其他相的都类似了:

1.开始信号的产生:

//-------------start transmisson--------------------
                6'd0: begin         //start signal
                            if(i2c_config_start & i2c_ren)
                                begin
                                    w_sdat <= 1'b0;
                                    w_state <= w_state + 1'b1;
                                end
                            else
                                begin
                                    i2c_config_done <= 1'b0;
                                    w_sdat <= 1'b1;
                                    i2c_en <= 1'b0;   //write data
                                end
                        end

2.写入8bit数据:

//-------------------write ID_Address----------------------
                6'd1: begin
                            if(i2c_wen)
                                begin
                                    w_sdat <= ID_Add[7];
                                    w_state <= w_state + 1'b1;
                                end
                        end
                6'd2: begin
                            if(i2c_wen)
                                begin
                                    w_sdat <= ID_Add[6];
                                    w_state <= w_state + 1'b1;
                                end
                        end
                6'd3: begin
                            if(i2c_wen)
                                begin
                                    w_sdat <= ID_Add[5];
                                    w_state <= w_state + 1'b1;
                                end
                        end        
                6'd4: begin
                            if(i2c_wen)
                                begin
                                    w_sdat <= ID_Add[4];
                                    w_state <= w_state + 1'b1;
                                end
                        end
                6'd5: begin
                            if(i2c_wen)
                                begin
                                    w_sdat <= ID_Add[3];
                                    w_state <= w_state + 1'b1;
                                end
                        end        
                6'd6: begin
                            if(i2c_wen)
                                begin
                                    w_sdat <= ID_Add[2];
                                    w_state <= w_state + 1'b1;
                                end
                        end    
                6'd7: begin
                            if(i2c_wen)
                                begin
                                    w_sdat <= ID_Add[1];
                                    w_state <= w_state + 1'b1;
                                end
                        end
                6'd8: begin
                            if(i2c_wen)
                                begin
                                    w_sdat <= 1'b0;   //write 
                                    w_state <= w_state + 1'b1;
                                end
                        end

3.写操作等待应答:由于写操作都是写使能信号i2c_wen控制状态跳转的,在等待应答时,需要两个状态来实现,第一个状态等待第九个时钟的低电平到来,释放总线;第二个状态才是等待第九个时钟的高电平到来,三态控制信号i2c_en置1读取应答。我开始调试的时候就是因为没有写第一个状态而直接到了第二个状态,实际上就变成了第八个时钟状态去读取了,导致时序错误,老是读不回ACK。

//-------------waiting for ACK1-------------
                6'd9: begin
                            if(i2c_wen)         //the ninth clock L
                                begin
                                    w_sdat <= 1'b0;  //release the bus
                                    i2c_en <= 1'b0;  //write data
                                    w_state <= w_state + 1'b1;
                                end
                        end
                6'd10: begin         //the ninth clock H
                            if(i2c_ren)
                                begin
                                    i2c_en <= 1'b1;  //read data
                                    ackw1 <= i2c_sdat;   //receive ack 
                                    w_state <= w_state + 1'b1;
                                end
                            else
                                begin
                                    i2c_en <= 1'b1;  //read data
                                    ackw1 <= 1'b1;
                                end
                        end

4.结束信号的产生:

//----------------stop transmisson------------    
                6'd11: begin
                            if(i2c_ren)        //stop signal
                                begin
                                    w_sdat <= 1'b1;
                                    i2c_config_done <= 1'b1;
                                    w_state <= w_state + 1'b1;
                                end
                            else if(i2c_wen)
                                begin
                                    w_sdat <= 1'b0;
                                    i2c_en <= 1'b0;   //write data
                                end
                        end

5.三态信号的控制:

assign i2c_sdat = (i2c_en == 1'b0) ? w_sdat : 1'bz;

四.Mudelsim仿真图

最后来一张SCCB协议的modelsim仿真图:

wps_clip_image-12539

文章录入:admin    责任编辑:admin 
  • 上一篇文章:

  • 下一篇文章: 没有了
  • 发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
    最新热点 最新推荐 相关文章
    FPGA入门学习八大关
    使用低成本FPGA巧妙地扩展微…
    用FPGA和完整的IP解决方案优…
    基于Xilinx FPGA的千兆以太网…
    基于FPGA的DDR内存条的控制研…
    提高FPGA可靠性的个人经验总…
    FPGA晶振害死人
    FPGA:各种电源方案锦集
    FPGA:跨时钟域数据交互
    FPGA异步复位同步释放解析
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)
    站长:61 湘ICP备13001086号-2