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,具体表现如下

  1. SCCB读:start_1 + phase_1 + phase_2 + stop_1 + start_2 + phase_3 + phase_4 + stop_2
  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 = 'b01010000 , //器件ID
  13. parameter CLK = 'd50_000_000 , //本模块的时钟频率
  14. parameter SCL = '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 [:] sccb_addr , //SCCB器件内地址
  26. input [ :] 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 = 'b00_0001 ; //空闲状态
  36. localparam DEVICE = 'b00_0010 ; //写器件地址
  37. localparam ADDR_16 = 'b00_0100 ; //写字地址高8位
  38. localparam ADDR_8 = 'b00_1000 ; //写字地址低8位
  39. localparam DATA = 'b01_0000 ; //写数据
  40. localparam STOP = 'b10_0000 ; //结束
  41. //========================< 信号 >==========================================
  42. reg sda_dir ; //SCCB数据(SDA)方向控制
  43. reg sda_out ; //SDA输出信号
  44. reg state_done ; //状态结束
  45. reg [ :] cnt ; //计数
  46. reg [ :] state_c ; //状态机当前状态
  47. reg [ :] state_n ; //状态机下一状态
  48. reg [:] sccb_addr_t ; //地址寄存
  49. reg [ :] sccb_data_t ; //数据寄存
  50. reg [ :] clk_cnt ; //分频时钟计数
  51. wire [ :] clk_divide ; //模块驱动时钟的分频系数
  52.  
  53. //==========================================================================
  54. //== sda控制
  55. //==========================================================================
  56. assign sccb_sda = sda_dir ? sda_out : 'bz; //SDA数据输出或高阻
  57.  
  58. //==========================================================================
  59. //== 生成SCL的4倍时钟来驱动后面SCCB的操作,生成1Mhz的sccb_dri_clk
  60. //==========================================================================
  61. assign clk_divide = (CLK/SCL) >> ; // >>3即除以8
  62.  
  63. always @(posedge clk or negedge rst_n) begin
  64. if(!rst_n) begin
  65. sccb_dri_clk <= 'b1;
  66. clk_cnt <= 'd0;
  67. end
  68. else if(clk_cnt == clk_divide - 'd1) begin
  69. clk_cnt <= 'd0;
  70. sccb_dri_clk <= ~sccb_dri_clk;
  71. end
  72. else
  73. clk_cnt <= clk_cnt + '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 <= 'b1;
  138. sda_out <= 'b1;
  139. sda_dir <= 'b1;
  140. sccb_done <= 'b0;
  141. cnt <= 'b0;
  142. state_done <= 'b0;
  143. sccb_addr_t <= 'b0;
  144. sccb_data_t <= 'b0;
  145. end
  146. else begin
  147. state_done <= 'b0 ;
  148. cnt <= cnt + 'b1 ;
  149. case(state_c)
  150. //--------------------------------------------------- 空闲状态
  151. IDLE: begin
  152. sccb_scl <= 'b1;
  153. sda_out <= 'b1;
  154. sda_dir <= 'b1;
  155. sccb_done <= 'b0;
  156. cnt <= '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. 'd1 : sda_out <= 1'b0;
  166. 'd3 : sccb_scl <= 1'b0;
  167. 'd4 : sda_out <= DEVICE_ID[7];
  168. 'd5 : sccb_scl <= 1'b1;
  169. 'd7 : sccb_scl <= 1'b0;
  170. 'd8 : sda_out <= DEVICE_ID[6];
  171. 'd9 : sccb_scl <= 1'b1;
  172. 'd11: sccb_scl <= 1'b0;
  173. 'd12: sda_out <= DEVICE_ID[5];
  174. 'd13: sccb_scl <= 1'b1;
  175. 'd15: sccb_scl <= 1'b0;
  176. 'd16: sda_out <= DEVICE_ID[4];
  177. 'd17: sccb_scl <= 1'b1;
  178. 'd19: sccb_scl <= 1'b0;
  179. 'd20: sda_out <= DEVICE_ID[3];
  180. 'd21: sccb_scl <= 1'b1;
  181. 'd23: sccb_scl <= 1'b0;
  182. 'd24: sda_out <= DEVICE_ID[2];
  183. 'd25: sccb_scl <= 1'b1;
  184. 'd27: sccb_scl <= 1'b0;
  185. 'd28: sda_out <= DEVICE_ID[1];
  186. 'd29: sccb_scl <= 1'b1;
  187. 'd31: sccb_scl <= 1'b0;
  188. 'd32: sda_out <= DEVICE_ID[0];
  189. 'd33: sccb_scl <= 1'b1;
  190. 'd35: sccb_scl <= 1'b0;
  191. 'd36: begin
  192. sda_dir <= 'b0; //从机应答
  193. sda_out <= 'b1;
  194. end
  195. 'd37: sccb_scl <= 1'b1;
  196. 'd38: state_done <= 1'b1; //状态结束
  197. 'd39: begin
  198. sccb_scl <= 'b0;
  199. cnt <= 'b0;
  200. end
  201. default : ;
  202. endcase
  203. end
  204. //--------------------------------------------------- 写字地址高8位
  205. ADDR_16: begin
  206. case(cnt)
  207. 'd0 : begin
  208. sda_dir <= 'b1 ;
  209. sda_out <= sccb_addr_t[];
  210. end
  211. 'd1 : sccb_scl <= 1'b1;
  212. 'd3 : sccb_scl <= 1'b0;
  213. 'd4 : sda_out <= sccb_addr_t[14];
  214. 'd5 : sccb_scl <= 1'b1;
  215. 'd7 : sccb_scl <= 1'b0;
  216. 'd8 : sda_out <= sccb_addr_t[13];
  217. 'd9 : sccb_scl <= 1'b1;
  218. 'd11: sccb_scl <= 1'b0;
  219. 'd12: sda_out <= sccb_addr_t[12];
  220. 'd13: sccb_scl <= 1'b1;
  221. 'd15: sccb_scl <= 1'b0;
  222. 'd16: sda_out <= sccb_addr_t[11];
  223. 'd17: sccb_scl <= 1'b1;
  224. 'd19: sccb_scl <= 1'b0;
  225. 'd20: sda_out <= sccb_addr_t[10];
  226. 'd21: sccb_scl <= 1'b1;
  227. 'd23: sccb_scl <= 1'b0;
  228. 'd24: sda_out <= sccb_addr_t[9];
  229. 'd25: sccb_scl <= 1'b1;
  230. 'd27: sccb_scl <= 1'b0;
  231. 'd28: sda_out <= sccb_addr_t[8];
  232. 'd29: sccb_scl <= 1'b1;
  233. 'd31: sccb_scl <= 1'b0;
  234. 'd32: begin
  235. sda_dir <= 'b0; //从机应答
  236. sda_out <= 'b1;
  237. end
  238. 'd33: sccb_scl <= 1'b1;
  239. 'd34: state_done <= 1'b1; //状态结束
  240. 'd35: begin
  241. sccb_scl <= 'b0;
  242. cnt <= 'b0;
  243. end
  244. default : ;
  245. endcase
  246. end
  247. //--------------------------------------------------- 写字地址低8位
  248. ADDR_8: begin
  249. case(cnt)
  250. 'd0: begin
  251. sda_dir <= 'b1 ;
  252. sda_out <= sccb_addr_t[];
  253. end
  254. 'd1 : sccb_scl <= 1'b1;
  255. 'd3 : sccb_scl <= 1'b0;
  256. 'd4 : sda_out <= sccb_addr_t[6];
  257. 'd5 : sccb_scl <= 1'b1;
  258. 'd7 : sccb_scl <= 1'b0;
  259. 'd8 : sda_out <= sccb_addr_t[5];
  260. 'd9 : sccb_scl <= 1'b1;
  261. 'd11: sccb_scl <= 1'b0;
  262. 'd12: sda_out <= sccb_addr_t[4];
  263. 'd13: sccb_scl <= 1'b1;
  264. 'd15: sccb_scl <= 1'b0;
  265. 'd16: sda_out <= sccb_addr_t[3];
  266. 'd17: sccb_scl <= 1'b1;
  267. 'd19: sccb_scl <= 1'b0;
  268. 'd20: sda_out <= sccb_addr_t[2];
  269. 'd21: sccb_scl <= 1'b1;
  270. 'd23: sccb_scl <= 1'b0;
  271. 'd24: sda_out <= sccb_addr_t[1];
  272. 'd25: sccb_scl <= 1'b1;
  273. 'd27: sccb_scl <= 1'b0;
  274. 'd28: sda_out <= sccb_addr_t[0];
  275. 'd29: sccb_scl <= 1'b1;
  276. 'd31: sccb_scl <= 1'b0;
  277. 'd32: begin
  278. sda_dir <= 'b0; //从机应答
  279. sda_out <= 'b1;
  280. end
  281. 'd33: sccb_scl <= 1'b1;
  282. 'd34: state_done <= 1'b1; //状态结束
  283. 'd35: begin
  284. sccb_scl <= 'b0;
  285. cnt <= 'b0;
  286. end
  287. default : ;
  288. endcase
  289. end
  290. //--------------------------------------------------- 写数据
  291. DATA: begin
  292. case(cnt)
  293. 'd0: begin
  294. sda_out <= sccb_data_t[];
  295. sda_dir <= 'b1;
  296. end
  297. 'd1 : sccb_scl <= 1'b1;
  298. 'd3 : sccb_scl <= 1'b0;
  299. 'd4 : sda_out <= sccb_data_t[6];
  300. 'd5 : sccb_scl <= 1'b1;
  301. 'd7 : sccb_scl <= 1'b0;
  302. 'd8 : sda_out <= sccb_data_t[5];
  303. 'd9 : sccb_scl <= 1'b1;
  304. 'd11: sccb_scl <= 1'b0;
  305. 'd12: sda_out <= sccb_data_t[4];
  306. 'd13: sccb_scl <= 1'b1;
  307. 'd15: sccb_scl <= 1'b0;
  308. 'd16: sda_out <= sccb_data_t[3];
  309. 'd17: sccb_scl <= 1'b1;
  310. 'd19: sccb_scl <= 1'b0;
  311. 'd20: sda_out <= sccb_data_t[2];
  312. 'd21: sccb_scl <= 1'b1;
  313. 'd23: sccb_scl <= 1'b0;
  314. 'd24: sda_out <= sccb_data_t[1];
  315. 'd25: sccb_scl <= 1'b1;
  316. 'd27: sccb_scl <= 1'b0;
  317. 'd28: sda_out <= sccb_data_t[0];
  318. 'd29: sccb_scl <= 1'b1;
  319. 'd31: sccb_scl <= 1'b0;
  320. 'd32: begin
  321. sda_dir <= 'b0; //从机应答
  322. sda_out <= 'b1;
  323. end
  324. 'd33: sccb_scl <= 1'b1;
  325. 'd34: state_done <= 1'b1; //状态结束
  326. 'd35: begin
  327. sccb_scl <= 'b0;
  328. cnt <= 'b0;
  329. end
  330. default : ;
  331. endcase
  332. end
  333. //--------------------------------------------------- 结束
  334. STOP: begin
  335. case(cnt)
  336. 'd0: begin
  337. sda_dir <= 'b1;
  338. sda_out <= 'b0;
  339. end
  340. 'd1 : sccb_scl <= 1'b1;
  341. 'd3 : sda_out <= 1'b1;
  342. 'd15: state_done <= 1'b1; //状态结束
  343. 'd16: begin
  344. cnt <= 'b0;
  345. sccb_done <= 'b1; //sccb配置完成
  346. end
  347. default : ;
  348. endcase
  349. end
  350. endcase
  351. end
  352. end
  353.  
  354. endmodule

参考资料:

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

[2]正点原子FPGA教程

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

协议——SCCB与IIC的区别的更多相关文章

  1. http、TCP/IP协议与socket之间的区别

    http.TCP/IP协议与socket之间的区别     网络由下往上分为:  www.2cto.com   物理层--                       数据链路层-- 网络层--   ...

  2. http、TCP/IP协议与socket之间的区别(转载)

    http.TCP/IP协议与socket之间的区别  https://www.cnblogs.com/iOS-mt/p/4264675.html http.TCP/IP协议与socket之间的区别   ...

  3. 转 WebService两种发布协议--SOAP和REST的区别

    转发文章 https://blog.csdn.net/zl834205311/article/details/62231545?ABstrategy=codes_snippets_optimize_v ...

  4. Python进阶----网络通信基础 ,OSI七层协议() ,UDP和TCP的区别 , TCP/IP协议(三次握手,四次挥手)

    Python进阶----网络通信基础 ,OSI七层协议() ,UDP和TCP的区别 , TCP/IP协议(三次握手,四次挥手) 一丶CS/BS 架构 C/S: 客户端/服务器    定义:       ...

  5. HTTP协议 结构,get post 区别(阿里面试)

    如果需要想了解相关的TCP的协议结构,底层架构,以及每次面试必问的三次握手,四次挥手可以 参考:TCP协议详解7层和4层解析(美团面试,阿里面试) 尤其是三次握手,四次挥手 具体发送的报文和状态都要掌 ...

  6. WebService发布协议--SOAP和REST的区别

    HTTP是标准超文本传输协议.使用对参数进行编码并将参数作为键值对传递,还使用关联的请求语义.每个协议都包含一系列HTTP请求标头及其他一些信息,定义客户端向服务器请求哪些内容,服务器用一系列HTTP ...

  7. Git使用总结 Asp.net生命周期与Http协议 托管代码与非托管代码的区别 通过IEnumerable接口遍历数据 依赖注入与控制反转 C#多线程——优先级 AutoFac容器初步 C#特性详解 C#特性详解 WPF 可触摸移动的ScrollViewer控件 .NET(C#)能开发出什么样的APP?盘点那些通过Smobiler开发的移动应用

    一,原理 首先,我们要明白Git是什么,它是一个管理工具或软件,用来管理什么的呢?当然是在软件开发过程中管理软件或者文件的不同版本的工具,一些作家也可以用这个管理自己创作的文本文件,由Linus开发的 ...

  8. HTTP协议中GET和POST区别

    GET一般用于获取和查询资源信息:POST一般用于更新信息,表示可能修改服务器上资源的请求 GET请求一般是幂等的 GET请求数据会附加在url之后,POST请求数据放到request-body中 G ...

  9. HTTP协议GET和POST的区别

    from http://blog.csdn.net/whuslei/article/details/6667095 权威点的说明请参考:http://www.cs.tut.fi/~jkorpela/f ...

随机推荐

  1. jmxtrans docker-compose 运行

    以下是一个简单的demo,使用jmxtrans 进行jmx 指标的处理,项目使用docker-compose 运行 同时写入数据到graphite 环境准备 docker-compose文件   ve ...

  2. 50、Spark Streaming实时wordcount程序开发

    一.java版本 package cn.spark.study.streaming; import java.util.Arrays; import org.apache.spark.SparkCon ...

  3. Flume(一) —— 启动与基本使用

    基础架构 Flume is a distributed, reliable(可靠地), and available service for efficiently(高效地) collecting, a ...

  4. 【大数据作业十一】分布式并行计算MapReduce

    作业要求:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/3319 1.用自己的话阐明Hadoop平台上HDFS和MapReduce的功 ...

  5. ls列出排除的文件

    今天有个需求,将从日志文件夹中列出它排除旧备份日志的文件. ls -lhrt --ignore="*.gz" --ignore="*.zip"

  6. git - 3.分支

    分支介绍 每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支.截止到目前,只有一条时间线, 在Git里,这个分支叫主分支,即master分支. HEAD严格来说不是指向提交,而是指向mas ...

  7. redis的相关原理

    一.AOF 二.RDB 三.哨兵

  8. matlab学习笔记10_7数值计算类型和常用计算公式

    一起来学matlab-matlab学习笔记11 数值数据类型以及特殊函数 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考书籍 <matlab 程序设计与综合应用>张德丰等著 ...

  9. 必备Linux命令

    文章来源:https://macrozheng.github.io/mall-learning/#/reference/linux 开发者必备Linux命令 开发者必备Linux常用命令,掌握这些命令 ...

  10. SpringBoot 为什么能够自动的注入一些常用的Bean ?详细分析SpringBoot 自动配置的实现

    转载至:https://blog.csdn.net/qq_29941401/article/details/79605388 有一个问题一直让我好奇,为什么在SpringBoot中有的bean 我们都 ...