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代码

 //**************************************************************************
// *** 名称 : sccb.v
// *** 作者 : xianyu_FPGA
// *** 博客 : https://www.cnblogs.com/xianyufpga/
// *** 日期 : 2019-08-10
// *** 描述 : SCCB控制器,只支持写
//************************************************************************** module sccb
//========================< 参数 >==========================================
#(
parameter DEVICE_ID = 'b01010000 , //器件ID
parameter CLK = 'd50_000_000 , //本模块的时钟频率
parameter SCL = 'd250_000 //输出的SCL时钟频率
)
//========================< 端口 >==========================================
(
input clk , //时钟
input rst_n , //复位,低电平有效
//SCCB control --------------------------------------
input sccb_en , //SCCB触发信号
input addr16_en , //16位地址使能
input addr8_en , //8位地址使能
//SCCB input ----------------------------------------
input [:] sccb_addr , //SCCB器件内地址
input [ :] sccb_data , //SCCB要写的数据
//SCCB output ---------------------------------------
output reg sccb_done , //SCCB一次操作完成
output reg sccb_scl , //SCCB的SCL时钟信号
inout sccb_sda , //SCCB的SDA数据信号
//dri_clk -------------------------------------------
output reg sccb_dri_clk //驱动SCCB操作的驱动时钟,1Mhz
);
//========================< 状态机参数 >====================================
localparam IDLE = 'b00_0001 ; //空闲状态
localparam DEVICE = 'b00_0010 ; //写器件地址
localparam ADDR_16 = 'b00_0100 ; //写字地址高8位
localparam ADDR_8 = 'b00_1000 ; //写字地址低8位
localparam DATA = 'b01_0000 ; //写数据
localparam STOP = 'b10_0000 ; //结束
//========================< 信号 >==========================================
reg sda_dir ; //SCCB数据(SDA)方向控制
reg sda_out ; //SDA输出信号
reg state_done ; //状态结束
reg [ :] cnt ; //计数
reg [ :] state_c ; //状态机当前状态
reg [ :] state_n ; //状态机下一状态
reg [:] sccb_addr_t ; //地址寄存
reg [ :] sccb_data_t ; //数据寄存
reg [ :] clk_cnt ; //分频时钟计数
wire [ :] clk_divide ; //模块驱动时钟的分频系数 //==========================================================================
//== sda控制
//==========================================================================
assign sccb_sda = sda_dir ? sda_out : 'bz; //SDA数据输出或高阻 //==========================================================================
//== 生成SCL的4倍时钟来驱动后面SCCB的操作,生成1Mhz的sccb_dri_clk
//==========================================================================
assign clk_divide = (CLK/SCL) >> ; // >>3即除以8 always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
sccb_dri_clk <= 'b1;
clk_cnt <= 'd0;
end
else if(clk_cnt == clk_divide - 'd1) begin
clk_cnt <= 'd0;
sccb_dri_clk <= ~sccb_dri_clk;
end
else
clk_cnt <= clk_cnt + 'b1;
end //==========================================================================
//== 状态机
//==========================================================================
always @(posedge sccb_dri_clk or negedge rst_n) begin
if(!rst_n)
state_c <= IDLE;
else
state_c <= state_n;
end always @(*) begin
case(state_c)
IDLE: begin //空闲状态
if(sccb_en)
state_n = DEVICE;
else
state_n = IDLE;
end
DEVICE: begin //写器件ID
if(state_done) begin
if(addr16_en)
state_n = ADDR_16;
else if(addr8_en)
state_n = ADDR_8 ;
end
else
state_n = DEVICE;
end
ADDR_16: begin //写地址高8位
if(state_done)
state_n = ADDR_8;
else
state_n = ADDR_16;
end
ADDR_8: begin //写地址低8位
if(state_done)
state_n = DATA;
else
state_n = ADDR_8;
end
DATA: begin //写数据
if(state_done)
state_n = STOP;
else
state_n = DATA;
end
STOP: begin //结束
if(state_done)
state_n = IDLE;
else
state_n = STOP ;
end
default:state_n= IDLE;
endcase
end //==========================================================================
//== 设计各路信号
//==========================================================================
always @(posedge sccb_dri_clk or negedge rst_n) begin
if(!rst_n) begin
sccb_scl <= 'b1;
sda_out <= 'b1;
sda_dir <= 'b1;
sccb_done <= 'b0;
cnt <= 'b0;
state_done <= 'b0;
sccb_addr_t <= 'b0;
sccb_data_t <= 'b0;
end
else begin
state_done <= 'b0 ;
cnt <= cnt + 'b1 ;
case(state_c)
//--------------------------------------------------- 空闲状态
IDLE: begin
sccb_scl <= 'b1;
sda_out <= 'b1;
sda_dir <= 'b1;
sccb_done <= 'b0;
cnt <= 'b0;
if(sccb_en) begin
sccb_addr_t <= sccb_addr;
sccb_data_t <= sccb_data;
end
end
//--------------------------------------------------- 写器件ID
DEVICE: begin
case(cnt)
'd1 : sda_out <= 1'b0;
'd3 : sccb_scl <= 1'b0;
'd4 : sda_out <= DEVICE_ID[7];
'd5 : sccb_scl <= 1'b1;
'd7 : sccb_scl <= 1'b0;
'd8 : sda_out <= DEVICE_ID[6];
'd9 : sccb_scl <= 1'b1;
'd11: sccb_scl <= 1'b0;
'd12: sda_out <= DEVICE_ID[5];
'd13: sccb_scl <= 1'b1;
'd15: sccb_scl <= 1'b0;
'd16: sda_out <= DEVICE_ID[4];
'd17: sccb_scl <= 1'b1;
'd19: sccb_scl <= 1'b0;
'd20: sda_out <= DEVICE_ID[3];
'd21: sccb_scl <= 1'b1;
'd23: sccb_scl <= 1'b0;
'd24: sda_out <= DEVICE_ID[2];
'd25: sccb_scl <= 1'b1;
'd27: sccb_scl <= 1'b0;
'd28: sda_out <= DEVICE_ID[1];
'd29: sccb_scl <= 1'b1;
'd31: sccb_scl <= 1'b0;
'd32: sda_out <= DEVICE_ID[0];
'd33: sccb_scl <= 1'b1;
'd35: sccb_scl <= 1'b0;
'd36: begin
sda_dir <= 'b0; //从机应答
sda_out <= 'b1;
end
'd37: sccb_scl <= 1'b1;
'd38: state_done <= 1'b1; //状态结束
'd39: begin
sccb_scl <= 'b0;
cnt <= 'b0;
end
default : ;
endcase
end
//--------------------------------------------------- 写字地址高8位
ADDR_16: begin
case(cnt)
'd0 : begin
sda_dir <= 'b1 ;
sda_out <= sccb_addr_t[];
end
'd1 : sccb_scl <= 1'b1;
'd3 : sccb_scl <= 1'b0;
'd4 : sda_out <= sccb_addr_t[14];
'd5 : sccb_scl <= 1'b1;
'd7 : sccb_scl <= 1'b0;
'd8 : sda_out <= sccb_addr_t[13];
'd9 : sccb_scl <= 1'b1;
'd11: sccb_scl <= 1'b0;
'd12: sda_out <= sccb_addr_t[12];
'd13: sccb_scl <= 1'b1;
'd15: sccb_scl <= 1'b0;
'd16: sda_out <= sccb_addr_t[11];
'd17: sccb_scl <= 1'b1;
'd19: sccb_scl <= 1'b0;
'd20: sda_out <= sccb_addr_t[10];
'd21: sccb_scl <= 1'b1;
'd23: sccb_scl <= 1'b0;
'd24: sda_out <= sccb_addr_t[9];
'd25: sccb_scl <= 1'b1;
'd27: sccb_scl <= 1'b0;
'd28: sda_out <= sccb_addr_t[8];
'd29: sccb_scl <= 1'b1;
'd31: sccb_scl <= 1'b0;
'd32: begin
sda_dir <= 'b0; //从机应答
sda_out <= 'b1;
end
'd33: sccb_scl <= 1'b1;
'd34: state_done <= 1'b1; //状态结束
'd35: begin
sccb_scl <= 'b0;
cnt <= 'b0;
end
default : ;
endcase
end
//--------------------------------------------------- 写字地址低8位
ADDR_8: begin
case(cnt)
'd0: begin
sda_dir <= 'b1 ;
sda_out <= sccb_addr_t[];
end
'd1 : sccb_scl <= 1'b1;
'd3 : sccb_scl <= 1'b0;
'd4 : sda_out <= sccb_addr_t[6];
'd5 : sccb_scl <= 1'b1;
'd7 : sccb_scl <= 1'b0;
'd8 : sda_out <= sccb_addr_t[5];
'd9 : sccb_scl <= 1'b1;
'd11: sccb_scl <= 1'b0;
'd12: sda_out <= sccb_addr_t[4];
'd13: sccb_scl <= 1'b1;
'd15: sccb_scl <= 1'b0;
'd16: sda_out <= sccb_addr_t[3];
'd17: sccb_scl <= 1'b1;
'd19: sccb_scl <= 1'b0;
'd20: sda_out <= sccb_addr_t[2];
'd21: sccb_scl <= 1'b1;
'd23: sccb_scl <= 1'b0;
'd24: sda_out <= sccb_addr_t[1];
'd25: sccb_scl <= 1'b1;
'd27: sccb_scl <= 1'b0;
'd28: sda_out <= sccb_addr_t[0];
'd29: sccb_scl <= 1'b1;
'd31: sccb_scl <= 1'b0;
'd32: begin
sda_dir <= 'b0; //从机应答
sda_out <= 'b1;
end
'd33: sccb_scl <= 1'b1;
'd34: state_done <= 1'b1; //状态结束
'd35: begin
sccb_scl <= 'b0;
cnt <= 'b0;
end
default : ;
endcase
end
//--------------------------------------------------- 写数据
DATA: begin
case(cnt)
'd0: begin
sda_out <= sccb_data_t[];
sda_dir <= 'b1;
end
'd1 : sccb_scl <= 1'b1;
'd3 : sccb_scl <= 1'b0;
'd4 : sda_out <= sccb_data_t[6];
'd5 : sccb_scl <= 1'b1;
'd7 : sccb_scl <= 1'b0;
'd8 : sda_out <= sccb_data_t[5];
'd9 : sccb_scl <= 1'b1;
'd11: sccb_scl <= 1'b0;
'd12: sda_out <= sccb_data_t[4];
'd13: sccb_scl <= 1'b1;
'd15: sccb_scl <= 1'b0;
'd16: sda_out <= sccb_data_t[3];
'd17: sccb_scl <= 1'b1;
'd19: sccb_scl <= 1'b0;
'd20: sda_out <= sccb_data_t[2];
'd21: sccb_scl <= 1'b1;
'd23: sccb_scl <= 1'b0;
'd24: sda_out <= sccb_data_t[1];
'd25: sccb_scl <= 1'b1;
'd27: sccb_scl <= 1'b0;
'd28: sda_out <= sccb_data_t[0];
'd29: sccb_scl <= 1'b1;
'd31: sccb_scl <= 1'b0;
'd32: begin
sda_dir <= 'b0; //从机应答
sda_out <= 'b1;
end
'd33: sccb_scl <= 1'b1;
'd34: state_done <= 1'b1; //状态结束
'd35: begin
sccb_scl <= 'b0;
cnt <= 'b0;
end
default : ;
endcase
end
//--------------------------------------------------- 结束
STOP: begin
case(cnt)
'd0: begin
sda_dir <= 'b1;
sda_out <= 'b0;
end
'd1 : sccb_scl <= 1'b1;
'd3 : sda_out <= 1'b1;
'd15: state_done <= 1'b1; //状态结束
'd16: begin
cnt <= 'b0;
sccb_done <= 'b1; //sccb配置完成
end
default : ;
endcase
end
endcase
end
end 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. jQuery - 添加元素append/prepend和after/before的区别

    append <p> <span class="s1">s1</span> </p> <script> $(" ...

  2. Eclipse 高亮显示(pydev 编辑 python)

    因为是使用pydev编辑的python,所以需要修改(pydev)的属性. Window->Preferences->General->Editors->Text Editor ...

  3. SDN初体验(软件定义网络实验一)

    作业说明 本次实验步骤2.3是在机房环境下完成的,步骤1.4是在自己笔记本上重新配置完成的,所以环境.用户名什么的会略有差别. 1. 安装轻量级网络仿真工具Mininet 为了节约课程时间,实验室机房 ...

  4. IT 常用单词表

    程序员英语单词册   前言   程序员必备的600个英语词汇(1)   程序员必备的600个英语词汇(2)   程序员必备的600个英语词汇(3)   程序员必备的600个英语词汇(4)   程序员不 ...

  5. [RoarCTF]Easy Calc

    目录 [RoarCTF]Easy Calc 知识点 1.http走私绕过WAF 2.php字符串解析特性绕过WAF 3.绕过过滤写shell [RoarCTF]Easy Calc 题目复现链接:htt ...

  6. 解读 | 你真正理解什么是Cloud Native吗?

    你能做到每周.每天甚至每个钟头向客户发布新特性吗?新加入的开发者能够在他们工作的第一天甚至面试阶段就能部署代码吗?部署新员工的代码后,你能因为确信应用程序运行正常而安然入睡吗?建立快速发布机制,包括支 ...

  7. centos7.6环境编译安装php-7.2.24修复最新 CVE-2019-11043 漏洞

    先编译安装php-7.2.24,然后编译安装扩展 主版本地址地址:https://www.php.net/distributions/php-7.2.24.tar.gz # 编译 php-7.2.24 ...

  8. SUSE操作系统,如何查看操作系统版本?

    背景描述: 今天需要统计操作系统版本,我在其中一台主机上执行cat /etc/redhat-release发现没有这个,应该知道不是redhat系统,然后想,怎么查来着,忘了,找了下,再此记录下. # ...

  9. Spring cloud微服务安全实战-7-8ELK+SpringBoot环境搭建

    采集不可聚合的离散的.日志信息的e ELK是三个系统的简称 LogStash:用来做日志的收集.过滤.格式转换 Kibana:和普罗米修斯的grafana一个意思.主要用来展示数据. 用docker来 ...

  10. k8s记录-kube-dns(core-dns)配置(七)

    docker search corednsdocker pull xxx 拉取镜像(根据实际情况选择)docker tag xxx coredns/coredns:latestdocker tag c ...