zoukankan      html  css  js  c++  java
  • 协议——SCCB与IIC的区别

      SCCB(Serial Camera Control Bus,串行摄像头控制总线)是由OV(OmniVision的简称)公司定义和发展的三线式串行总线,该总线控制着摄像头大部分的功能,包括图像数据格式、分辨率以及图像处理参数等。结构框图如下所示:

      OV公司为了减少传感器引脚的封装,现在SCCB总线大多采用两线式接口总线。OV7725使用的是两线式接口总线,该接口总线包括SIO_C串行时钟输入线和SIO_D串行双向数据线,分别相当于IIC协议的SCL信号线和SDA信号线。SIO_C的最小时间为10us,即最大频率为100K。一般来说,100K-400K之间都可以。

     

       由此可见,SCCB就是改编版的IIC,完全可以按照IIC来理解,下面仔细讲解SCCB的时序以及和IIC的不同之处。

    一、SCCB起始和结束(与IIC完全一致)

      起始:SIO_C为高时,SIO_D由高拉低。
      停止:SIO_C为高时,SIO_D由低拉高
     

    二、SCCB写(与IIC完全一致)

      ID Address(W)里面就已经包括进了IIC中的“读写控制位”,所以没有额外写出。

      即:start + phase_1 + phase_2 + phase_3 + stop

      “X”的意思是“don't care”,该位是由从机发出应答信号来响应主机表示当前ID Address、Sub-address和Write Data是否传输完成,但是从机有可能不发出应答信号,因此主机(此处指FPGA)可不用判断此处是否有应答,直接默认当前传输完成即可。“X”即IIC中的ACK应答位。

    三、SCCB读

      数据手册中的SCCB读只写了上图的Phase3和Phase4,实际上它是和Phase1和Phase2联系在一起的。SCCB不支持连续读,Phase4的主机应答位必须为NA(no ack),即为1,所以SCCB读其实就专指单次读,和IIC单次读几乎一样。

      区别就一点:在IIC读传输协议中,写完寄存器地址后会有restart即重复开始的操作;而SCCB读传输协议中没有重复开始的概念,在写完寄存器地址后,需发起总线停止信号。

      即:start_1 + phase_1 + phase_2 + stop_1 + start_2 + phase_3 + phase_4 + stop_2

    四、SCCB和IIC的区别

      1.SCCB的应答位称为X,表示“don't care”,而IIC应答位称为ACK。

        2.SCCB只能单次读,而IIC除了单次读还支持连续读。

      3.SCCB读操作中间有stop,而IIC读操作中间可以有stop也可以不需要stop,具体表现如下

    SCCB读:start_1 + phase_1 + phase_2 + stop_1 + start_2 + phase_3 + phase_4 + stop_2
     IIC读:start_1 + phase_1 + phase_2 +        + start_2 + phase_3 + phase_4 + stop_2

      除去上面三点,SCCB和IIC再无区别,因此如果只需要配置寄存器(只用到写),可以直接拿IIC的时序来当做SCCB用,如果需要读,读操作中间必须有一个stop。

     五、SCCB控制器Verilog代码

      1 //**************************************************************************
      2 // *** 名称 : sccb.v
      3 // *** 作者 : xianyu_FPGA
      4 // *** 博客 : https://www.cnblogs.com/xianyufpga/
      5 // *** 日期 : 2019-08-10
      6 // *** 描述 : SCCB控制器,只支持写
      7 //**************************************************************************
      8 
      9 module sccb
     10 //========================< 参数 >==========================================
     11 #(
     12 parameter DEVICE_ID         = 8'b01010000           , //器件ID
     13 parameter CLK               = 26'd50_000_000        , //本模块的时钟频率
     14 parameter SCL               = 18'd250_000             //输出的SCL时钟频率
     15 )
     16 //========================< 端口 >==========================================
     17 (
     18 input                       clk                     , //时钟
     19 input                       rst_n                   , //复位,低电平有效
     20 //SCCB control -------------------------------------- 
     21 input                       sccb_en                 , //SCCB触发信号
     22 input                       addr16_en               , //16位地址使能
     23 input                       addr8_en                , //8位地址使能
     24 //SCCB input ---------------------------------------- 
     25 input        [15:0]         sccb_addr               , //SCCB器件内地址
     26 input        [ 7:0]         sccb_data               , //SCCB要写的数据
     27 //SCCB output --------------------------------------- 
     28 output  reg                 sccb_done               , //SCCB一次操作完成
     29 output  reg                 sccb_scl                , //SCCB的SCL时钟信号
     30 inout                       sccb_sda                , //SCCB的SDA数据信号
     31 //dri_clk ------------------------------------------- 
     32 output  reg                 sccb_dri_clk              //驱动SCCB操作的驱动时钟,1Mhz
     33 );
     34 //========================< 状态机参数 >====================================
     35 localparam  IDLE            = 6'b00_0001            ; //空闲状态
     36 localparam  DEVICE          = 6'b00_0010            ; //写器件地址
     37 localparam  ADDR_16         = 6'b00_0100            ; //写字地址高8位
     38 localparam  ADDR_8          = 6'b00_1000            ; //写字地址低8位
     39 localparam  DATA            = 6'b01_0000            ; //写数据
     40 localparam  STOP            = 6'b10_0000            ; //结束
     41 //========================< 信号 >==========================================
     42 reg                         sda_dir                 ; //SCCB数据(SDA)方向控制
     43 reg                         sda_out                 ; //SDA输出信号
     44 reg                         state_done              ; //状态结束
     45 reg    [ 6:0]               cnt                     ; //计数
     46 reg    [ 7:0]               state_c                 ; //状态机当前状态
     47 reg    [ 7:0]               state_n                 ; //状态机下一状态
     48 reg    [15:0]               sccb_addr_t             ; //地址寄存
     49 reg    [ 7:0]               sccb_data_t             ; //数据寄存
     50 reg    [ 9:0]               clk_cnt                 ; //分频时钟计数
     51 wire   [ 8:0]               clk_divide              ; //模块驱动时钟的分频系数
     52 
     53 //==========================================================================
     54 //==    sda控制
     55 //==========================================================================
     56 assign  sccb_sda = sda_dir ?  sda_out : 1'bz;         //SDA数据输出或高阻
     57 
     58 //==========================================================================
     59 //==     生成SCL的4倍时钟来驱动后面SCCB的操作,生成1Mhz的sccb_dri_clk
     60 //==========================================================================
     61 assign  clk_divide = (CLK/SCL) >> 3;                  // >>3即除以8
     62 
     63 always @(posedge clk or negedge rst_n) begin
     64     if(!rst_n) begin
     65         sccb_dri_clk <=  1'b1;
     66         clk_cnt <= 10'd0;
     67     end
     68     else if(clk_cnt == clk_divide - 1'd1) begin
     69         clk_cnt <= 10'd0;
     70         sccb_dri_clk <= ~sccb_dri_clk;
     71     end
     72     else
     73         clk_cnt <= clk_cnt + 1'b1;
     74 end
     75 
     76 //==========================================================================
     77 //==    状态机
     78 //==========================================================================
     79 always @(posedge sccb_dri_clk or negedge rst_n) begin
     80     if(!rst_n)
     81         state_c <= IDLE;
     82     else
     83         state_c <= state_n;
     84 end
     85 
     86 always @(*) begin
     87     case(state_c)
     88         IDLE: begin                             //空闲状态
     89            if(sccb_en)
     90                state_n = DEVICE;
     91            else
     92                state_n = IDLE;
     93         end
     94         DEVICE: begin                           //写器件ID
     95             if(state_done) begin
     96                 if(addr16_en)
     97                    state_n = ADDR_16;
     98                 else if(addr8_en)
     99                    state_n = ADDR_8 ;
    100             end
    101             else
    102                 state_n = DEVICE;
    103         end
    104         ADDR_16: begin                          //写地址高8位
    105             if(state_done)
    106                 state_n = ADDR_8;
    107             else
    108                 state_n = ADDR_16;
    109         end
    110         ADDR_8: begin                           //写地址低8位
    111             if(state_done)
    112                 state_n = DATA;
    113             else
    114                 state_n = ADDR_8;
    115         end
    116         DATA: begin                             //写数据
    117             if(state_done)
    118                 state_n = STOP;
    119             else
    120                 state_n = DATA;
    121         end
    122         STOP: begin                             //结束
    123             if(state_done)
    124                 state_n = IDLE;
    125             else
    126                 state_n = STOP ;
    127         end
    128         default:state_n= IDLE;
    129     endcase
    130 end
    131 
    132 //==========================================================================
    133 //==    设计各路信号
    134 //==========================================================================
    135 always @(posedge sccb_dri_clk or negedge rst_n) begin
    136     if(!rst_n) begin
    137         sccb_scl    <= 1'b1;
    138         sda_out     <= 1'b1;
    139         sda_dir     <= 1'b1;
    140         sccb_done   <= 1'b0;
    141         cnt         <= 1'b0;
    142         state_done  <= 1'b0;
    143         sccb_addr_t <= 1'b0;
    144         sccb_data_t <= 1'b0;
    145     end
    146     else begin
    147         state_done  <= 1'b0 ;
    148         cnt         <= cnt + 1'b1 ;
    149         case(state_c)
    150             //--------------------------------------------------- 空闲状态
    151             IDLE: begin
    152                     sccb_scl  <= 1'b1;
    153                     sda_out   <= 1'b1;
    154                     sda_dir   <= 1'b1;
    155                     sccb_done <= 1'b0;
    156                     cnt       <= 7'b0;
    157                     if(sccb_en) begin
    158                         sccb_addr_t <= sccb_addr;
    159                         sccb_data_t <= sccb_data;
    160                     end
    161             end
    162             //--------------------------------------------------- 写器件ID
    163             DEVICE: begin
    164                 case(cnt)
    165                     7'd1 : sda_out  <= 1'b0;
    166                     7'd3 : sccb_scl <= 1'b0;
    167                     7'd4 : sda_out  <= DEVICE_ID[7];
    168                     7'd5 : sccb_scl <= 1'b1;
    169                     7'd7 : sccb_scl <= 1'b0;
    170                     7'd8 : sda_out  <= DEVICE_ID[6];
    171                     7'd9 : sccb_scl <= 1'b1;
    172                     7'd11: sccb_scl <= 1'b0;
    173                     7'd12: sda_out  <= DEVICE_ID[5];
    174                     7'd13: sccb_scl <= 1'b1;
    175                     7'd15: sccb_scl <= 1'b0;
    176                     7'd16: sda_out  <= DEVICE_ID[4];
    177                     7'd17: sccb_scl <= 1'b1;
    178                     7'd19: sccb_scl <= 1'b0;
    179                     7'd20: sda_out  <= DEVICE_ID[3];
    180                     7'd21: sccb_scl <= 1'b1;
    181                     7'd23: sccb_scl <= 1'b0;
    182                     7'd24: sda_out  <= DEVICE_ID[2];
    183                     7'd25: sccb_scl <= 1'b1;
    184                     7'd27: sccb_scl <= 1'b0;
    185                     7'd28: sda_out  <= DEVICE_ID[1];
    186                     7'd29: sccb_scl <= 1'b1;
    187                     7'd31: sccb_scl <= 1'b0;
    188                     7'd32: sda_out  <= DEVICE_ID[0];
    189                     7'd33: sccb_scl <= 1'b1;
    190                     7'd35: sccb_scl <= 1'b0;
    191                     7'd36: begin
    192                             sda_dir <= 1'b0;    //从机应答
    193                             sda_out <= 1'b1;
    194                     end
    195                     7'd37: sccb_scl <= 1'b1;
    196                     7'd38: state_done <= 1'b1;  //状态结束
    197                     7'd39: begin
    198                             sccb_scl <= 1'b0;
    199                             cnt <= 1'b0;
    200                     end
    201                     default :  ;
    202                 endcase
    203             end
    204             //--------------------------------------------------- 写字地址高8位
    205             ADDR_16: begin
    206                 case(cnt)
    207                     7'd0 : begin
    208                             sda_dir <= 1'b1 ;
    209                             sda_out <= sccb_addr_t[15];
    210                     end
    211                     7'd1 : sccb_scl <= 1'b1;
    212                     7'd3 : sccb_scl <= 1'b0;
    213                     7'd4 : sda_out  <= sccb_addr_t[14];
    214                     7'd5 : sccb_scl <= 1'b1;
    215                     7'd7 : sccb_scl <= 1'b0;
    216                     7'd8 : sda_out  <= sccb_addr_t[13];
    217                     7'd9 : sccb_scl <= 1'b1;
    218                     7'd11: sccb_scl <= 1'b0;
    219                     7'd12: sda_out  <= sccb_addr_t[12];
    220                     7'd13: sccb_scl <= 1'b1;
    221                     7'd15: sccb_scl <= 1'b0;
    222                     7'd16: sda_out  <= sccb_addr_t[11];
    223                     7'd17: sccb_scl <= 1'b1;
    224                     7'd19: sccb_scl <= 1'b0;
    225                     7'd20: sda_out  <= sccb_addr_t[10];
    226                     7'd21: sccb_scl <= 1'b1;
    227                     7'd23: sccb_scl <= 1'b0;
    228                     7'd24: sda_out  <= sccb_addr_t[9];
    229                     7'd25: sccb_scl <= 1'b1;
    230                     7'd27: sccb_scl <= 1'b0;
    231                     7'd28: sda_out  <= sccb_addr_t[8];
    232                     7'd29: sccb_scl <= 1'b1;
    233                     7'd31: sccb_scl <= 1'b0;
    234                     7'd32: begin
    235                            sda_dir  <= 1'b0;    //从机应答
    236                            sda_out  <= 1'b1;
    237                     end
    238                     7'd33: sccb_scl <= 1'b1;
    239                     7'd34: state_done <= 1'b1;  //状态结束
    240                     7'd35: begin
    241                            sccb_scl <= 1'b0;
    242                            cnt <= 1'b0;
    243                     end
    244                     default :  ;
    245                 endcase
    246             end
    247             //--------------------------------------------------- 写字地址低8位
    248             ADDR_8: begin
    249                 case(cnt)
    250                     7'd0: begin
    251                             sda_dir <= 1'b1 ;
    252                             sda_out <= sccb_addr_t[7];
    253                     end
    254                     7'd1 : sccb_scl <= 1'b1;
    255                     7'd3 : sccb_scl <= 1'b0;
    256                     7'd4 : sda_out  <= sccb_addr_t[6];
    257                     7'd5 : sccb_scl <= 1'b1;
    258                     7'd7 : sccb_scl <= 1'b0;
    259                     7'd8 : sda_out  <= sccb_addr_t[5];
    260                     7'd9 : sccb_scl <= 1'b1;
    261                     7'd11: sccb_scl <= 1'b0;
    262                     7'd12: sda_out  <= sccb_addr_t[4];
    263                     7'd13: sccb_scl <= 1'b1;
    264                     7'd15: sccb_scl <= 1'b0;
    265                     7'd16: sda_out  <= sccb_addr_t[3];
    266                     7'd17: sccb_scl <= 1'b1;
    267                     7'd19: sccb_scl <= 1'b0;
    268                     7'd20: sda_out  <= sccb_addr_t[2];
    269                     7'd21: sccb_scl <= 1'b1;
    270                     7'd23: sccb_scl <= 1'b0;
    271                     7'd24: sda_out  <= sccb_addr_t[1];
    272                     7'd25: sccb_scl <= 1'b1;
    273                     7'd27: sccb_scl <= 1'b0;
    274                     7'd28: sda_out  <= sccb_addr_t[0];
    275                     7'd29: sccb_scl <= 1'b1;
    276                     7'd31: sccb_scl <= 1'b0;
    277                     7'd32: begin
    278                            sda_dir  <= 1'b0;    //从机应答
    279                            sda_out  <= 1'b1;
    280                     end
    281                     7'd33: sccb_scl <= 1'b1;
    282                     7'd34: state_done <= 1'b1;  //状态结束
    283                     7'd35: begin
    284                            sccb_scl <= 1'b0;
    285                            cnt <= 1'b0;
    286                     end
    287                     default :  ;
    288                 endcase
    289             end
    290             //--------------------------------------------------- 写数据
    291             DATA: begin
    292                 case(cnt)
    293                     7'd0: begin
    294                             sda_out <= sccb_data_t[7];
    295                             sda_dir <= 1'b1;
    296                     end
    297                     7'd1 : sccb_scl <= 1'b1;
    298                     7'd3 : sccb_scl <= 1'b0;
    299                     7'd4 : sda_out  <= sccb_data_t[6];
    300                     7'd5 : sccb_scl <= 1'b1;
    301                     7'd7 : sccb_scl <= 1'b0;
    302                     7'd8 : sda_out  <= sccb_data_t[5];
    303                     7'd9 : sccb_scl <= 1'b1;
    304                     7'd11: sccb_scl <= 1'b0;
    305                     7'd12: sda_out  <= sccb_data_t[4];
    306                     7'd13: sccb_scl <= 1'b1;
    307                     7'd15: sccb_scl <= 1'b0;
    308                     7'd16: sda_out  <= sccb_data_t[3];
    309                     7'd17: sccb_scl <= 1'b1;
    310                     7'd19: sccb_scl <= 1'b0;
    311                     7'd20: sda_out  <= sccb_data_t[2];
    312                     7'd21: sccb_scl <= 1'b1;
    313                     7'd23: sccb_scl <= 1'b0;
    314                     7'd24: sda_out  <= sccb_data_t[1];
    315                     7'd25: sccb_scl <= 1'b1;
    316                     7'd27: sccb_scl <= 1'b0;
    317                     7'd28: sda_out  <= sccb_data_t[0];
    318                     7'd29: sccb_scl <= 1'b1;
    319                     7'd31: sccb_scl <= 1'b0;
    320                     7'd32: begin
    321                            sda_dir  <= 1'b0;    //从机应答
    322                            sda_out  <= 1'b1;
    323                     end
    324                     7'd33: sccb_scl <= 1'b1;
    325                     7'd34: state_done <= 1'b1;  //状态结束
    326                     7'd35: begin
    327                            sccb_scl  <= 1'b0;
    328                            cnt  <= 1'b0;
    329                     end
    330                     default  :  ;
    331                 endcase
    332             end
    333             //--------------------------------------------------- 结束
    334             STOP: begin
    335                 case(cnt)
    336                     7'd0: begin
    337                            sda_dir  <= 1'b1;
    338                            sda_out  <= 1'b0;
    339                     end
    340                     7'd1 : sccb_scl <= 1'b1;
    341                     7'd3 : sda_out  <= 1'b1;
    342                     7'd15: state_done <= 1'b1;  //状态结束
    343                     7'd16: begin
    344                            cnt <= 1'b0;
    345                            sccb_done <= 1'b1;   //sccb配置完成
    346                     end
    347                     default  : ;
    348                 endcase
    349             end
    350         endcase
    351     end
    352 end
    353 
    354 
    355 
    356 endmodule

    参考资料:

    [1]OmniVision Serial Camera Control Bus (SCCB) Functional Specification

    [2]正点原子FPGA教程

    [3]开源骚客.SDRAM那些事儿

  • 相关阅读:
    C语言初学 使用while语句统计输入字符个数
    C语言初学 比较五个整数并输出最大值和最小值2
    C语言初学 比较五个整数并输出最大值和最小值1
    C语言初学 计算表达式的值 switch的意义
    C语言初学 if-else语句判别在ASCII值中小于32的可控制符的类型
    C语言初学 if-else语句判断俩数的最大值
    C语言初学 计算二元一次方程的问题
    C语言初学 判断闰年的问题
    简单Elixir游戏服务器开篇
    关于Elixir游戏服设计系列
  • 原文地址:https://www.cnblogs.com/xianyufpga/p/11338204.html
Copyright © 2011-2022 走看看