前记:
众说周知,SCCB协议与IIC协议十分相似,不过IIC是PHILIPS的专利,所以OmnVision在IIC的基础上做了点小改动,然后你懂的。SCCB最主要是阉割了IIC的连续读写的功能,即每读写完一个字节就主机必须发送一个NA信号。
SCCB简介
SCCB是欧姆尼图像技术公司(OmniVision)开发的一种总线,并广泛的应用于OV系列图像传感器上,所以一般使用OV的图像传感器都离不开SCCB总线协议。
可以通俗地讲SCCB有两种工作模式,一主多从,一主一从模式。
- 一主机多从机 也即3线操作:(通过控制使能端SCCB_E控制选中的从机)
- 一主一从 也即2线操作:(默认SCCB_E被拉低)
管脚定义
可与IIC对比来看
SCCB | IIC | 方向 | 描述 |
---|---|---|---|
SIO_E | \ | 主机发出 | 低电平有效,总线空闲时主机驱动此引脚为1,驱动为0时表示开始传输或者挂起模式 |
SIO_C | SCL | 主机发出 | 总线空闲时主机驱动此引脚为1; 当驱动SIO_E为0时,主机驱动此引脚为0或1;当挂起时主机驱动SIO_C为0; SIO_D只能在SIO_C为0时发生变化。 |
SIO_D | SDA | 双向传输 | 当总线空闲时保持浮动,状态不固定(0、1或高阻态) 相当于数据位! |
SCCB时序
- SCCB_E为低电平时传输有效,SIO_C为高电平时SIO_D读取数据(SIO_C为低电平时SIO_D改变)
- 开始传输的时序
tPRC>=15ns
tPRA>=2.5ns
2线操作的代码实现
void SCCB_Start(void)
{
SCCB_SDA_OUT(); //数据线为输出模式
SCCB_SDA=1; //数据线高电平
delay_us(50);
SCCB_SCL=1; //在时钟高的时候数据线由高至低
delay_us(50);
SCCB_SDA=0;
delay_us(50);
SCCB_SCL=0; //数据线恢复低电平,单操作函数必要
delay_us(50);
}
- 结束传输的时序
tPSC>=15ns
tPSA>=0ns
2线操作的代码实现
void SCCB_Stop(void)
{
SCCB_SDA_OUT(); //数据线为输出模式
SCCB_SDA=0; //数据线低电平
delay_us(50);
SCCB_SCL=1;
delay_us(50);
SCCB_SDA=1;
delay_us(50);
}
- 产生NA时序(用于读数据)
//SCCB_D先拉高,再把SCCB_C拉高,后把SCCB_C拉低,最后把SCCB_D拉低
void SCCB_NA(void)
{
SCCB_SDA_OUT();
SCCB_SDA=1;
delay_us(50);
SCCB_SCL=1;
delay_us(50);
SCCB_SCL=0;
delay_us(50);
SCCB_SDA=0;
delay_us(50);
}
读\写时序
- 读时序
u8 SCCB_RD_Byte(void)
{
u8 read,j;
read=0x00;
SCCB_SDA_IN(); //设置SDA为输入
delay_us(50);
for(j=8;j>0;j--)
{
delay_us(50);
SCCB_SCL=1;
read=read<<1;
if(SCCB_READ_SDA) read++; //左移一位,若读取到高电平 read相应位写1
delay_us(50);
SCCB_SCL=0;
}
SCCB_SDA_OUT();
return (read);
}
- 写时序
u8 SCCB_WR_Byte(u8 dat)
{
u8 temp=0,j;
for(j=0;j<8;j++)
{
if((dat<<j)&0x80) //高位先发送
{
SCCB_SDA=1;
}
else
{
SCCB_SDA=0;
}
delay_us(50);
SCCB_SCL=1; //高电平时写入
delay_us(50);
SCCB_SCL=0; //低电平时 改变SDA
}
SCCB_SDA_IN(); //设置SDA为输入
delay_us(50);
SCCB_SCL=1; //高电平时读取第九位,以判断是否发送成功
delay_us(50);
if(SCCB_READ_SDA) //SDA=1 发送失败
{
temp=1;
}
else
{
temp=0;
}
SCCB_SCL=0; //写完字节后 SCL拉低 方便继续操作
SCCB_SDA_OUT(); //设置SDA为输出
return (temp);
}
传输规则
- 写寄存器值
写寄存器分三个阶段:写器件地址,写寄存器地址,写数据
u8 SCCB_WR_Reg(u8 reg, u8 data)
{
u8 res=0;
SCCB_Start(); //启动SCCB传输
if(SCCB_WR_Byte(SCCB_ID)) res=1; //写器件地址 失败返回1
delay_us(100);
if(SCCB_WR_Byte(reg)) res=1; //写寄存器地址 失败返回1
delay_us(100);
if(SCCB_WR_Byte(data)) res=1; //写数据 失败返回1
SCCB_Stop(); //停止
return(res);
}
- 读寄存器值
读寄存器分两次两个阶段
- 写器件地址,写要读的寄存器地址
- 写器件地址+1(表示读命令),读取数据,最后在发送NA信号
u8 SCCB_RD_Reg(u8 reg)
{
u8 val=0;
SCCB_Start(); //启动SCCB传输
SCCB_WR_Byte(SCCB_ID); //写器件ID
delay_us(100);
SCCB_WR_Byte(reg); //写寄存器地址
delay_us(100);
SCCB_Stop();
delay_us(100);
SCCB_Start(); //设置完寄存器后才是读
SCCB_WR_Byte(SCCB_ID|0x01); //发送读命令
delay_us(100);
val=SCCB_RD_Byte(); //读取命令
SCCB_NA(); //发送NA信号
SCCB_Stop();
return(val);
}
后记:
学习SCCB协议主要还是为了配合OV的图像传感器食用的,顺道巩固一下IIC协议。第一次写文章,有疏漏的地方也请指出,谢谢啦!
下期出个OV7670的调试文章,调了三四天,能实现缩放,调分辨率,RGB565,YUV输出。觉得有帮助的评论一下,或有疑问的我们一起探讨撒!