协议

  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             end101             else102                 state_n = DEVICE;103         end104         ADDR_16: begin                          //写地址高8位105             if(state_done)106                 state_n = ADDR_8;107             else108                 state_n = ADDR_16;109         end110         ADDR_8: begin                           //写地址低8位111             if(state_done)112                 state_n = DATA;113             else114                 state_n = ADDR_8;115         end116         DATA: begin                             //写数据117             if(state_done)118                 state_n = STOP;119             else120                 state_n = DATA;121         end122         STOP: begin                             //结束123             if(state_done)124                 state_n = IDLE;125             else126                 state_n = STOP ;127         end128         default:state_n= IDLE;129     endcase130 end131 132 //==========================================================================133 //==    设计各路信号134 //==========================================================================135 always @(posedge sccb_dri_clk or negedge rst_n) begin136     if(!rst_n) begin137         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     end146     else begin147         state_done  <= 1'b0 ;148         cnt         <= cnt + 1'b1 ;149         case(state_c)150             //--------------------------------------------------- 空闲状态151             IDLE: begin152                     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) begin158                         sccb_addr_t <= sccb_addr;159                         sccb_data_t <= sccb_data;160                     end161             end162             //--------------------------------------------------- 写器件ID163             DEVICE: begin164                 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: begin192                             sda_dir <= 1'b0;    //从机应答193                             sda_out <= 1'b1;194                     end195                     7'd37: sccb_scl <= 1'b1;196                     7'd38: state_done <= 1'b1;  //状态结束197                     7'd39: begin198                             sccb_scl <= 1'b0;199                             cnt <= 1'b0;200                     end201                     default :  ;202                 endcase203             end204             //--------------------------------------------------- 写字地址高8位205             ADDR_16: begin206                 case(cnt)207                     7'd0 : begin208                             sda_dir <= 1'b1 ;209                             sda_out <= sccb_addr_t[15];210                     end211                     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: begin235                            sda_dir  <= 1'b0;    //从机应答236                            sda_out  <= 1'b1;237                     end238                     7'd33: sccb_scl <= 1'b1;239                     7'd34: state_done <= 1'b1;  //状态结束240                     7'd35: begin241                            sccb_scl <= 1'b0;242                            cnt <= 1'b0;243                     end244                     default :  ;245                 endcase246             end247             //--------------------------------------------------- 写字地址低8位248             ADDR_8: begin249                 case(cnt)250                     7'd0: begin251                             sda_dir <= 1'b1 ;252                             sda_out <= sccb_addr_t[7];253                     end254                     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: begin278                            sda_dir  <= 1'b0;    //从机应答279                            sda_out  <= 1'b1;280                     end281                     7'd33: sccb_scl <= 1'b1;282                     7'd34: state_done <= 1'b1;  //状态结束283                     7'd35: begin284                            sccb_scl <= 1'b0;285                            cnt <= 1'b0;286                     end287                     default :  ;288                 endcase289             end290             //--------------------------------------------------- 写数据291             DATA: begin292                 case(cnt)293                     7'd0: begin294                             sda_out <= sccb_data_t[7];295                             sda_dir <= 1'b1;296                     end297                     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: begin321                            sda_dir  <= 1'b0;    //从机应答322                            sda_out  <= 1'b1;323                     end324                     7'd33: sccb_scl <= 1'b1;325                     7'd34: state_done <= 1'b1;  //状态结束326                     7'd35: begin327                            sccb_scl  <= 1'b0;328                            cnt  <= 1'b0;329                     end330                     default  :  ;331                 endcase332             end333             //--------------------------------------------------- 结束334             STOP: begin335                 case(cnt)336                     7'd0: begin337                            sda_dir  <= 1'b1;338                            sda_out  <= 1'b0;339                     end340                     7'd1 : sccb_scl <= 1'b1;341                     7'd3 : sda_out  <= 1'b1;342                     7'd15: state_done <= 1'b1;  //状态结束343                     7'd16: begin344                            cnt <= 1'b0;345                            sccb_done <= 1'b1;   //sccb配置完成346                     end347                     default  : ;348                 endcase349             end350         endcase351     end352 end353 354 355 356 endmodule

参考资料:

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

[2]正点原子FPGA教程

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

(0)

相关推荐