協議——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那些事兒


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM